AWSのAPI GatewayとLambdaでREST APIを構築するケースは多いかと思います。 その際に画像を扱う上でいくつかハマるポイントがあったので共有します。 Lambdaプロキシ統合を用いたAPIを前提とします。
AWS - REST API のバイナリメディアタイプの使用によると、以下のように書かれています。
AWS Lambda プロキシ統合のバイナリペイロードを処理するには、関数のレスポンスを base64 でエンコードする必要があります。また、API の binaryMediaTypes を設定する必要があります。API の binaryMediaTypes 設定は、API がバイナリデータとして扱うコンテンツタイプのリストです。バイナリメディアタイプの例には、image/png または application/octet-stream が含まれます。ワイルドカード文字 () を使用して、複数のメディアタイプを対象にすることができます。例えば、/* にはすべてのコンテンツタイプが含まれます。
ここでいうバイナリメディアタイプは、API Gateway
のコンソール画面から設定できます。
左メニューから[設定]を選択し、画面下部の「バイナリメディアタイプ」に扱いたいメディアタイプを記載しましょう。
※画像全般を扱う場合はimage/*
と入れると良いです
画像を受け取るAPIについては特別な処理は必要ないです。
Lambda
上では、送られてきた画像(バイナリ)はbase64
にエンコードされた状態でevent.body
に格納されているので、デコードした上で処理を行いましょう。
実際にはS3
のバケットに格納するか、DB
に格納するかの二択だと思います。
exports.handler = async (event, context) => {
try {
// リクエストボディに設定された画像データはBase64エンコードされているので、デコードする
const image = Buffer.from(event.body, 'base64');
if(image) {
// imageをS3に入れたり、DBに入れたり・・・
return {
statusCode: 200,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
result: true,
})
};
}
} catch (e) {
return {
statusCode: 500,
headers: {
"Content-Type": "application/json"
},
body: e.message
}
}
};
画像を返却するAPIのLambda
はbase64
でエンコードした状態でレスポンスボディに格納する必要があります。
こちらも、画像の実体をどこで持つかによって取得方法は変わってきますが、概ね以下のようなレスポンスのイメージです。
exports.handler = async (event, context) => {
try {
// imageは実際にはS3から取得したり、DBから取得したりする
const imaeg = null;
return {
statusCode: 200,
headers: {
"Content-Type": "image/png"
},
body: image.toString("base64")
};
} catch (e) {
return {
statusCode: 500,
headers: {
"Content-Type": "application/json"
},
body: e.message
}
}
};
あとはAPI
を叩くだけなのですが、Accept
をヘッダにつけて、値を目的の画像のメディアバイナリタイプとしましょう。
これを忘れると正常に画像が取得できません。
今回はAPI Gateway
とLambda
を用いて作成するREST API
において、画像(バイナリ)を扱う際の実装の簡単なサンプルを紹介しました。
忘れがちなのがAPI Gateway
側で「メディアバイナリタイプ」を設定し忘れていたり、取得時にAccept
をヘッダにつけていなかったり等です。
この場合、ログを見てもLambda
は正常に動いており、そこから先のAPI Gatway
とのデータの授受で失敗しているのでなかなか気づきにくいです。
今回の内容が役立ちましたら幸いです。