“画像が表示されない?”AWS CDK, API GatewayとLambdaを用いた画像返却APIの修正

環境

API Gateway
Lambda(Python)
AWS CDK(typescript)

概要

zxy方式のラスター画像を会得しleafletなどでフロントに表示したかったため、ラスター画像を送信する以下のようなAPIを、AWSCDK, API GatewayとLambdaを用いて作っていた。

"https://lusterapi.ap-northeast-1.amazonaws.com/v1/{z}/{x}/{y}",

 

こちらのAPI URLにパラメータ入れてアクセスすると以下のように画像が出てくれると嬉しかった。

 

しかし以下のように、API URLにアクセスしても画像が表示されない問題が発生してしまった。

 

 

エラーの原因

このURLについてPythonのRequestでは取れているため、API自体が何も返していないわけではないことがわかった。

url="https://lusterapi.ap-northeast-1.amazonaws.com/v1/{z}/{x}/{y}"

Request.get(url)

 

さらに帰ってきているレスポンスの内容を確かめるとバイナリデータであり、base64エンコードをすると無事保存もできた。

以下確認とbase64エンコードのPythonコード。

import requests
import base64
z='任意の値'
x='任意の値'y='任意の値'
url = f"https://lusterapi.ap-northeast-1.amazonaws.com/v1/{z}/{x}/{y}"
response = requests.get(url)

# レスポンスがバイナリデータであることを確認
if response.content:
    # バイナリデータをBase64エンコード
    encoded_data = base64.b64encode(response.content)

    # Base64エンコードされたデータをデコードして画像として保存
    with open('output.png', 'wb') as f:
    f.write(base64.b64decode(encoded_data))
else:
    print("No response data received.")


つまり、
Base64エンコードされた画像をレスポンスボディとして返す必要がある。

 

解決策

調べてみると以下のように、AWSコンソール上でのバイナリタイプ変更の記事がいくつかヒットしたんですが、AWSCDKでの変更記事が全然見当たらなかった、、。

Qiita

ApiGateway + LambdaのExpressで画像も配信したら表示されなかったのでその時の対応メモ画像のヘッダ…

Qiita

概要API GatewayとLambdaでS3にある画像を返却するクライアント側からは単にURLにアクセスしたら画像が表…

どうにか公式やchatGPT参照しながら以下の解決方法を発見。

AWSCDKのコードに  binaryMediaTypes: [‘*/*’を追加するだけでよかったみたい。

    // API Gateway RestAPIの作成

    const nameRestApi ="Luster API";

    const restApi = new aws_apigateway.RestApi(this, nameRestApi, {

      restApiName: `Luster_API`,

      binaryMediaTypes: ['*/*'],  // ここに追加

      deployOptions: {

        stageName: 'v1',

      },

    });

    //API Gatewayにリクエスト先のリソースを追加

    let restApiLuster = restApi.root.addResource('{z}');

    restApiLuster = restApiLuster.addResource('{x}');

    restApiLuster = restApiLuster.addResource('{y}');

    //リソースにGETメソッド、Lambda統合プロキシを指定

    restApiLuster.addMethod(

      'GET',

      new aws_apigateway.LambdaIntegration(fnc)

    );

また、APIに紐づくlambda内のレスポンス設定も以下のようにbase64に設定しておく必要もあるため変更。

    # header情報

    headers = {

        'Content-Type': 'image/png',

        'Access-Control-Allow-Origin': '*'

    }

    # レスポンス

    res = {

        "statusCode": 200,

        "headers": headers,

        'body': base64.b64encode(open(outpng, 'rb').read()).decode('utf-8'),

        'isBase64Encoded': True

    }

これらの変更を適用した後、ブラウザのURLバーにAPI URLを直接入力すると、無事画像が表示された!!