How to Write Your Own Serverless Framework Plugin for AWS Lambda using JavaScript
Time to read: 8 minutes
The Serverless framework makes it easy to deploy applications to AWS Lambda. However, Serverless does not currently support binary files, but we can solve this issue by implementing a Serverless plugin and uploading proper configuration to the AWS API Gateway.
In this post we will:
- Set up an npm project and create a Hello World application with a fancy image background
- Configure the Serverless framework and deploy this app on AWS Lambda
- Learn how to use AWS SDK by recreating serverless plugin for binary support in AWS API Gateway
- Publish plugin in the npm repository
To accomplish tasks in this post you will need:
- AWS account
- Npm account
- Node.js and npm installed
- AWS CLI installed
Set up environment & Hello World!
Let’s create our app. Set up the npm project and install dependencies:
Create our app:
Inside dist/app.js
we will:
- Initialize express application
- Set views extension and catalog
- Add mapping to the homepage (‘/’)
To do that paste this code to the dist/app.js
file:
Next, add our view. Paste this code to the dist/views/index.html
file:
Here comes time for making some fancy decoration with CSS. Paste this styles to the dist/assets/css/main.css
file:
As you can see we are using the image as a background for our app. You can get it here and save it in the dist/assets/img
directory as sandbox.gif:
It is fancy. Isn’t it?
We are ready to put some code to our “localhost-entry” file, local.js
:
We need only to add proper scripts in the package.json
file:
And we can launch our app on the localhost:
The output from this command you should see:
After reaching the given url in your browser, you should see:
Ok! App is ready. Let’s go forward now and deploy it on AWS Lambda. What we need to do now is add two files:
Inside lambda.js
add code for the AWS Lambda function:
In the serverless.yml
add following configuration:
Now we need only to add one more script inside package.json
:
And we can deploy the app:
Output from this command should be:
After reaching provided URL you can see your app deployed on AWS Lambda.
But…hey…my awesome background image is missing!
That is because of lack of support for binary files in our API Gateway, but we can solve it with our plugin.
If you want to catch up this step:
Add support for binary files in API Gateway
We can use the AWS console to solve the problem manually. After login to console, choose ‘API Gateway’ from the “Services” menu under “Application Services”, and click on your API (make sure that you are in proper AWS region):
From the left navigation pane choose Binary support
:
As you can see there is no type listed here. Let’s add our image type: click on edit
button, then on add binary media type
in the input type image/gif
and click save
:
After this (and each other) change in API Gateway you need to redeploy it:
Let’s try to reload our page again. And…
Still not working, an image is not visible, what is going on? No worries, let’s check it with some REST testing tool (ie Postman):
What the hell?! Ok, easy. There is a one ‘small’ issue in AWS API Gateway. Update your request with header ‘Accept’ and value ‘image/gif’. Boom! Now it’s working:
But.. Browser doesn’t send Accept
header. What now? There is a workaround for that. To make API Gateway send binary files as a response to every request (without expecting Accept
header), you need to specify at least one mime type as a wildcard */*
. You can read more about this issue here:
https://github.com/awslabs/serverless-application-model/issues/145#issuecomment-311672573
As it is written in the issue now all our binary data is sent in base64-encoded form, so we need to encode it on the server side. Change lambda.js
file to:
Now our application will work correctly. Deploy it again (npm run deploy) and check given URL.
If you want to catch up this step:
git clone https://github.com/maciejtreder/serverless-apigw-binary.git
cd serverless-apigw-binary
git checkout tutorialSecondStep
npm install
npm run deploy
Create Serverless plugin
We have our application ready and working. But we can’t stop at this moment. We use Serverless to automate the deployment process. Login to AWS console and set up binary support manually is definitely not that what we are looking for. Let’s create a plugin which will customize binary types for us, during deployment.
We will keep everything in one repo, in two catalogs example/express
(here the app will be kept) and plugin
.
Move our app to subcatalog:
Create the main file for our plugin and initialize npm project:
We need to make one important change in the package.json
file. Ensure that “main” field value is src/index.js
(the exact path to our plugin entry point). Your plugin package.json
should look like (more or less) this:
We can start writing plugin now. Specify the main class for it and proper constructor (in src/index.js
file):
Let’s try to use our plugin with the app:
Add a plugin in your Serverless configuration. Paste this to the serverless.yml
:
And take a look if our ‘Hello world!’ message is displayed to the console:
We should see the output:
Hooray! Let’s go forward. What we are going to do now is move our message to the method and bind it to the ‘after:deploy:deploy’ hook (hooks are described by convention ::, so our hook means: after users run command deploy
deploy afterDeploy method). This is how ../../plugin/src/index.js
file should look like after those changes:
Execute of deploy should give following output:
Ok. Plugin works, hook works. Now let’s connect to the AWS using their SDK and make proper changes in just-deployed API. At the beginning, we will specify mime-types in the serverless.yml
file (the convention is custom -> pluginName -> values):
Retrieve them in the plugin constructor (../../plugin/src/index.js)
:
Additional data which we need to collect are the provider used by the client and the stage to which we are deploying:
The next step is to add a getApiId
method to our BinarySupport
class. For that we will use describeStacks
method from AWS SDK. We can reuse the request
method from the serverless.provider
class, because of some nice logic attached to it, such as support for different AWS profiles and retries of requests in case of error.
As a parameter we need to pass a name of the class from AWS SDK (CloudFormation
), a method which we want to invoke (describeStacks
) and a payload which we want to pass to it:
Let’s try it. Update your afterDeploy
method with following code:
For next step we need url of our just deployed API. It is hidden under Outputs: [Array]
. Let’s print it out. Make change in the afterDeploy
method inside plugin/src/index.js
:
If you will invoke npm run deploy
(from the example/express directory) again. You should get this lines as an output:
We have now full information about the just-deployed stack. The most important thing for us is inside Outputs
array. We have there our ServiceEndpoint
which contains API ID in it. Let’s filter out this output and retrieve that id:
What we are going to do now is put our binaryTypes into this API. We will provide changes in the Swagger format, so let’s prepare it inside our hook method – afterDeploy()
. Add following code at the beginning of afterDeploy()
method:
As you can see, inside the JSON body of our swaggerInput
constant we are providing information about the swagger format version, the title of our API (if we won’t add this, AWS will override our API name with the default value), and x-amazon-apigateway-binary-media-types
to which we are passing an array of strings representing mime-types provided by the serverless.yml
configuration file.
Let’s implement a getApiGatewayName
method inside our BinarySupport
class:
Ok. We have an API ID and name collected; we can make changes to it now. To do that we are going to use the putRestApi
method from the AWS SDK, and pass information about changes which we want to perform:
We are going to chain all added methods in the after:deploy:deploy
hook. Let’s update it:
We are ready to test our plugin now. To make sure that we don’t have old deployments, remove them:
Now we are going to deploy application again, log in to AWS console and take a look at Binary Support
section. Yay! The app is there! Binary types are there! Let’s navigate to it. Oh.. an issue, again. The beautiful picture is missing..
The reason is simple. Do you remember that we were redeploying the API after any changes made in it? That’s what we forgot to do with our Serverless plugin. Let’s add that step:
Now we can deploy our app and be happy because it is working correctly and deployment process is fully automated!
If you want to catch up this step:
Let’s go public
Ok. We have our plugin ready. It is working perfectly. What now? Now we are going to make our plugin available to the world!
We have several ways to do that.
Node Package Manager (npm)
It’s really simple. You need to do two things.
Login to your npm account via npm CLI:
And publish package:
More interesting (in my opinion) is Git deployment. Why? It gives you the possibility to make your package available to only people which you want to use it (ie. team in your company).
The only thing which you need to do is just push your code to the repo:
After that, if you want to install the package in your project you need to provide your git repo address ie:
npm install https://github.com/maciejtreder/serverless-apigw-binary.git
Next steps
In the previous post, we learned how to use Serverless framework. Today we created Serverless plugin using the AWS SDK to compensate for the lack of default support for binary files. Now we are ready to make use of this knowledge and make something awesome. In next post, we will create and deploy Angular 4 application and deploy it on the AWS Lambda!
Live demo of app used in this post can be found here: https://serverless-apigw.maciejtreder.com
Plugin git repo: https://github.com/maciejtreder/serverless-apigw-binary
Plugin npm repo: https://www.npmjs.com/package/serverless-apigw-binary
Maciej Treder,
contact@maciejtreder.com
https://www.maciejtreder.com
@maciejtreder (GitHub, Twitter, StackOverflow, LinkedIn)
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.