はじめに
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返してみましょう
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
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を編集
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.py
のxmltodict.unparse
でencoding='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')
}