English

Serverless architecture enables building scalable applications without managing infrastructure.

Vercel Edge Functions

// app/api/edge/route.ts
import { NextRequest, NextResponse } from 'next/server';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const name = searchParams.get('name') || 'World';

  return NextResponse.json({
    message: `Hello, ${name}!`,
    timestamp: new Date().toISOString(),
    region: process.env.VERCEL_REGION,
  });
}

AWS Lambda with API Gateway

// lambda/handler.ts
import { APIGatewayProxyHandler } from 'aws-lambda';

export const handler: APIGatewayProxyHandler = async (event) => {
  const { name = 'World' } = event.queryStringParameters || {};

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*',
    },
    body: JSON.stringify({
      message: `Hello, ${name}!`,
      timestamp: new Date().toISOString(),
    }),
  };
};

Serverless Framework

# serverless.yml
service: my-service

provider:
  name: aws
  runtime: nodejs20.x
  region: us-east-1
  environment:
    DATABASE_URL: ${env:DATABASE_URL}

functions:
  hello:
    handler: handler.hello
    events:
      - httpApi:
          path: /hello
          method: get

  createUser:
    handler: users.create
    events:
      - httpApi:
          path: /users
          method: post
    environment:
      TABLE_NAME: !Ref UsersTable

  processQueue:
    handler: queue.process
    events:
      - sqs:
          arn: !GetAtt ProcessQueue.Arn
          batchSize: 10

resources:
  Resources:
    UsersTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: users
        BillingMode: PAY_PER_REQUEST
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH

    ProcessQueue:
      Type: AWS::SQS::Queue
      Properties:
        QueueName: process-queue

DynamoDB Operations

import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import {
  DynamoDBDocumentClient,
  PutCommand,
  GetCommand,
  QueryCommand,
  UpdateCommand,
} from '@aws-sdk/lib-dynamodb';

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

// Create item
export async function createUser(user: User) {
  await docClient.send(
    new PutCommand({
      TableName: 'users',
      Item: {
        id: crypto.randomUUID(),
        ...user,
        createdAt: new Date().toISOString(),
      },
    })
  );
}

// Get item
export async function getUser(id: string) {
  const result = await docClient.send(
    new GetCommand({
      TableName: 'users',
      Key: { id },
    })
  );
  return result.Item;
}

// Query with index
export async function getUsersByEmail(email: string) {
  const result = await docClient.send(
    new QueryCommand({
      TableName: 'users',
      IndexName: 'email-index',
      KeyConditionExpression: 'email = :email',
      ExpressionAttributeValues: {
        ':email': email,
      },
    })
  );
  return result.Items;
}

S3 File Upload

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

const s3Client = new S3Client({});

export async function getUploadUrl(fileName: string) {
  const command = new PutObjectCommand({
    Bucket: process.env.BUCKET_NAME,
    Key: `uploads/${Date.now()}-${fileName}`,
    ContentType: 'image/jpeg',
  });

  const url = await getSignedUrl(s3Client, command, { expiresIn: 3600 });
  return url;
}

// Client-side upload
async function uploadFile(file: File) {
  const url = await fetch('/api/upload-url?name=' + file.name).then((r) =>
    r.json()
  );

  await fetch(url, {
    method: 'PUT',
    body: file,
    headers: {
      'Content-Type': file.type,
    },
  });
}

SQS Queue Processing

import { SQSHandler } from 'aws-lambda';

export const handler: SQSHandler = async (event) => {
  for (const record of event.Records) {
    const message = JSON.parse(record.body);

    try {
      await processMessage(message);
      console.log('Processed message:', message.id);
    } catch (error) {
      console.error('Failed to process:', error);
      throw error; // Message will be retried
    }
  }
};

async function processMessage(message: any) {
  // Process the message
  await sendEmail(message.email, message.content);
}

Step Functions State Machine

{
  "Comment": "Order processing workflow",
  "StartAt": "ValidateOrder",
  "States": {
    "ValidateOrder": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789:function:validate-order",
      "Next": "ProcessPayment",
      "Catch": [
        {
          "ErrorEquals": ["ValidationError"],
          "Next": "OrderFailed"
        }
      ]
    },
    "ProcessPayment": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789:function:process-payment",
      "Next": "FulfillOrder",
      "Retry": [
        {
          "ErrorEquals": ["PaymentError"],
          "MaxAttempts": 3,
          "BackoffRate": 2
        }
      ]
    },
    "FulfillOrder": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789:function:fulfill-order",
      "Next": "OrderComplete"
    },
    "OrderComplete": {
      "Type": "Succeed"
    },
    "OrderFailed": {
      "Type": "Fail",
      "Error": "OrderProcessingFailed"
    }
  }
}

Cold Start Optimization

// Initialization outside handler
import { PrismaClient } from '@prisma/client';

let prisma: PrismaClient;

export const handler = async (event) => {
  // Reuse connection across invocations
  if (!prisma) {
    prisma = new PrismaClient();
  }

  const users = await prisma.user.findMany();
  return { statusCode: 200, body: JSON.stringify(users) };
};

Event-Driven Architecture

// EventBridge pattern
import {
  EventBridgeClient,
  PutEventsCommand,
} from '@aws-sdk/client-eventbridge';

const client = new EventBridgeClient({});

export async function publishEvent(type: string, data: any) {
  await client.send(
    new PutEventsCommand({
      Entries: [
        {
          Source: 'my-app',
          DetailType: type,
          Detail: JSON.stringify(data),
          EventBusName: 'default',
        },
      ],
    })
  );
}

// Listener Lambda
export const handler = async (event: any) => {
  const { 'detail-type': type, detail } = event;

  if (type === 'UserCreated') {
    await sendWelcomeEmail(detail.email);
  }
};

Serverless architecture provides automatic scaling, pay-per-use pricing, and reduced operational overhead.

0
0
0
0