この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
お試しでAPIをサクッと叩くとき、cURLコマンドをよく使います。とてもお手軽で便利なのですが、雰囲気で使っていたのでハマりました。
ハマったこと
とあるAPIに対して、クエリ文字列付きで下記のようにアクセスしましたが、「APIキーが無効だよ」のメッセージが返ってきました。
curl https://xxxxx.com/todo?id=aaa&apikey=bbb
そのときは「APIキーを作ったばかりなのでしばらく待ってみよう。ドキュメントにも数時間待ってねと書いてあるし。」と考えましたが、24時間以上が経過しても「APIキーが無効だよ」が返ってくるのです。 わけが分かりませんでした。
何が起きてたか
シェルの制御に使う文字(&
)がコマンドの引数にある場合、文字列の解釈がそこで終わっていました。
たとえば、上記の例を分かりやすくすると次のようになります。
curl https://xxxxx.com/todo?id=aaa&echo bbb
&
はバックグランド実行指定のため、「curl https://xxxxx.com/todo?id=aaa
をバックグランドで実行して、次にecho bbb
を実行する動作」になっています。
解決方法
curl
コマンドのURLをダブルクオートで囲めばOKでした。
curl "https://xxxxx.com/todo?id=aaa&apikey=bbb"
または&
をエスケープシーケンスしてあげるとOKでした。
curl https://xxxxx.com/todo?id=aaa\&apikey=bbb
APIを作って再現してみた
受け取ったクエリ文字列をそのまま返すAPIを作って試してみました。
AWS SAMテンプレート
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: QueryStringApiSample
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.7
Timeout: 10
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
Outputs:
HelloWorldApi:
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello"
Lambdaコード
app.py
import json
def lambda_handler(event, context):
return {
'statusCode': 200,
'body': json.dumps({
'message': event['queryStringParameters'],
}),
}
ビルド&デプロイ
sam build
sam package \
--output-template-file packaged.yaml \
--s3-bucket cm-fujii.genki-sam-test-bucket
sam deploy \
--template-file packaged.yaml \
--stack-name Query-String-Sample-Stack \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
APIエンドポイント取得
aws cloudformation describe-stacks \
--stack-name Query-String-Sample-Stack \
--query 'Stacks[].Outputs'
NGの場合
&
以降のクエリ文字列が無視されています。
$ curl https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello?id=aaa&apikey=bbb
{"message": {"id": "aaa"}}
OKの場合
&
以降のクエリ文字列もバッチリ扱えました。
$ curl "https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello?foo=aaa&bar=bbb"
{"message": {"apikey": "bbb", "id": "aaa"}}
エスケープシーケンスした場合も同様にOKでした。
curl https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello?id=aaa\&apikey=bbb
{"message": {"apikey": "bbb", "id": "aaa"}}
さいごに
「もしかして……?」と気づくのに時間が掛かってしまいました。どなたかの参考になれば幸いです。