このセクションでは、Amazon S3 Object Lambda アクセスポイントで使用するための AWS Lambda 関数を記述する方法について詳述します。
S3 Object Lambda の一部のタスクにおける完全なエンドツーエンド手順については、以下を参照してください。
トピック
Lambda での GetObject
リクエストの使用
このセクションでは、Object Lambda アクセスポイントが GetObject
用に Lambda 関数を呼び出すように設定されていることを前提としています。S3 Object Lambda には、Amazon S3 API オペレーション、WriteGetObjectResponse
が含まれています。これにより、Lambda 関数は、カスタマイズされたデータとレスポンスヘッダーを GetObject
発信者に提供できるようになります。
WriteGetObjectResponse
は、処理のニーズに基づいて、ステータスコード、レスポンスヘッダー、レスポンス本文を広範囲に制御できます。WriteGetObjectResponse
を使用すると、変換されたオブジェクト全体、変換されたオブジェクトの一部、またはアプリケーションのコンテキストに基づくその他のレスポンスに対して応答することができます。次のセクションでは、WriteGetObjectResponse
API オペレーションを使用した一意の例を示します。
-
例 1: HTTP ステータスコード 403 (Forbidden) で応答します。
-
例 2: 変換された画像で応答する
-
例 3: 圧縮されたコンテンツをストリーミングする
例 1: HTTP ステータスコード 403 (Forbidden) で応答します。
WriteGetObjectResponse
を使用して、オブジェクトの内容に基づいて HTTP ステータスコード 403 (Forbidden) で応答できます。
package com.amazon.s3.objectlambda;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.S3ObjectLambdaEvent;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.WriteGetObjectResponseRequest;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example1 {
public void handleRequest(S3ObjectLambdaEvent event, Context context) throws Exception {
AmazonS3 s3Client = AmazonS3Client.builder().build();
// Check to see if the request contains all of the necessary information.
// If it does not, send a 4XX response and a custom error code and message.
// Otherwise, retrieve the object from S3 and stream it
// to the client unchanged.
var tokenIsNotPresent = !event.getUserRequest().getHeaders().containsKey("requiredToken");
if (tokenIsNotPresent) {
s3Client.writeGetObjectResponse(new WriteGetObjectResponseRequest()
.withRequestRoute(event.outputRoute())
.withRequestToken(event.outputToken())
.withStatusCode(403)
.withContentLength(0L).withInputStream(new ByteArrayInputStream(new byte[0]))
.withErrorCode("MissingRequiredToken")
.withErrorMessage("The required token was not present in the request."));
return;
}
// Prepare the presigned URL for use and make the request to S3.
HttpClient httpClient = HttpClient.newBuilder().build();
var presignedResponse = httpClient.send(
HttpRequest.newBuilder(new URI(event.inputS3Url())).GET().build(),
HttpResponse.BodyHandlers.ofInputStream());
// Stream the original bytes back to the caller.
s3Client.writeGetObjectResponse(new WriteGetObjectResponseRequest()
.withRequestRoute(event.outputRoute())
.withRequestToken(event.outputToken())
.withInputStream(presignedResponse.body()));
}
}
例 2: 変換された画像で応答する
画像変換を実行する場合、ソースオブジェクトの処理を開始する前に、ソースオブジェクトのすべてのバイトが必要になる可能性があります。この場合、WriteGetObjectResponse
リクエストは、オブジェクト全体を 1 回の呼び出しでリクエスト元のアプリケーションに返します。
package com.amazon.s3.objectlambda;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.S3ObjectLambdaEvent;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.WriteGetObjectResponseRequest;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.Image;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example2 {
private static final int HEIGHT = 250;
private static final int WIDTH = 250;
public void handleRequest(S3ObjectLambdaEvent event, Context context) throws Exception {
AmazonS3 s3Client = AmazonS3Client.builder().build();
HttpClient httpClient = HttpClient.newBuilder().build();
// Prepare the presigned URL for use and make the request to S3.
var presignedResponse = httpClient.send(
HttpRequest.newBuilder(new URI(event.inputS3Url())).GET().build(),
HttpResponse.BodyHandlers.ofInputStream());
// The entire image is loaded into memory here so that we can resize it.
// Once the resizing is completed, we write the bytes into the body
// of the WriteGetObjectResponse request.
var originalImage = ImageIO.read(presignedResponse.body());
var resizingImage = originalImage.getScaledInstance(WIDTH, HEIGHT, Image.SCALE_DEFAULT);
var resizedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
resizedImage.createGraphics().drawImage(resizingImage, 0, 0, WIDTH, HEIGHT, null);
var baos = new ByteArrayOutputStream();
ImageIO.write(resizedImage, "png", baos);
// Stream the bytes back to the caller.
s3Client.writeGetObjectResponse(new WriteGetObjectResponseRequest()
.withRequestRoute(event.outputRoute())
.withRequestToken(event.outputToken())
.withInputStream(new ByteArrayInputStream(baos.toByteArray())));
}
}
例 3: 圧縮されたコンテンツをストリーミングする
オブジェクトを圧縮すると、圧縮データは増分的に生成されます。したがって、準備ができたらすぐに圧縮されたデータを返すために、WriteGetObjectResponse
リクエストを使用できます。この例で示すように、完了した変換の長さを知る必要はありません。
package com.amazon.s3.objectlambda;
import com.amazonaws.services.lambda.runtime.events.S3ObjectLambdaEvent;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.WriteGetObjectResponseRequest;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example3 {
public void handleRequest(S3ObjectLambdaEvent event, Context context) throws Exception {
AmazonS3 s3Client = AmazonS3Client.builder().build();
HttpClient httpClient = HttpClient.newBuilder().build();
// Request the original object from S3.
var presignedResponse = httpClient.send(
HttpRequest.newBuilder(new URI(event.inputS3Url())).GET().build(),
HttpResponse.BodyHandlers.ofInputStream());
// Consume the incoming response body from the presigned request,
// apply our transformation on that data, and emit the transformed bytes
// into the body of the WriteGetObjectResponse request as soon as they're ready.
// This example compresses the data from S3, but any processing pertinent
// to your application can be performed here.
var bodyStream = new GZIPCompressingInputStream(presignedResponse.body());
// Stream the bytes back to the caller.
s3Client.writeGetObjectResponse(new WriteGetObjectResponseRequest()
.withRequestRoute(event.outputRoute())
.withRequestToken(event.outputToken())
.withInputStream(bodyStream));
}
}
注記
S3 Object Lambda では、発信者に完全なレスポンスを送信するのに最大 60 秒かかります。WriteGetObjectResponse
リクエストの場合、実際の利用可能な時間は短くなる可能性があります。例えば、Lambda 関数のタイムアウトが 60 秒未満である可能性があります。それ以外にも、発信者のタイムアウトがより厳しい場合があります。
元の発信者が HTTP ステータスコード 500 以外のレスポンス (内部サーバエラー) を受信するには、WriteGetObjectResponse
コールが完了する必要があります。WriteGetObjectResponse
API オペレーションが呼び出される前に、Lambda 関数が例外的に、またはその他の方法で返された場合、元の発信者は 500 (内部サーバーエラー) レスポンスを受け取ります。レスポンスが完了するまでの間にスローされた例外は、発信者へのレスポンスが切り捨てられます。Lambda 関数が WriteGetObjectResponse
API コールから HTTP ステータスコード 200 (OK) レスポンスを受信した場合、元の発信者は完全なリクエストを送信しています。例外がスローされたかどうかにかかわらず、Lambda 関数のレスポンスは S3 Object Lambda では無視されます。
この WriteGetObjectResponse
API オペレーションを呼び出すとき、Amazon S3 はイベントコンテキストからのルートトークンとリクエストトークンを必要とします。詳細については、「イベントコンテキストの形式と使用法」を参照してください。
ルートトークンとリクエストトークンのパラメータは、WriteGetObjectResult
レスポンスを元の発信者に接続するために必要です。通常、500 (内部サーバーエラー) レスポンスを再試行するのが適切ですが、リクエストトークンはワンタイムトークンであることに注意してください。それ以降に使用を試みると、HTTP ステータスコード 400 (Bad Request) レスポンスが返されることになる可能性があります。ルートトークンとリクエストトークンを使用した WriteGetObjectResponse
への呼び出しは、呼び出された Lambda 関数から作成する必要はありませんが、同じアカウント内のアイデンティティによって作成する必要があります。この呼び出しは、Lambda 関数の実行を完了する前に完了する必要があります。
Lambdaでの HeadObject
リクエストの処理
このセクションでは、Object Lambda アクセスポイントが HeadObject
用に Lambda 関数を呼び出すように設定されていることを前提としています。Lambda は headObjectContext
というキーを含む JSON ペイロードを受け取ります。コンテキスト内には、inputS3Url
というプロパティが 1 つあります。これは、HeadObject
をサポートしているアクセスポイントの署名付き URL です。
署名付き URL に次のプロパティが指定されている場合、署名付き URL にはそれらが含まれます。
-
versionId
(クエリパラメータ内) -
requestPayer
(x-amz-request-payer
ヘッダー内) -
expectedBucketOwner
(x-amz-expected-bucket-owner
ヘッダー内)
他のプロパティは署名付きではないため、含まれません。ヘッダーとして送信される署名されていないオプションは、userRequest
ヘッダーにある署名付き URL を呼び出すときに、手動でリクエストに追加できます。サーバー側の暗号化オプションは、HeadObject
ではサポートされていません。
リクエスト構文 URI パラメータについては、「Amazon Simple Storage Service API リファレンス」の「HeadObject
」を参照してください。
次の例は、HeadObject
の Lambda JSON 入力ペイロードを示しています。
{ "xAmzRequestId": "
requestId
", "**headObjectContext**": { "**inputS3Url**": "https://my-s3-ap-111122223333
.s3-accesspoint.us-east-1
.amazonaws.com/example?X-Amz-Security-Token=<snip>" }, "configuration": { "accessPointArn": "arn:aws:s3-object-lambda:us-east-1
:111122223333
:accesspoint/example-object-lambda-ap
", "supportingAccessPointArn": "arn:aws:s3:us-east-1
:111122223333
:accesspoint/example-ap
", "payload": "{}" }, "userRequest": { "url": "https://object-lambda-111122223333
.s3-object-lambda.us-east-1
.amazonaws.com/example
", "headers": { "Host": "object-lambda-111122223333
.s3-object-lambda.us-east-1
.amazonaws.com", "Accept-Encoding": "identity", "X-Amz-Content-SHA256": "e3b0c44298fc1example
" } }, "userIdentity": { "type": "AssumedRole", "principalId": "principalId
", "arn": "arn:aws:sts::111122223333
:assumed-role/Admin/example
", "accountId": "111122223333
", "accessKeyId": "accessKeyId
", "sessionContext": { "attributes": { "mfaAuthenticated": "false", "creationDate": "Wed Mar 10 23:41:52 UTC 2021" }, "sessionIssuer": { "type": "Role", "principalId": "principalId
", "arn": "arn:aws:iam::111122223333
:role/Admin", "accountId": "111122223333
", "userName": "Admin" } } }, "protocolVersion": "1.00" }
Lambda 関数は、HeadObject
呼び出しで返されるヘッダーと値を含む JSON オブジェクトを返します。
次の例は、HeadObject
の Lambda レスポンス JSON の構造を示しています。
{
"statusCode": <number>; // Required
"errorCode": <string>;
"errorMessage": <string>;
"headers": {
"Accept-Ranges": <string>,
"x-amz-archive-status": <string>,
"x-amz-server-side-encryption-bucket-key-enabled": <boolean>,
"Cache-Control": <string>,
"Content-Disposition": <string>,
"Content-Encoding": <string>,
"Content-Language": <string>,
"Content-Length": <number>, // Required
"Content-Type": <string>,
"x-amz-delete-marker": <boolean>,
"ETag": <string>,
"Expires": <string>,
"x-amz-expiration": <string>,
"Last-Modified": <string>,
"x-amz-missing-meta": <number>,
"x-amz-object-lock-mode": <string>,
"x-amz-object-lock-legal-hold": <string>,
"x-amz-object-lock-retain-until-date": <string>,
"x-amz-mp-parts-count": <number>,
"x-amz-replication-status": <string>,
"x-amz-request-charged": <string>,
"x-amz-restore": <string>,
"x-amz-server-side-encryption": <string>,
"x-amz-server-side-encryption-customer-algorithm": <string>,
"x-amz-server-side-encryption-aws-kms-key-id": <string>,
"x-amz-server-side-encryption-customer-key-MD5": <string>,
"x-amz-storage-class": <string>,
"x-amz-tagging-count": <number>,
"x-amz-version-id": <string>,
<x-amz-meta-headers>: <string>, // user-defined metadata
"x-amz-meta-meta1": <string>, // example of the user-defined metadata header, it will need the x-amz-meta prefix
"x-amz-meta-meta2": <string>
...
};
}
次の例は、JSON を返す前に必要に応じてヘッダー値を変更することにより、署名付き URL を使用してレスポンスを入力する方法を示しています。
import requests
def lambda_handler(event, context):
print(event)
# Extract the presigned URL from the input.
s3_url = event["headObjectContext"]["inputS3Url"]
# Get the head of the object from S3.
response = requests.head(s3_url)
# Return the error to S3 Object Lambda (if applicable).
if (response.status_code >= 400):
return {
"statusCode": response.status_code,
"errorCode": "RequestFailure",
"errorMessage": "Request to S3 failed"
}
# Store the headers in a dictionary.
response_headers = dict(response.headers)
# This obscures Content-Type in a transformation, it is optional to add
response_headers["Content-Type"] = ""
# Return the headers to S3 Object Lambda.
return {
"statusCode": response.status_code,
"headers": response_headers
}
Lambda での ListObjects
リクエストの使用
このセクションでは、Object Lambda アクセスポイントが ListObjects
用に Lambda 関数を呼び出すように設定されていることを前提としています。Lambda は、listObjectsContext
という新しいオブジェクトを持つ JSON ペイロードを受け取ります。listObjectsContext
には、inputS3Url
という単一のプロパティが含まれており、これは ListObjects
をサポートしているアクセスポイント用の署名付き URL です。
GetObject
や HeadObject
とは異なり、署名付き URL には、次のプロパティが指定されている場合はそれらが含まれます。
-
すべてのクエリパラメータ
-
requestPayer
(x-amz-request-payer
ヘッダー内) -
expectedBucketOwner
(x-amz-expected-bucket-owner
ヘッダー内)
リクエスト構文 URI パラメータについては、「Amazon Simple Storage Service API リファレンス」の「ListObjects
」を参照してください。
重要
アプリケーションを開発する場合は、新しいバージョンの ListObjectSv2 を使用することをお勧めします。Amazon S3 は、下位互換性のために、引き続き ListObjects
をサポートしています。
次の例は、ListObjects
の Lambda JSON 入力ペイロードを示しています。
{ "xAmzRequestId": "
requestId
", "**listObjectsContext**": { "**inputS3Url**": "https://my-s3-ap-111122223333
.s3-accesspoint.us-east-1
.amazonaws.com/?X-Amz-Security-Token=<snip>", }, "configuration": { "accessPointArn": "arn:aws:s3-object-lambda:us-east-1
:111122223333
:accesspoint/example-object-lambda-ap
", "supportingAccessPointArn": "arn:aws:s3:us-east-1
:111122223333
:accesspoint/example-ap
", "payload": "{}" }, "userRequest": { "url": "https://object-lambda-111122223333
.s3-object-lambda.us-east-1
.amazonaws.com/example
", "headers": { "Host": "object-lambda-111122223333
.s3-object-lambda.us-east-1
.amazonaws.com", "Accept-Encoding": "identity", "X-Amz-Content-SHA256": "e3b0c44298fc1example
" } }, "userIdentity": { "type": "AssumedRole", "principalId": "principalId
", "arn": "arn:aws:sts::111122223333
:assumed-role/Admin/example
", "accountId": "111122223333
", "accessKeyId": "accessKeyId
", "sessionContext": { "attributes": { "mfaAuthenticated": "false", "creationDate": "Wed Mar 10 23:41:52 UTC 2021" }, "sessionIssuer": { "type": "Role", "principalId": "principalId
", "arn": "arn:aws:iam::111122223333
:role/Admin", "accountId": "111122223333
", "userName": "Admin" } } }, "protocolVersion": "1.00" }
Lambda 関数は、S3 Object Lambda から返されるステータスコード、XML 結果のリスト、またはエラー情報を含む JSON オブジェクトを返します。
S3 Object Lambda は listResultXml
の処理も検証もせず、代わりに ListObjects
呼び出し元に転送します。listBucketResult
については、S3 Object Lambda は特定のプロパティが特定のタイプであることを想定し、解析できない場合は例外をスローします。 listResultXml
および listBucketResult
を同時に提供することはできません。
次の例は、署名付き URL を使用して Amazon S3 を呼び出し、その結果を使用してエラーチェックを含むレスポンスを入力する方法を示しています。
import requests
import xmltodict
def lambda_handler(event, context):
# Extract the presigned URL from the input.
s3_url = event["listObjectsContext"]["inputS3Url"]
# Get the head of the object from Amazon S3.
response = requests.get(s3_url)
# Return the error to S3 Object Lambda (if applicable).
if (response.status_code >= 400):
error = xmltodict.parse(response.content)
return {
"statusCode": response.status_code,
"errorCode": error["Error"]["Code"],
"errorMessage": error["Error"]["Message"]
}
# Store the XML result in a dict.
response_dict = xmltodict.parse(response.content)
# This obscures StorageClass in a transformation, it is optional to add
for item in response_dict['ListBucketResult']['Contents']:
item['StorageClass'] = ""
# Convert back to XML.
listResultXml = xmltodict.unparse(response_dict)
# Create response with listResultXml.
response_with_list_result_xml = {
'statusCode': 200,
'listResultXml': listResultXml
}
# Create response with listBucketResult.
response_dict['ListBucketResult'] = sanitize_response_dict(response_dict['ListBucketResult'])
response_with_list_bucket_result = {
'statusCode': 200,
'listBucketResult': response_dict['ListBucketResult']
}
# Return the list to S3 Object Lambda.
# Can return response_with_list_result_xml or response_with_list_bucket_result
return response_with_list_result_xml
# Converting the response_dict's key to correct casing
def sanitize_response_dict(response_dict: dict):
new_response_dict = dict()
for key, value in response_dict.items():
new_key = key[0].lower() + key[1:] if key != "ID" else 'id'
if type(value) == list:
newlist = []
for element in value:
if type(element) == type(dict()):
element = sanitize_response_dict(element)
newlist.append(element)
value = newlist
elif type(value) == dict:
value = sanitize_response_dict(value)
new_response_dict[new_key] = value
return new_response_dict
次の例は、ListObjects
の Lambda レスポンス JSON の構造を示しています。
{
"statusCode": <number>; // Required
"errorCode": <string>;
"errorMessage": <string>;
"listResultXml": <string>; // This can also be Error XML string in case S3 returned error response when calling the pre-signed URL
"listBucketResult": { // listBucketResult can be provided instead of listResultXml, however they can not both be provided in the JSON response
"name": <string>, // Required for 'listBucketResult'
"prefix": <string>,
"marker": <string>,
"nextMarker": <string>,
"maxKeys": <int>, // Required for 'listBucketResult'
"delimiter": <string>,
"encodingType": <string>
"isTruncated": <boolean>, // Required for 'listBucketResult'
"contents": [ {
"key": <string>, // Required for 'content'
"lastModified": <string>,
"eTag": <string>,
"checksumAlgorithm": <string>, // CRC32, CRC32C, SHA1, SHA256
"size": <int>, // Required for 'content'
"owner": {
"displayName": <string>, // Required for 'owner'
"id": <string>, // Required for 'owner'
},
"storageClass": <string>
},
...
],
"commonPrefixes": [ {
"prefix": <string> // Required for 'commonPrefix'
},
...
],
}
}
Lambda での ListObjectsV2
リクエストの使用
このセクションでは、Object Lambda アクセスポイントが ListObjectsV2
用に Lambda 関数を呼び出すように設定されていることを前提としています。Lambda は、listObjectsV2Context
という新しいオブジェクトを持つ JSON ペイロードを受け取ります。listObjectsV2Context
には、inputS3Url
という単一のプロパティが含まれており、これは ListObjectsV2
をサポートしているアクセスポイント用の署名付き URL です。
GetObject
や HeadObject
とは異なり、署名付き URL には、次のプロパティが指定されている場合はそれらが含まれます。
-
すべてのクエリパラメータ
-
requestPayer
(x-amz-request-payer
ヘッダー内) -
expectedBucketOwner
(x-amz-expected-bucket-owner
ヘッダー内)
リクエスト構文 URI パラメータについては、「Amazon Simple Storage Service API リファレンス」の「ListObjectsV2
」を参照してください。
次の例は、ListObjectsV2
の Lambda JSON 入力ペイロードを示しています。
{ "xAmzRequestId": "
requestId
", "**listObjectsV2Context**": { "**inputS3Url**": "https://my-s3-ap-111122223333
.s3-accesspoint.us-east-1
.amazonaws.com/?list-type=2&X-Amz-Security-Token=<snip>", }, "configuration": { "accessPointArn": "arn:aws:s3-object-lambda:us-east-1
:111122223333
:accesspoint/example-object-lambda-ap
", "supportingAccessPointArn": "arn:aws:s3:us-east-1
:111122223333
:accesspoint/example-ap
", "payload": "{}" }, "userRequest": { "url": "https://object-lambda-111122223333
.s3-object-lambda.us-east-1
.amazonaws.com/example
", "headers": { "Host": "object-lambda-111122223333
.s3-object-lambda.us-east-1
.amazonaws.com", "Accept-Encoding": "identity", "X-Amz-Content-SHA256": "e3b0c44298fc1example
" } }, "userIdentity": { "type": "AssumedRole", "principalId": "principalId
", "arn": "arn:aws:sts::111122223333
:assumed-role/Admin/example
", "accountId": "111122223333
", "accessKeyId": "accessKeyId
", "sessionContext": { "attributes": { "mfaAuthenticated": "false", "creationDate": "Wed Mar 10 23:41:52 UTC 2021" }, "sessionIssuer": { "type": "Role", "principalId": "principalId
", "arn": "arn:aws:iam::111122223333
:role/Admin", "accountId": "111122223333
", "userName": "Admin" } } }, "protocolVersion": "1.00" }
Lambda 関数は、S3 Object Lambda から返されるステータスコード、XML 結果のリスト、またはエラー情報を含む JSON オブジェクトを返します。
S3 Object Lambda は listResultXml
の処理も検証もせず、代わりに ListObjectsV2
呼び出し元に転送します。listBucketResult
については、S3 Object Lambda は特定のプロパティが特定のタイプであることを想定し、解析できない場合は例外をスローします。 listResultXml
および listBucketResult
を同時に提供することはできません。
次の例は、署名付き URL を使用して Amazon S3 を呼び出し、その結果を使用してエラーチェックを含むレスポンスを入力する方法を示しています。
import requests
import xmltodict
def lambda_handler(event, context):
# Extract the presigned URL from the input.
s3_url = event["listObjectsV2Context"]["inputS3Url"]
# Get the head of the object from Amazon S3.
response = requests.get(s3_url)
# Return the error to S3 Object Lambda (if applicable).
if (response.status_code >= 400):
error = xmltodict.parse(response.content)
return {
"statusCode": response.status_code,
"errorCode": error["Error"]["Code"],
"errorMessage": error["Error"]["Message"]
}
# Store the XML result in a dict.
response_dict = xmltodict.parse(response.content)
# This obscures StorageClass in a transformation, it is optional to add
for item in response_dict['ListBucketResult']['Contents']:
item['StorageClass'] = ""
# Convert back to XML.
listResultXml = xmltodict.unparse(response_dict)
# Create response with listResultXml.
response_with_list_result_xml = {
'statusCode': 200,
'listResultXml': listResultXml
}
# Create response with listBucketResult.
response_dict['ListBucketResult'] = sanitize_response_dict(response_dict['ListBucketResult'])
response_with_list_bucket_result = {
'statusCode': 200,
'listBucketResult': response_dict['ListBucketResult']
}
# Return the list to S3 Object Lambda.
# Can return response_with_list_result_xml or response_with_list_bucket_result
return response_with_list_result_xml
# Converting the response_dict's key to correct casing
def sanitize_response_dict(response_dict: dict):
new_response_dict = dict()
for key, value in response_dict.items():
new_key = key[0].lower() + key[1:] if key != "ID" else 'id'
if type(value) == list:
newlist = []
for element in value:
if type(element) == type(dict()):
element = sanitize_response_dict(element)
newlist.append(element)
value = newlist
elif type(value) == dict:
value = sanitize_response_dict(value)
new_response_dict[new_key] = value
return new_response_dict
次の例は、ListObjectsV2
の Lambda レスポンス JSON の構造を示しています。
{
"statusCode": <number>; // Required
"errorCode": <string>;
"errorMessage": <string>;
"listResultXml": <string>; // This can also be Error XML string in case S3 returned error response when calling the pre-signed URL
"listBucketResult": { // listBucketResult can be provided instead of listResultXml, however they can not both be provided in the JSON response
"name": <string>, // Required for 'listBucketResult'
"prefix": <string>,
"startAfter": <string>,
"continuationToken": <string>,
"nextContinuationToken": <string>,
"keyCount": <int>, // Required for 'listBucketResult'
"maxKeys": <int>, // Required for 'listBucketResult'
"delimiter": <string>,
"encodingType": <string>
"isTruncated": <boolean>, // Required for 'listBucketResult'
"contents": [ {
"key": <string>, // Required for 'content'
"lastModified": <string>,
"eTag": <string>,
"checksumAlgorithm": <string>, // CRC32, CRC32C, SHA1, SHA256
"size": <int>, // Required for 'content'
"owner": {
"displayName": <string>, // Required for 'owner'
"id": <string>, // Required for 'owner'
},
"storageClass": <string>
},
...
],
"commonPrefixes": [ {
"prefix": <string> // Required for 'commonPrefix'
},
...
],
}
}