[Serverless] Refactoring: Using Ports and Adapters pattern to refactor code
The original code:
createGroup.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | import { v4 as uuidv4 } from "uuid" ; import "source-map-support/register" ; import * as AWS from "aws-sdk" ; import { APIGatewayProxyEvent, APIGatewayProxyHandler, APIGatewayProxyResult, } from "aws-lambda" ; import { getUserId } from "../../auth/utils" ; const docClient = new AWS.DynamoDB.DocumentClient(); const groupTables = process.env.GROUPS_TABLE; export const handler: APIGatewayProxyHandler = async ( event: APIGatewayProxyEvent ): Promise<APIGatewayProxyResult> => { console.log( "Processing event: " , event); const itemId = uuidv4(); const parsedBody = JSON.parse(event.body); const authorization = event.headers.Authorization; const splits = authorization.split( " " ); const jwtToken = splits[1]; const newItem = { id: itemId, userId: getUserId(jwtToken), ...parsedBody, }; await docClient .put({ TableName: groupTables, Item: newItem, }) .promise(); return { statusCode: 201, headers: { "Access-Control-Allow-Origin" : "*" , }, body: JSON.stringify({ newItem, }), }; }; |
getGroups.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import * as AWS from "aws-sdk" ; import { APIGatewayProxyEvent, APIGatewayProxyHandler, APIGatewayProxyResult, } from "aws-lambda" ; const docClient = new AWS.DynamoDB.DocumentClient(); const groupTables = process.env.GROUPS_TABLE; export const handler: APIGatewayProxyHandler = async ( event: APIGatewayProxyEvent ): Promise<APIGatewayProxyResult> => { console.log( "Processing event: " , event); const result = await docClient .scan({ TableName: groupTables, }) .promise(); const items = result.Items; return { statusCode: 200, headers: { "Access-Control-Allow-Origin" : "*" , }, body: JSON.stringify({ items, }), }; }; |
Tow entry functions both contains busniess logic code and data access code (dynamoDB).
What we want is:
Entry function --> Busniess logic code --> Data access layer
First, create interfaces for both Reqest & Model:
requests/CreateGroupRequest.ts:
export interface CreateGroupRequest { name: string; description: string; }
models/Group.ts:
export interface Group { id: string; name: string; description: string; userId: string; }
Then create data access layer code, it mainly handle all the dynamoDB operations.
dataAccess/groupAccess.ts:
import * as AWS from "aws-sdk"; import { DocumentClient } from "aws-sdk/clients/dynamodb"; import {Group} from '../models/Group' export class GroupAccess { constructor( private readonly docClient: DocumentClient = new AWS.DynamoDB.DocumentClient(), private readonly groupsTable = process.env.GROUPS_TABLE ) { } async getAllGroups(): Promise<Group[]> { console.log('Getting all groups'); const result = await this.docClient.scan({ TableName: this.groupsTable, }).promise() const items = result.Items; return items as Group[]; } async createGroup(group: Group): Promise<Group> { console.log('Creating a group with id', group.id) await this.docClient.put({ TableName: this.groupsTable, Item: group }).promise(); return group; } }
Then create busniessLogic layer, it mainly talk to data access layer and passing and returning the data.
busniessLogic/groups.ts:
import * as uuid from "uuid"; import { Group } from "../models/Group"; import { GroupAccess } from "../dataAccess/groupAccess"; import { CreateGroupRequest } from "../requests/CreateGroupRequest"; import { getUserId } from "../auth/utils"; const groupAccess = new GroupAccess(); export async function getAllGroups(): Promise<Group[]> { return groupAccess.getAllGroups(); } export async function createGroup( createGroupRequest: CreateGroupRequest, jwtToken: string ) { const itemId = uuid.v4(); const userId = getUserId(jwtToken); return await groupAccess.createGroup({ id: itemId, userId: userId, name: createGroupRequest.name, description: createGroupRequest.description, }); }
Lastly, entry function will just talk to busniess layer code:
createGroup.ts:
import "source-map-support/register"; import { APIGatewayProxyEvent, APIGatewayProxyHandler, APIGatewayProxyResult, } from "aws-lambda"; import { createGroup } from "../../busniessLogic/groups"; import { CreateGroupRequest } from "../../requests/CreateGroupRequest"; export const handler: APIGatewayProxyHandler = async ( event: APIGatewayProxyEvent ): Promise<APIGatewayProxyResult> => { console.log("Processing event: ", event); const newGroup: CreateGroupRequest = JSON.parse(event.body); const authorization = event.headers.Authorization; const splits = authorization.split(" "); const jwtToken = splits[1]; const newItem = await createGroup(newGroup, jwtToken); return { statusCode: 201, headers: { "Access-Control-Allow-Origin": "*", }, body: JSON.stringify({ newItem, }), }; };
getGroups.ts:
import { APIGatewayProxyEvent, APIGatewayProxyHandler, APIGatewayProxyResult, } from "aws-lambda"; import { getAllGroups } from "src/busniessLogic/groups"; export const handler: APIGatewayProxyHandler = async ( event: APIGatewayProxyEvent ): Promise<APIGatewayProxyResult> => { console.log("Processing event: ", event); const items = await getAllGroups(); return { statusCode: 200, headers: { "Access-Control-Allow-Origin": "*", }, body: JSON.stringify({ items, }), }; };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2016-05-27 [RxJS] Transformation operators: delay and delayWhen
2016-05-27 [RxJS] Transformation operator: buffer, bufferCount, bufferTime
2016-05-27 [RxJS] Transformation operator: scan
2016-05-27 [PWA] Keynote: Progressive Web Apps across all frameworks
2016-05-27 [PWA] Add web app to your Home Screen