In this article, we will create a serverless application using AWS Lambda, TypeScript, and the Serverless Framework. This application will have a routing structure similar to Next.js, where routes are defined in a routes
folder using TypeScript files. It will also support a _layout
approach for wrapping content in the same folder and in child folders. The application will be built using serverless-bundle
for efficiency.
npm install -g serverless
)In your terminal, run the following command to create a new Serverless service using the aws-nodejs-typescript
template:
serverless create --template aws-nodejs-typescript --path my-serverless-app
Change into the my-serverless-app
directory:
cd my-serverless-app
Run the following command to install the required dependencies:
npm install
serverless.yml
:Replace the contents of the serverless.yml
file with the following configuration:
service: my-serverless-app
frameworkVersion: '2'
provider:
name: aws
runtime: nodejs14.x
lambdaHashingVersion: 20201221
stage: ${opt:stage, 'dev'}
functions:
app:
handler: src/app.handler
events:
- http:
path: /{proxy+}
method: any
cors: true
plugins:
- serverless-bundle
- serverless-offline
custom:
bundle:
sourcemaps: false
caching: false
tsconfig: tsconfig.json
excludeDevDependencies: false
src/app.ts
:Create a new file named app.ts
in the src
directory with the following content:
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
function capitalizeFirstLetter(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function removeStagePrefix(path: string, stage: string): string {
if (path.startsWith(`/${stage}`)) {
return path.substring(stage.length + 1);
}
return path;
}
export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
const stage = event.requestContext.stage;
const originalPath = event.pathParameters?.proxy || '';
const routePath = removeStagePrefix(originalPath, stage);
const routeMethod = event.httpMethod.toLowerCase();
const capitalizedRouteMethod = capitalizeFirstLetter(routeMethod);
try {
const routeModule = await import(`./routes/${routePath}`);
const routeHandler = routeModule[`onRequest${capitalizedRouteMethod}`];
if (routeHandler) {
return await routeHandler(event);
} else {
throw new Error('No route handler found');
}
} catch (error) {
return {
statusCode: 404,
body: 'Not found',
};
}
};