
The difficulty we encountered
The main factor is pricing. EC2 severs result in higher expenses compared to utilizing serverless technology. The cost is significant higher when utilizing EC2 Servers compared to accessing a Lambda function in AWS. For our requirements, there is no need for server to run the application so we decided to switch to serverless. Let's dive how we achieved this.
Wacky widgets to whip up before launching into your wild rumpus
- Basic understanding of GraphQL
- Basic understanding of Prisma ORM
- AWS account
- Database and URL that your application can use to access data
- Node JS install
Mandatory plugins that must be installed
- @prisma/client 4.8.1
- serverless 3.26.0
- serverless-appsync-plugins 1.14.0
- serverless-webpack-prisma 1.1.1
- serverless-webpack 5.11.0
- webpack 5.75.0
- webpack-node-externals 3.0.0
Letβs start the battle

Donβt skip any steps between also please use same versions used below
Serverless setup
First, you need to set up your AWS account credentials in your IDE, but you can skip this step if you have already done so. Next, you will need to install the serverless plugin in your project. Finally, you will run the specified command for a serverless template project, which will create the project for you. These simple steps will help you get started quickly and easily with a serverless template project.
serverless create --template aws-nodejs
Then, open the serverless.yml file. In this file, you will define the basics of your application, such as the region where it will be deployed, the stage it will be in, and any global configuration variables you may have. These configurations are done in the provider section of the file.
service: everify-api frameworkVersion: "3" package: individually: true excludeDevDependencies: false patterns: - '!node_modules/.prisma/client/libquery_engine-*' - 'node_modules/.prisma/client/libquery_engine-rhel-*' - '!node_modules/prisma/libquery_engine-*' - '!node_modules/@prisma/engines/**' # Plugins that are used has to be mentioned here. plugins: - serverless-appsync-plugin - serverless-webpack - serverless-webpack-prisma provider: name: aws runtime: nodejs16.x # you can overwrite defaults here stage: ${opt:stage, 'dev'} region: ${opt:region, self:custom.default.region} memorySize: 1024 timeout: 120 logs: restApi: true iamRoleStatements: - Effect: Allow Action: - lambda:InvokeFunction - ses:SendEmail - sns:* Resource: "*" - Effect: "Allow" Action: - s3:* Resource: arn:aws:s3:::demo.${self:provider.stage}/* #-- versionFunctions: False environment: SERVICE_NAME: ${self:service} STAGE: ${self:provider.stage} DB_NAME: ${self:custom.default.mysql_db} DB_USER: ${self:custom.default.mysql_user} DB_PASSWORD: ${self:custom.default.mysql_password} DB_HOST: ${self:custom.default.mysql_host} custom: splitStacks: custom: src/utils/stack-map.js default: ${file(./src/config/config.${self:provider.stage}.json):default} stages: - dev - uat - demo appSync: schema: serviceRole: "AppSyncServiceRole-${self:provider.stage}" authenticationType: "API_KEY" apiKeys: - name: api key //your api key name description: api key expires: 1y logConfig: loggingRoleArn: { Fn::GetAtt: [AppSyncLoggingServiceRole, Arn] } level: ALL mappingTemplates: ${file(mappingTemplates.yml)} dataSources: - type: AWS_LAMBDA name: Lambda description: "Lambda DataSource" config: functionName: graphql serviceRoleArn: { Fn::GetAtt: [AppSyncServiceRole, Arn] } webpack: includeModules: true resources: Resources: # AppSync logging role AppSyncLoggingServiceRole: Type: "AWS::IAM::Role" Properties: RoleName: "Logging-${self:custom.appSync.serviceRole}" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "appsync.amazonaws.com" Action: - "sts:AssumeRole" Policies: - PolicyName: "Logging-${self:custom.appSync.serviceRole}-Policy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: - "*" # AppSync lambda role AppSyncServiceRole: Type: "AWS::IAM::Role" Properties: RoleName: "Lambda-${self:custom.appSync.serviceRole}" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "appsync.amazonaws.com" Action: - "sts:AssumeRole" Policies: - PolicyName: "Lambda-${self:custom.appSync.serviceRole}-Policy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - "lambda:InvokeFunction" Resource: - "arn:aws:lambda:${self:provider.region}:*:function:${self:service}-${self:provider.stage}-graphql" - "arn:aws:lambda:${self:provider.region}:*:function:${self:service}-${self:provider.stage}-graphql:*" functions: graphql: handler: src/graphQL/graphqlHandler.graphql events: - http: path: graphql method: any cors: origin: "*" headers: - Authorization
Deploy your serverless project
serverless deploy
Verifying the success of your deployment can be done by checking the presence of your function in both AWS Lambda and AWS AppSync.
Halfway there! We're getting closer to having our serverless project up and running! Just keep chugging along! πͺ
Create graphQL functions
- Define your GraphQL schema in a file named schema.graphql. This will serve as a blueprint for your API and help guide the development process
- Create a file named mappingTemplates.yml. This file will map the functions in your GraphQL schema to specific implementations in your code
- In the src folder, create a new file to contain the function definitions. This file will be where you write the code to handle each GraphQL function and make sure it operates as expected.
Serverless.yml
Add new function in serverless.yml file and setup file path
Create Handler for graphql function
Create a resolver file in the same location specified in the serverless.yml file. This file will contain your graphql functions and their corresponding function definition. A switch statement can be utilized to handle all graphql functions
Mapping templates
- dataSource: Lambda type: Query field: getHello request: "request/getHello-req-mt.vtl" response: "common-response.vtl"
Add the following block of code in mapping templates
The 'field' referred to below refers to your GraphQL function name. Afterwards, make a new file in the directory specified in the request and include the code mentioned below.
{ "version": "2018-05-29", "operation": "Invoke", "payload": { "field": "getHello", "arguments": $utils.toJson($context.arguments), "request": $utils.toJson($context.request.headers) } }
Ensure that your field values are accurate in each function and that each GraphQL function has its own distinct file within the folder. Then, create a common-response.vtl file and include the specified code.
$util.toJson($ctx.result)
Function definition file
Define your function and test the response in AWS AppSync

Prisma setup
Open terminal and run,
npx prisma init
This process will result in the creation of a prisma folder, containing the schema.prisma file, and the client can be generated by executing the designated command
generator client { provider = "prisma-client-js" binaryTargets = ["native", "rhel-openssl-1.0.x"] }
Then you will need to add your database details in the datasource object. Then, you can define your Prisma models below that. Finally, run the command to generate the Prisma client, and you'll be ready to start accessing your data
npx prisma generate
We are almost there π
Webpack-config file
Add new file in root of your project, webpack.config.js and add the below code then save and deploy your project again.
/* eslint-disable @typescript-eslint/no-var-requires */ const path = require('path') const nodeExternals = require('webpack-node-externals') const slsw = require('serverless-webpack') const { isLocal } = slsw.lib.webpack module.exports = { target: 'node', stats: 'normal', entry: slsw.lib.entries, externals: [nodeExternals()], mode: isLocal ? 'development' : 'production', optimization: { concatenateModules: false }, resolve: { extensions: ['.js'] }, output: { libraryTarget: 'commonjs', filename: '[name].js', path: path.resolve(__dirname, '.webpack'), }, }
ππ Woo hoo! We've reached the finish line of our wild and crazy serverless journey! We've done it all, from configuring our AWS account to mapping our graphql functions. We've even added a little humor along the way. High fives all around! π