Введение в Serverless функции на TypeScript с AWS Lambda
Serverless-архитектура стала стандартом современной облачной разработки. AWS Lambda позволяет запускать код без управления серверами, а TypeScript добавляет строгую типизацию и удобство разработки. В этой статье мы разберем весь процесс: от создания первой функции до деплоя в продакшен. Вы узнаете, как писать эффективные serverless функции на TypeScript, работать с триггерами и обрабатывать ошибки.
Serverless-функции идеально подходят для микросервисов, обработки событий, вебхуков и фоновых задач. TypeScript делает код безопаснее и предсказуемее, что критически важно для production-решений.
1. Настройка окружения для AWS Lambda на TypeScript
Перед началом работы установите необходимые инструменты. Вам понадобятся Node.js (версия 18+), npm и AWS CLI.
1.1. Установка зависимостей
npm init -y
npm install -D typescript @types/node @aws-sdk/client-lambda
npm install aws-lambda @types/aws-lambda
1.2. Конфигурация TypeScript
Создайте файл tsconfig.json с настройками для Lambda:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
1.3. Установка AWS CLI
Скачайте и настройте AWS CLI из официального источника. После установки выполните:
aws configure
Введите ваш Access Key ID, Secret Access Key, регион (например, us-east-1) и формат вывода (json).
2. Создание первой serverless функции на TypeScript
Структура проекта должна выглядеть так:
my-lambda-project/
├── src/
│ └── handler.ts
├── dist/
├── tsconfig.json
├── package.json
└── .gitignore
2.1. Базовый обработчик Lambda
Создайте файл src/handler.ts с простой функцией:
import { Context, APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
interface HelloResponse {
message: string;
timestamp: string;
eventType: string;
}
export const handler = async (
event: APIGatewayProxyEvent,
context: Context
): Promise<APIGatewayProxyResult> => {
console.log('Event:', JSON.stringify(event, null, 2));
console.log('Context:', context);
const response: HelloResponse = {
message: 'Hello from AWS Lambda with TypeScript!',
timestamp: new Date().toISOString(),
eventType: event.httpMethod || 'UNKNOWN'
};
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(response)
};
};
2.2. Компиляция TypeScript
Добавьте скрипты в package.json:
"scripts": {
"build": "tsc",
"watch": "tsc --watch",
"clean": "rm -rf dist"
}
Выполните сборку:
npm run build
Проверьте, что в папке dist появился файл handler.js.
3. Деплой Lambda функции на AWS
Есть несколько способов деплоя. Рассмотрим самый простой — через AWS CLI.
3.1. Упаковка функции
Создайте ZIP-архив с кодом:
cd dist
zip -r ../function.zip .
cd ..
3.2. Создание Lambda функции
Выполните команду AWS CLI:
aws lambda create-function \
--function-name hello-typescript \
--runtime nodejs18.x \
--role arn:aws:iam::YOUR_ACCOUNT_ID:role/lambda-execution-role \
--handler handler.handler \
--zip-file fileb://function.zip
Замените YOUR_ACCOUNT_ID на ваш ID аккаунта и lambda-execution-role на существующую роль с базовыми правами Lambda.
3.3. Тестирование функции
Вызовите функцию через AWS CLI:
aws lambda invoke \
--function-name hello-typescript \
--payload '{"httpMethod": "GET"}' \
response.json
cat response.json
Вы должны увидеть JSON-ответ с сообщением и timestamp.
4. Продвинутые техники и лучшие практики
Для production-решений используйте следующие подходы.
4.1. Обработка ошибок
Создайте кастомный класс ошибок:
export class ValidationError extends Error {
constructor(message: string, public statusCode: number = 400) {
super(message);
this.name = 'ValidationError';
}
}
export const errorHandler = (error: unknown): APIGatewayProxyResult => {
if (error instanceof ValidationError) {
return {
statusCode: error.statusCode,
body: JSON.stringify({ error: error.message })
};
}
console.error('Unhandled error:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: 'Internal server error' })
};
};
4.2. Работа с переменными окружения
Используйте process.env для конфигурации:
const config = {
tableName: process.env.TABLE_NAME || 'default-table',
region: process.env.AWS_REGION || 'us-east-1',
logLevel: process.env.LOG_LEVEL || 'info'
};
export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
console.log(`Using table: ${config.tableName} in ${config.region}`);
// ... логика функции
};
4.3. Кэширование соединений
Инициализируйте клиенты вне обработчика для повторного использования:
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
const client = new DynamoDBClient({ region: process.env.AWS_REG