Skip to content
All essays
CraftFebruary 25, 202510 min

Serverless Architecture: AWS Lambda and Beyond

Master serverless architecture. Build scalable apps without managing servers.

Ü
Ümit Uz
Mobile & Full Stack Developer

What is Serverless?

No server management, automatic scaling, pay-per-use.

Traditional:
- Provision servers
- Manage capacity
- Pay for idle time

Serverless:
- Deploy code
- Auto scaling
- Pay per execution

AWS Lambda

Function Code

javascript
// lambda/handler.js
export const handler = async (event) => {
  // Parse event
  const { body, pathParameters } = event;

  try {
    // Business logic
    const result = await processData(JSON.parse(body));

    return {
      statusCode: 200,
      body: JSON.stringify(result)
    };
  } catch (error) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error: error.message })
    };
  }
};

Serverless Framework

yaml
# serverless.yml
service: my-service

provider:
  name: aws
  runtime: nodejs18.x
  region: us-east-1
  environment:
    TABLE_NAME: ${self:service}-${sls:stage}

functions:
  createUser:
    handler: src/createUser.handler
    events:
      - http:
          path: /users
          method: post
    environment:
      TABLE_NAME: UsersTable

  getUser:
    handler: src/getUser.handler
    events:
      - http:
          path: /users/{id}
          method: get

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

Deploy

bash
# Install Serverless Framework
npm install -g serverless

# Deploy
serverless deploy

# Invoke function
serverless invoke -f createUser --data '{"name":"John"}'

# Logs
serverless logs -f createUser -t

DynamoDB Integration

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

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

const TABLE_NAME = process.env.TABLE_NAME;

export const handler = async (event) => {
  const { id } = event.pathParameters || {};

  switch (event.routeKey) {
    case 'GET /users/{id}':
      const getCommand = new GetCommand({
        TableName: TABLE_NAME,
        Key: { id }
      });
      const user = await docClient.send(getCommand);
      return { statusCode: 200, body: JSON.stringify(user.Item) };

    case 'POST /users':
      const body = JSON.parse(event.body);
      const putCommand = new PutCommand({
        TableName: TABLE_NAME,
        Item: { id: crypto.randomUUID(), ...body }
      });
      await docClient.send(putCommand);
      return { statusCode: 201, body: JSON.stringify({ success: true }) };
  }
};

API Gateway Integration

yaml
# API Gateway HTTP API
functions:
  api:
    handler: src/handler.handler
    events:
      - httpApi:
          path: /
          method: ANY
      - httpApi:
          path: /{proxy+}
          method: ANY

CI/CD Pipeline

yaml
# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Deploy to AWS
        run: |
          npm install -g serverless
          serverless deploy --stage prod
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

Best Practices

  1. 1Stateless: Functions should be stateless
  2. 2Idempotent: Same input = same output
  3. 3Small functions: Single responsibility
  4. 4Environment variables: Configuration
  5. 5Logging: CloudWatch Logs
  6. 6Monitoring: CloudWatch Metrics
  7. 7Cold starts: Keep functions warm
  8. 8Timeouts: Set appropriate timeouts

Pricing

AWS Lambda:
- $0.20 per 1M requests
- $0.0000166667 per GB-second

Example:
- 128MB, 1 second = $0.0000002083 per invocation
- 1M invocations = $0.21

Use Cases

  • Web APIs: REST and GraphQL
  • Data processing: ETL jobs
  • Webhooks: Handle events
  • Scheduled tasks: Cron jobs
  • Chatbots: Conversational AI
  • File processing: Image/video

Serverless = Less ops, more code!

Related essays

Next essay
Swift Programming: Modern iOS Development