Building Serverless Applications with AWS

3 min read

Building Serverless Applications with AWS

Learn how to build scalable and cost-effective serverless applications using AWS Lambda, API Gateway, and other AWS services.

Lambda Functions

Create efficient Lambda functions:

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

const dynamodb = new DynamoDB.DocumentClient();

export const handler: APIGatewayProxyHandler = async (event) => {
  try {
    const { id } = event.pathParameters || {};
    
    const result = await dynamodb.get({
      TableName: process.env.TABLE_NAME!,
      Key: { id }
    }).promise();

    return {
      statusCode: 200,
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(result.Item)
    };
  } catch (error) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error: 'Internal server error' })
    };
  }
};

API Gateway Configuration

Set up API Gateway with Lambda:

# serverless.yml
service: my-serverless-api

provider:
  name: aws
  runtime: nodejs18.x
  stage: ${opt:stage, 'dev'}
  region: ${opt:region, 'us-east-1'}

functions:
  getItem:
    handler: handler.handler
    events:
      - http:
          path: /items/{id}
          method: get
          cors: true
    environment:
      TABLE_NAME: ${self:service}-${self:provider.stage}-items

DynamoDB Integration

Set up DynamoDB tables:

resources:
  Resources:
    ItemsTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:service}-${self:provider.stage}-items
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH
        BillingMode: PAY_PER_REQUEST

S3 Integration

Handle file uploads:

import { S3 } from 'aws-sdk';

const s3 = new S3();

export const uploadHandler: APIGatewayProxyHandler = async (event) => {
  const { file, type } = JSON.parse(event.body || '{}');
  const buffer = Buffer.from(file, 'base64');
  
  const params = {
    Bucket: process.env.BUCKET_NAME!,
    Key: `uploads/${Date.now()}-${type}`,
    Body: buffer,
    ContentType: type,
    ACL: 'public-read'
  };

  try {
    const result = await s3.upload(params).promise();
    return {
      statusCode: 200,
      body: JSON.stringify({ url: result.Location })
    };
  } catch (error) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error: 'Upload failed' })
    };
  }
};

SQS Integration

Handle asynchronous processing:

export const queueHandler: SQSHandler = async (event) => {
  for (const record of event.Records) {
    try {
      const body = JSON.parse(record.body);
      await processMessage(body);
    } catch (error) {
      console.error('Processing error:', error);
      throw error; // Retry handling
    }
  }
};

// serverless.yml
functions:
  processQueue:
    handler: handler.queueHandler
    events:
      - sqs:
          arn: !GetAtt ProcessingQueue.Arn
          batchSize: 10

CloudWatch Monitoring

Set up monitoring:

functions:
  api:
    handler: handler.handler
    events:
      - http:
          path: /api
          method: post
    alarms:
      - name: errors
        metric: Errors
        threshold: 1
        period: 60
        evaluationPeriods: 1
        comparisonOperator: GreaterThanThreshold

Best Practices

  1. Use proper error handling
  2. Implement proper logging
  3. Use environment variables
  4. Implement proper security
  5. Use proper monitoring
  6. Optimize cold starts
  7. Use proper IAM roles

Conclusion

Serverless architecture on AWS provides a powerful way to build scalable applications. Focus on proper service integration and monitoring to build reliable systems.