-
Notifications
You must be signed in to change notification settings - Fork 5
/
api-gateway-v2.ts
109 lines (89 loc) · 2.71 KB
/
api-gateway-v2.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import type {
APIGatewayProxyEventHeaders,
APIGatewayProxyEventV2,
APIGatewayProxyStructuredResultV2
} from 'aws-lambda'
import { readableStreamToString } from '@remix-run/node'
import { isBinaryType } from '../binaryTypes'
import { RemixAdapter } from './index'
function createRemixRequest(event: APIGatewayProxyEventV2): Request {
const host = event.headers['x-forwarded-host'] || event.headers.host
const search = event.rawQueryString.length ? `?${event.rawQueryString}` : ''
const scheme = event.headers['x-forwarded-proto'] || 'http'
const url = new URL(event.rawPath + search, `${scheme}://${host}`)
const isFormData = event.headers['content-type']?.includes(
'multipart/form-data'
)
return new Request(url.href, {
method: event.requestContext.http.method,
headers: createRemixHeaders(event.headers, event.cookies),
body:
event.body && event.isBase64Encoded
? isFormData
? Buffer.from(event.body, 'base64')
: Buffer.from(event.body, 'base64').toString()
: event.body,
})
}
function createRemixHeaders(
requestHeaders: APIGatewayProxyEventHeaders,
requestCookies?: string[]
): Headers {
const headers = new Headers()
for (const [header, value] of Object.entries(requestHeaders)) {
if (value) {
headers.append(header, value)
}
}
if (requestCookies) {
headers.append('Cookie', requestCookies.join('; '))
}
return headers
}
async function sendRemixResponse(
nodeResponse: Response
): Promise<APIGatewayProxyStructuredResultV2> {
const cookies: string[] = []
// AWS API Gateway will send back set-cookies outside of response headers.
for (const [key, values] of Object.entries(nodeResponse.headers.raw())) {
if (key.toLowerCase() === 'set-cookie') {
for (const value of values) {
cookies.push(value)
}
}
}
if (cookies.length) {
nodeResponse.headers.delete('Set-Cookie')
}
const contentType = nodeResponse.headers.get('Content-Type')
const isBase64Encoded = isBinaryType(contentType)
let body: string | undefined
if (nodeResponse.body) {
if (isBase64Encoded) {
body = await readableStreamToString(nodeResponse.body, 'base64')
} else {
body = await nodeResponse.text()
}
}
return {
statusCode: nodeResponse.status,
headers: Object.fromEntries(nodeResponse.headers.entries()),
cookies,
body,
isBase64Encoded,
}
}
type ApiGatewayV2Adapter = RemixAdapter<APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2>
const apiGatewayV2Adapter: ApiGatewayV2Adapter = {
createRemixRequest,
sendRemixResponse
}
export {
createRemixRequest,
createRemixHeaders,
sendRemixResponse,
apiGatewayV2Adapter
}
export type {
ApiGatewayV2Adapter
}