AWS Lambda
AWS Lambda는 Amazon Web Services에서 제공하는 서버리스 플랫폼이다. 특정 이벤트에 반응해 코드를 실행할 수 있으며, 기본적인 컴퓨팅 리소스를 자동으로 관리한다.
Hono는 Node.js 18 이상의 환경에서 AWS Lambda와 함께 동작한다.
1. 설정
AWS Lambda에서 애플리케이션을 생성할 때, CDK를 사용하면 IAM Role, API Gateway 등의 함수를 설정하는 데 유용하다.
cdk CLI를 사용해 프로젝트를 초기화한다.
mkdir my-app
cd my-app
cdk init app -l typescript
npm i hono
mkdir lambda
touch lambda/index.tsmkdir my-app
cd my-app
cdk init app -l typescript
yarn add hono
mkdir lambda
touch lambda/index.tsmkdir my-app
cd my-app
cdk init app -l typescript
pnpm add hono
mkdir lambda
touch lambda/index.tsmkdir my-app
cd my-app
cdk init app -l typescript
bun add hono
mkdir lambda
touch lambda/index.ts2. Hello World
lambda/index.ts 파일을 수정한다.
import { Hono } from 'hono'
import { handle } from 'hono/aws-lambda'
const app = new Hono()
app.get('/', (c) => c.text('Hello Hono!'))
export const handler = handle(app)3. 배포
lib/cdk-stack.ts 파일을 수정한다.
import * as cdk from 'aws-cdk-lib'
import { Construct } from 'constructs'
import * as lambda from 'aws-cdk-lib/aws-lambda'
import * as apigw from 'aws-cdk-lib/aws-apigateway'
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'
export class MyAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props)
const fn = new NodejsFunction(this, 'lambda', {
entry: 'lambda/index.ts',
handler: 'handler',
runtime: lambda.Runtime.NODEJS_20_X,
})
fn.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE,
})
new apigw.LambdaRestApi(this, 'myapi', {
handler: fn,
})
}
}마지막으로 배포를 실행한다:
cdk deploy바이너리 데이터 제공
Hono는 바이너리 데이터를 응답으로 지원한다. Lambda 환경에서 바이너리 데이터를 반환하려면 base64 인코딩이 필요하다. Content-Type 헤더에 바이너리 타입을 설정하면 Hono가 자동으로 데이터를 base64로 인코딩한다.
app.get('/binary', async (c) => {
// ...
c.status(200)
c.header('Content-Type', 'image/png') // 바이너리 데이터를 의미
return c.body(buffer) // `ArrayBufferLike` 타입을 지원하며, base64로 인코딩됨
})AWS Lambda 객체 접근하기
Hono에서는 LambdaEvent와 LambdaContext 타입을 바인딩하고 c.env를 사용해 AWS Lambda 이벤트와 컨텍스트에 접근할 수 있다.
import { Hono } from 'hono'
import type { LambdaEvent, LambdaContext } from 'hono/aws-lambda'
import { handle } from 'hono/aws-lambda'
type Bindings = {
event: LambdaEvent
lambdaContext: LambdaContext
}
const app = new Hono<{ Bindings: Bindings }>()
app.get('/aws-lambda-info/', (c) => {
return c.json({
isBase64Encoded: c.env.event.isBase64Encoded,
awsRequestId: c.env.lambdaContext.awsRequestId,
})
})
export const handler = handle(app)RequestContext 접근하기
Hono에서는 LambdaEvent 타입을 바인딩하고 c.env.event.requestContext를 사용해 AWS Lambda의 요청 컨텍스트에 접근할 수 있다.
import { Hono } from 'hono'
import type { LambdaEvent } from 'hono/aws-lambda'
import { handle } from 'hono/aws-lambda'
type Bindings = {
event: LambdaEvent
}
const app = new Hono<{ Bindings: Bindings }>()
app.get('/custom-context/', (c) => {
const lambdaContext = c.env.event.requestContext
return c.json(lambdaContext)
})
export const handler = handle(app)v3.10.0 이전 (더 이상 사용되지 않음)
ApiGatewayRequestContext 타입을 바인딩하고 c.env를 사용해 AWS Lambda 요청 컨텍스트에 접근할 수 있다.
import { Hono } from 'hono'
import type { ApiGatewayRequestContext } from 'hono/aws-lambda'
import { handle } from 'hono/aws-lambda'
type Bindings = {
requestContext: ApiGatewayRequestContext
}
const app = new Hono<{ Bindings: Bindings }>()
app.get('/custom-context/', (c) => {
const lambdaContext = c.env.requestContext
return c.json(lambdaContext)
})
export const handler = handle(app)Lambda 응답 스트리밍
AWS Lambda의 호출 모드를 변경하면 스트리밍 응답을 구현할 수 있다.
fn.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE,
+ invokeMode: lambda.InvokeMode.RESPONSE_STREAM,
})일반적으로 구현 시 awslambda.streamifyResponse를 사용해 NodeJS.WritableStream에 청크를 기록해야 하지만, AWS Lambda Adaptor를 사용하면 handle 대신 streamHandle을 활용해 Hono의 전통적인 스트리밍 응답을 구현할 수 있다.
import { Hono } from 'hono'
import { streamHandle } from 'hono/aws-lambda'
const app = new Hono()
app.get('/stream', async (c) => {
return streamText(c, async (stream) => {
for (let i = 0; i < 3; i++) {
await stream.writeln(`${i}`)
await stream.sleep(1)
}
})
})
const handler = streamHandle(app)