Skip to content

Commit 943bb4f

Browse files
svozzasdangol
andauthored
docs(event-handler): update binary response docs (aws-powertools#4783)
Co-authored-by: Swopnil Dangol <[email protected]>
1 parent dd9b722 commit 943bb4f

File tree

9 files changed

+105
-22
lines changed

9 files changed

+105
-22
lines changed

docs/features/event-handler/rest.md

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -514,33 +514,84 @@ You can enable response compression by using the `compress` middleware. This wil
514514

515515
### Binary responses
516516

517-
!!! note "Coming soon"
517+
If you need to return binary data, there are several ways you can do so based on how much control you require.
518+
519+
#### Auto serialization
518520

519521
As described in the [response auto serialization](#response-auto-serialization) section, when you return a JavaScript object from your route handler, we automatically serialize it to JSON and set the `Content-Type` header to `application/json`.
520522

521-
If you need to return binary data (e.g. images, PDFs, etc), you will need to return an API Gateway Proxy result directly, setting the `isBase64Encoded` flag to `true` and base64 encoding the binary data, as well as setting the appropriate `Content-Type` header.
523+
A similar pattern applies to binary data where you can return an `ArrayBuffer`,
524+
a [Nodejs stream](https://nodejs.org/api/stream.html){target="_blank"}, or
525+
a [Web stream](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API#browser_compatibility){target="_blank"}
526+
directly from your handler. We will automatically serialize the response by setting the `isBase64Encoded` flag to `true` and `base64` encoding the binary data.
527+
528+
!!! note "Content types"
529+
The default header will be set to `application/json`. If you wish to change this,
530+
e.g., in the case of images, PDFs, videos, etc, then you should use the `reqCtx.res.headers` object to set the appropriate header.
522531

523532
=== "index.ts"
524533

525-
```ts hl_lines="10-17"
526-
--8<-- "examples/snippets/event-handler/rest/advanced_binary_responses.ts"
534+
```ts hl_lines="8-9"
535+
--8<-- "examples/snippets/event-handler/rest/advanced_binary_response_auto.ts"
527536
```
528537

529538
=== "Request"
530539

531540
```json
532-
--8<-- "examples/snippets/event-handler/rest/samples/advanced_binary_req.json"
541+
--8<-- "examples/snippets/event-handler/rest/samples/advanced_binary_req_logo_image.json"
533542
```
534543

535544
=== "Response"
536545

537546
```json
538-
--8<-- "examples/snippets/event-handler/rest/samples/advanced_binary_res.json"
547+
--8<-- "examples/snippets/event-handler/rest/samples/advanced_binary_res_logo_image.json"
539548
```
540549

541-
You can use binary responses together with the [`compress`](#compress) feature, and the client must send the `Accept` header with the correct media type.
550+
#### Set `isBase64Encoded` parameter
542551

543-
We plan to add first-class support for binary responses in a future release. Please [check this issue](https://github.com/aws-powertools/powertools-lambda-typescript/issues/4514) for more details and examples, and add 👍 if you would like us to prioritize it.
552+
You can indicate that you wish to `base64` encode any response, regardless of type, by setting the `isBase64Encoded` field in `reqCtx` to `true`.
553+
554+
=== "index.ts"
555+
556+
```ts hl_lines="7"
557+
--8<-- "examples/snippets/event-handler/rest/advanced_binary_response_reqCtx.ts"
558+
```
559+
560+
=== "Request"
561+
562+
```json
563+
--8<-- "examples/snippets/event-handler/rest/samples/advanced_binary_req_json64.json"
564+
```
565+
566+
=== "Response"
567+
568+
```json
569+
--8<-- "examples/snippets/event-handler/rest/samples/advanced_binary_res_json64.json"
570+
```
571+
572+
#### Manual serialization
573+
574+
For complete control you can return an `APIGatewayProxyEvent` (`v1` or `v2`) and this will be handled transparently by the resolver.
575+
576+
=== "index.ts"
577+
578+
```ts hl_lines="8-16"
579+
--8<-- "examples/snippets/event-handler/rest/advanced_binary_response_manual.ts"
580+
```
581+
582+
=== "Request"
583+
584+
```json
585+
--8<-- "examples/snippets/event-handler/rest/samples/advanced_binary_req_logo_image.json"
586+
```
587+
588+
=== "Response"
589+
590+
```json
591+
--8<-- "examples/snippets/event-handler/rest/samples/advanced_binary_res_logo_image.json"
592+
```
593+
!!! note "Compression"
594+
If you wish to use binary responses together with the [`compress`](#compress) feature, the client must send the `Accept` header with the correct media type.
544595

545596
### Response streaming
546597

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { createReadStream } from 'node:fs';
2+
import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest';
3+
import type { Context } from 'aws-lambda';
4+
5+
const app = new Router();
6+
7+
app.get('/logo', async (reqCtx) => {
8+
reqCtx.res.headers.set('Content-Type', 'image/png');
9+
return createReadStream(`${process.env.LAMBDA_TASK_ROOT}/logo.png`);
10+
});
11+
12+
export const handler = async (event: unknown, context: Context) =>
13+
app.resolve(event, context);

examples/snippets/event-handler/rest/advanced_binary_responses.ts renamed to examples/snippets/event-handler/rest/advanced_binary_response_manual.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { readFile } from 'node:fs/promises';
22
import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest';
3-
import { compress } from '@aws-lambda-powertools/event-handler/experimental-rest/middleware';
43
import type { Context } from 'aws-lambda';
54

65
const app = new Router();
76

8-
app.get('/logo', [compress()], async () => {
7+
app.get('/logo', async () => {
98
const logoFile = await readFile(`${process.env.LAMBDA_TASK_ROOT}/logo.png`);
109
return {
1110
body: logoFile.toString('base64'),
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Router } from '@aws-lambda-powertools/event-handler/experimental-rest';
2+
import type { Context } from 'aws-lambda';
3+
4+
const app = new Router();
5+
6+
app.get('/json64', async (reqCtx) => {
7+
reqCtx.isBase64Encoded = true;
8+
return { message: 'Hello World!' };
9+
});
10+
11+
export const handler = async (event: unknown, context: Context) =>
12+
app.resolve(event, context);

examples/snippets/event-handler/rest/samples/advanced_binary_req.json

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"resource": "/json64",
3+
"path": "/json64",
4+
"httpMethod": "GET"
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"resource": "/logo",
3+
"path": "/logo",
4+
"httpMethod": "GET"
5+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"body": "eyJtZXNzYWdlIjoiSGVsbG8gV29ybGQifQ==",
3+
"headers": {
4+
"Content-Type": "application/json"
5+
},
6+
"isBase64Encoded": true,
7+
"statusCode": 200
8+
}

examples/snippets/event-handler/rest/samples/advanced_binary_res.json renamed to examples/snippets/event-handler/rest/samples/advanced_binary_res_logo_image.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
{
22
"body": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjU2cHgiIGhlaWdodD0iMjU2cHgiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4KICAgIDx0aXRsZT5BV1MgTGFtYmRhPC90aXRsZT4KICAgIDxkZWZzPgogICAgICAgIDxsaW5lYXJHcmFkaWVudCB4MT0iMCUiIHkxPSIxMDAlIiB4Mj0iMTAwJSIgeTI9IjAlIiBpZD0ibGluZWFyR3JhZGllbnQtMSI+CiAgICAgICAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNDODUxMUIiIG9mZnNldD0iMCUiPjwvc3RvcD4KICAgICAgICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0ZGOTkwMCIgb2Zmc2V0PSIxMDAlIj48L3N0b3A+CiAgICAgICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDwvZGVmcz4KICAgIDxnPgogICAgICAgIDxyZWN0IGZpbGw9InVybCgjbGluZWFyR3JhZGllbnQtMSkiIHg9IjAiIHk9IjAiIHdpZHRoPSIyNTYiIGhlaWdodD0iMjU2Ij48L3JlY3Q+CiAgICAgICAgPHBhdGggZD0iTTg5LjYyNDExMjYsMjExLjIgTDQ5Ljg5MDMyNzcsMjExLjIgTDkzLjgzNTQ4MzIsMTE5LjM0NzIgTDExMy43NDcyOCwxNjAuMzM5MiBMODkuNjI0MTEyNiwyMTEuMiBaIE05Ni43MDI5MzU3LDExMC41Njk2IEM5Ni4xNjQwODU4LDEwOS40NjU2IDk1LjA0MTQ4MTMsMTA4Ljc2NDggOTMuODE2MjM4NCwxMDguNzY0OCBMOTMuODA2NjE2MywxMDguNzY0OCBDOTIuNTcxNzUxNCwxMDguNzY4IDkxLjQ0OTE0NjYsMTA5LjQ3NTIgOTAuOTE5OTE4NywxMTAuNTg1NiBMNDEuOTEzNDIwOCwyMTMuMDIwOCBDNDEuNDM4NzE5NywyMTQuMDEyOCA0MS41MDYwNzU4LDIxNS4xNzc2IDQyLjA5NjI0NTEsMjE2LjEwODggQzQyLjY3OTk5OTQsMjE3LjAzNjggNDMuNzA2MzgwNSwyMTcuNiA0NC44MDY1MzMxLDIxNy42IEw5MS42NTQ0MjMsMjE3LjYgQzkyLjg5NTcwMjcsMjE3LjYgOTQuMDIxNTE0OSwyMTYuODg2NCA5NC41NTM5NTAxLDIxNS43Njk2IEwxMjAuMjAzODU5LDE2MS42ODk2IEMxMjAuNjE3NjE5LDE2MC44MTI4IDEyMC42MTQ0MTIsMTU5Ljc5ODQgMTIwLjE4NzgyMiwxNTguOTI4IEw5Ni43MDI5MzU3LDExMC41Njk2IFogTTIwNy45ODUxMTcsMjExLjIgTDE2OC41MDc5MjgsMjExLjIgTDEwNS4xNzM3ODksNzguNjI0IEMxMDQuNjQ0NTYxLDc3LjUxMDQgMTAzLjUxNTU0MSw3Ni44IDEwMi4yNzc0NjksNzYuOCBMNzYuNDQ3OTQzLDc2LjggTDc2LjQ3NjgwOTksNDQuOCBMMTI3LjEwMzA2Niw0NC44IEwxOTAuMTQ1MzI4LDE3Ny4zNzI4IEMxOTAuNjc0NTU2LDE3OC40ODY0IDE5MS44MDM1NzUsMTc5LjIgMTkzLjA0MTY0NywxNzkuMiBMMjA3Ljk4NTExNywxNzkuMiBMMjA3Ljk4NTExNywyMTEuMiBaIE0yMTEuMTkyNTU4LDE3Mi44IEwxOTUuMDcxOTU4LDE3Mi44IEwxMzIuMDI5Njk2LDQwLjIyNzIgQzEzMS41MDA0NjgsMzkuMTEzNiAxMzAuMzcxNDQ5LDM4LjQgMTI5LjEzMDE2OSwzOC40IEw3My4yNzI1NzYsMzguNCBDNzEuNTA1Mjc1OCwzOC40IDcwLjA2ODM0MjEsMzkuODMwNCA3MC4wNjUxMzQ0LDQxLjU5NjggTDcwLjAyOTg1MjgsNzkuOTk2OCBDNzAuMDI5ODUyOCw4MC44NDggNzAuMzYzNDI2Niw4MS42NjA4IDcwLjk2OTYzMyw4Mi4yNjI0IEM3MS41Njk0MjQ2LDgyLjg2NCA3Mi4zODQxMTQ2LDgzLjIgNzMuMjM3Mjk0MSw4My4yIEwxMDAuMjUzNTczLDgzLjIgTDE2My41OTA5MiwyMTUuNzc2IEMxNjQuMTIzMzU1LDIxNi44ODk2IDE2NS4yNDU5NiwyMTcuNiAxNjYuNDg0MDMyLDIxNy42IEwyMTEuMTkyNTU4LDIxNy42IEMyMTIuOTY2Mjc0LDIxNy42IDIxNC40LDIxNi4xNjY0IDIxNC40LDIxNC40IEwyMTQuNCwxNzYgQzIxNC40LDE3NC4yMzM2IDIxMi45NjYyNzQsMTcyLjggMjExLjE5MjU1OCwxNzIuOCBMMjExLjE5MjU1OCwxNzIuOCBaIiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+CiAgICA8L2c+Cjwvc3ZnPg==",
3-
"multiValueHeaders": {
4-
"Content-Type": ["image/png"],
5-
"Content-Encoding": ["gzip"]
3+
"headers": {
4+
"Content-Type": "image/png"
65
},
76
"isBase64Encoded": true,
87
"statusCode": 200

0 commit comments

Comments
 (0)