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 executionAWS 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_REQUESTDeploy
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 -tDynamoDB 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: ANYCI/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
- 1Stateless: Functions should be stateless
- 2Idempotent: Same input = same output
- 3Small functions: Single responsibility
- 4Environment variables: Configuration
- 5Logging: CloudWatch Logs
- 6Monitoring: CloudWatch Metrics
- 7Cold starts: Keep functions warm
- 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.21Use 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!