LoginSignup
6
3

More than 5 years have passed since last update.

APIGatewayでxmlを返したい

Last updated at Posted at 2018-10-03

はじめに

AWSのAPIGatewayでjsonを返している記事は数多くありますがxmlを返している記事があまり見つからなかったので調査しました。(ググり力不足の可能性あり)
今回はServerlessFrameworkを使用して作成しました。

環境

  • OS: macOS High Sierra(10.13.6)
  • Python: 3.6.5
  • pipenv: 2018.7.1
  • ServerlessFramework: 1.29.2

プロジェクト作成

プロジェクトを作成

sls create -t aws-python3 -n api-gateway-xml

serverless-python-requirements(モジュールを一緒にデプロイするために必要)をインストール

sls plugin install -n serverless-python-requirements

pipenvで仮想環境を作成

pipenv install --python 3.6.5   

serverless.ymlとhandler.pyの編集

とりあえず最初はシンプルにjson返してみましょう

serverless.yml
service: api-gateway-xml
provider:
  name: aws
  runtime: python3.6
  stage: dev # とりあえずdevで
  region: ap-northeast-1 # リージョン指定
  profile: xxxxxxxxxx # credentialsが複数あるのであれば指定できる

functions:
  main: # 生成されたhelloはなんかダサいので関数名変えました
    handler: handler.get_sin
    events:
      - http: GET /sin/{theta} # APIGatewayのルーティング、{}はパスのパラメータ

plugins:
  - serverless-python-requirements

custom: # pipenvで入れたライブラリを使用する
  pythonRequirements:
    usePipenv: true 
handler.py
import json
import math


def get_sin(event, context):
    theta = event['pathParameters']['theta']
    try:
        theta = int(theta)
        sin = math.sin(math.radians(theta))
        body = {
            "sin": sin
            }
    except:
        body = {
            "error": 'not number'
            }

    response = {
        'statusCode': 200,
        'isBase64Encoded': False,
        'headers': {'Content-Type': 'application/json'},
        'body': json.dumps(body)
    }

    return response

あんまりいい例が思いつかなかったのでsinθの値を返すAPIを作成しました。{theta}には角度を入力します。
※ちなみに安直にnumpyをpipenvで入れたらLambda実行時にエラーになりました。どうやらCで書かれたライブラリはMac用にビルドされているので使えないようです。なのでmathライブラリで書いています。

デプロイとテスト

デプロイ

sls deploy -v
Service Information
service: api-gateway-xml
stage: dev
region: ap-northeast-1
stack: api-gateway-xml-dev
api keys:
  None
endpoints:
  GET - https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/sin/{theta}
functions:
  main: api-gateway-xml-dev-main

デプロイが終了するとエンドポイントが表示されるのでcurlを投げてみましょう。

curl https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/sin/30 | jq 
{
  "sin": 0.49999999999999994
}

返ってきましたね。

本題:xmlにして返す

今回使用するのはxmltodictというライブラリです。
xmlをdict(辞書)に変換してくれるライブラリですがその逆のdict(辞書)からxmlに変換もしてくれます。

pipenv install xmltodict

handler.pyを編集

handler.py
import math
import xmltodict


def get_sin(event, context):
    theta = event['pathParameters']['theta']
    try:
        theta = int(theta)
        sin = math.sin(math.radians(theta))
        body = {
            "sin": sin
            }
    except:
        body = {
            "error": 'not number'
            }

    response = {
        'statusCode': 200,
        'isBase64Encoded': False,
        'headers': {'Content-Type': 'text/xml'},
        'body': xmltodict.unparse(
            body, pretty=True, encoding='utf-8')
    }

    return response

デプロイしたらcurlを投げてテスト

curl https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/sin/30
<?xml version="1.0" encoding="utf-8"?>
<sin>0.49999999999999994</sin>

xmlになって返ってきました。

body = {
        'result':{'sin': sin}
        }

bodyの部分をこのような構成にするとxmlの子要素も作成してくれます

<?xml version="1.0" encoding="utf-8"?>
<result>
    <sin>0.49999999999999994</sin>
</result>

日本語を扱う場合の注意点

上記したhandler.pyxmltodict.unparseencoding='utf-8'としていますが、文字化けします。
headersを以下のように編集すると文字化けしなくなります

response = {
        'statusCode': 200,
        'isBase64Encoded': False,
        'headers': {'Content-Type': 'text/xml;charset=UTF-8'}, # ;charset=UTF-8を追記
        'body': xmltodict.unparse(
            body, pretty=True, encoding='utf-8')
    }
6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3