In this section, you will deploy the backend infrastructure for the Serverless Student Management System. This includes:
┌─────────────────────────────────────────────────────────────┐
│ Frontend (React/Amplify) │
└────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ API Gateway (REST) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ /students (GET, POST, PUT, DELETE) │ │
│ │ /students/{id} (GET, PUT, DELETE) │ │
│ │ /auth (POST) - Login/Register │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Lambda │ │ Lambda │ │ Lambda │
│ CRUD │ │ Auth │ │ Admin │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└────────────────┼────────────────┘
│
▼
┌────────────────────────────────┐
│ DynamoDB Table │
│ ┌──────────────────────────┐ │
│ │ PK: studentId │ │
│ │ SK: timestamp │ │
│ │ Attributes: name, email, │ │
│ │ grade, etc. │ │
│ └──────────────────────────┘ │
└────────────────────────────────┘
Before deploying CDK stacks, bootstrap your AWS account:
# Bootstrap CDK
cdk bootstrap aws://ACCOUNT_ID/REGION
# Example:
cdk bootstrap aws://123456789012/us-east-1
// lib/stacks/database-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
export class DatabaseStack extends cdk.Stack {
public readonly table: dynamodb.Table;
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
this.table = new dynamodb.Table(this, 'StudentTable', {
partitionKey: { name: 'studentId', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'timestamp', type: dynamodb.AttributeType.NUMBER },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
// Add GSI for querying by email
this.table.addGlobalSecondaryIndex({
indexName: 'emailIndex',
partitionKey: { name: 'email', type: dynamodb.AttributeType.STRING },
projectionType: dynamodb.ProjectionType.ALL,
});
}
}
// lib/stacks/auth-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as cognito from 'aws-cdk-lib/aws-cognito';
export class AuthStack extends cdk.Stack {
public readonly userPool: cognito.UserPool;
public readonly userPoolClient: cognito.UserPoolClient;
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
this.userPool = new cognito.UserPool(this, 'StudentUserPool', {
userPoolName: 'student-management-pool',
selfSignUpEnabled: true,
autoVerifiedAttributes: [cognito.UserPoolAttribute.EMAIL],
passwordPolicy: {
minLength: 8,
requireLowercase: true,
requireUppercase: true,
requireDigits: true,
requireSymbols: false,
},
});
this.userPoolClient = this.userPool.addClient('StudentAppClient', {
clientName: 'student-app-client',
generateSecret: false,
authFlows: {
userPassword: true,
userSrp: true,
},
});
}
}
// lib/stacks/backend-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
export class BackendStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Create Lambda function for CRUD operations
const crudFunction = new lambda.Function(this, 'CrudFunction', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda/crud'),
environment: {
TABLE_NAME: 'StudentTable',
},
});
// Create API Gateway
const api = new apigateway.RestApi(this, 'StudentApi', {
restApiName: 'Student Management API',
});
// Add resources and methods
const students = api.root.addResource('students');
students.addMethod('GET', new apigateway.LambdaIntegration(crudFunction));
students.addMethod('POST', new apigateway.LambdaIntegration(crudFunction));
const student = students.addResource('{id}');
student.addMethod('GET', new apigateway.LambdaIntegration(crudFunction));
student.addMethod('PUT', new apigateway.LambdaIntegration(crudFunction));
student.addMethod('DELETE', new apigateway.LambdaIntegration(crudFunction));
}
}
# Deploy all stacks
cdk deploy
# Or deploy specific stack
cdk deploy DatabaseStack
cdk deploy AuthStack
cdk deploy BackendStack
# Check deployed stacks
aws cloudformation list-stacks --region us-east-1
# Check DynamoDB table
aws dynamodb describe-table --table-name StudentTable --region us-east-1
# Check Lambda functions
aws lambda list-functions --region us-east-1
# Check API Gateway
aws apigateway get-rest-apis --region us-east-1
// lambda/crud/index.ts
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, GetCommand, PutCommand, QueryCommand, UpdateCommand, DeleteCommand } from '@aws-sdk/lib-dynamodb';
const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);
export const handler = async (event: any) => {
const method = event.httpMethod;
const path = event.path;
try {
if (method === 'GET' && path === '/students') {
return await getAllStudents();
} else if (method === 'POST' && path === '/students') {
return await createStudent(JSON.parse(event.body));
} else if (method === 'GET' && path.includes('/students/')) {
const id = path.split('/')[2];
return await getStudent(id);
} else if (method === 'PUT' && path.includes('/students/')) {
const id = path.split('/')[2];
return await updateStudent(id, JSON.parse(event.body));
} else if (method === 'DELETE' && path.includes('/students/')) {
const id = path.split('/')[2];
return await deleteStudent(id);
}
} catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: 'Internal server error' }),
};
}
};
async function getAllStudents() {
const result = await docClient.send(new QueryCommand({
TableName: process.env.TABLE_NAME,
KeyConditionExpression: 'studentId = :id',
ExpressionAttributeValues: {
':id': 'STUDENT',
},
}));
return {
statusCode: 200,
body: JSON.stringify(result.Items),
};
}
async function createStudent(data: any) {
const studentId = `STUDENT#${Date.now()}`;
await docClient.send(new PutCommand({
TableName: process.env.TABLE_NAME,
Item: {
studentId,
timestamp: Date.now(),
...data,
},
}));
return {
statusCode: 201,
body: JSON.stringify({ id: studentId }),
};
}
// Implement other CRUD operations...
Issue: CDK bootstrap failed
# Check AWS credentials
aws sts get-caller-identity
# Try bootstrap again with explicit credentials
cdk bootstrap aws://ACCOUNT_ID/REGION --profile your-profile
Issue: Lambda function not found
# Check Lambda function code path
ls -la lambda/crud/
# Ensure index.ts is compiled to index.js
npm run build
Issue: DynamoDB table not created
# Check CloudFormation stack status
aws cloudformation describe-stacks --stack-name DatabaseStack
# Check stack events for errors
aws cloudformation describe-stack-events --stack-name DatabaseStack
Once the backend is deployed, proceed to Frontend Development to build and deploy the frontend application.