Building and Distributing NodeJS 12.x Express Serverless Application With Lyrid
Introduction
This is a series of tutorials that I will start building mainly focusing on showcasing how things work and how to build an application using Lyrid. This example specifically will show you how to deliver a standard NodeJS 12.x running Express Web Server as a Lyrid application.
Although these blogs are about our own technology, you will soon see that there is nothing in this platform that requires you to conform with a non-standard method of building an application. Everything you do here can still carry forward to writing an application on your own Virtual Machine. For instance, Docker Container, or Kubernetes.
Prerequisites
- A laptop or PC (Mac/Windows/Ubuntu don’t really matter)
- NodeJS 12.x or above installed: https://nodejs.org/en/download/
- npm: https://www.npmjs.com/get-npm
- Lyrid account: you can register here for free, no credit card required, along with Lyrid CLI downloaded.
- Git: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
- Any of your favorite IDE, I use Visual Studio Code in this example.
- Some HTTP testing tool (I will use Insomnia in this example, but either one works):
Postman: https://www.postman.com/downloads/ or
Insomnia: https://insomnia.rest/download/
Initial Setup
First you will need to register your Lyrid account:
And go through the 3 sections:
- Registration: https://docs.lyrid.io/docs/en/registration/
- Installation: https://docs.lyrid.io/docs/en/installation/
- Client Initialization: https://docs.lyrid.io/docs/en/initialization/
This whole guide assumes that you already registered with Lyrid, downloaded our command line client, and initialized the client with your access and secret key.
You will then need to clone the base project. For this example, it is hosted at GitHub:
git clone https://github.com/LyridInc/lyrid-expressjs.git
Local Build and Test
To run the sample locally, simply run these commands:
cd lyrid-expressjs
npm install
npm start
Simple…so far so good…lets dig into what we have in the code. This sample REST API is quite simple:
It contains a basic index.js where it will initialize an express web server application instance, and the function entry point (entry.js) will define how this instance is built along the routes. There’s a logging middleware (morgan: http://expressjs.com/en/resources/middleware/morgan.html) that logs every request for this application.
This service has two routes:
/echo/* : This endpoint will just echo all your request url, and method then prints it out as a text response. Test it with Insomnia by passing HTTP POST Method and /echo/hello_world request:
Looks good!
/sharp/ : We will get into this endpoint in the later portion of the tutorial.
Lyrid Definition File and Entry Point
Let’s explain a bit about this GitHub project example. The structure of the code is similar to our initial code when you run:
lc code init --name "$AppName" --module "$ModuleName" --function "$FunctionName" --language "nodejs12.x" --web "express"
Except in this case we already prefilled all those names and description.
A few things to explain in this template is the .lyrid-definition.yml file, and inside it there is an entry point called entry.js
Changing this definition file is not required, but it is crucial to explain how this file is being used by our platform.
The definition file contains descriptors that will be used in our platform to identify how the function will be built and packed. In this scenario, because it is an Express Project, our build will expect an express server instance application to be returned from the entry point (entry.js). The user has the flexibility to modify the entry point to include more routes and middleware inside the project, and our platform will take in the express server instance and wrap the instance for different types of serverless platforms.
The definition file determines how your function will be called inside our API Gateway.
NOTES: This is specific for our NodeJS 12.x Support. Our current support for NodeJS and Express is only for non-asynchronous function execution, and continues until the event loop is empty or the function times out. We will have support for asynchronous Promise based type of wrapper soon.
Public Cloud Deployment
Now your code is working locally, the next question is: how to make this API run on a publicly accessible endpoint?
Run our submission command from the folder that contains our definition file:
lc code submit
In this stage, your function will be zipped, and wrapped by our platform and the platform will perform a build to create a build artifact for all the public cloud serverless platforms that we support.
At the end of the submission, save the endpoint generated by the platform.
In this stage, we went through a standard serverless function build. This runs the pre-built installation using npm install and packages the function as an application.
Run the following command to monitor your build output:
lc monitor -c '*.build.*'
When your build is deployed to your default execution platform, your function is published and ready to use.
Public Cloud Execution
Now that your application is deployed, execute it using our endpoint. Remember the structure of our endpoint is currently:
This turns your endpoint to (if you didn’t change any names in the lyrid definition): https://api.lyrid.io/x/node/express/latest/entry/
When testing with HTTP client like Insomnia, remember to change the authorization to Basic on this tab and fill in your Lyrid access key as username and Lyrid secret key as the password:
Let’s execute this by clicking on the Send button:
Looks good! The app is now hosted inside our platform.
Similarly, you can also test out calling the application using cURL command like this (on Mac or Linux):
curl -u $LYRID_ACCESS:$LYRID_SECRET https://api.lyrid.io/x/node/express/latest/entry/echo/hello_world
Where $LYRID_ACCESS and $LYRID_SECRET corresponds to your access key and secret key.
You can monitor your LYR execution logs using our lc monitor function and filter for all LYR execution in your account:
lc monitor -c '*.execute.LYR'
Express Sharp Endpoint
The other endpoint that we have in this example is our implementation of an image processing that uses a high performance Node.js image processing called Sharp: https://sharp.pixelplumbing.com/
We take inspiration from this GitHub page: https://github.com/pmb0/express-sharp/tree/3.1.1
And made little modifications to the endpoint to be able to support any URL given to the function. The URL format is as follows:
/resize/:width/:height?format=$format&progressive=true&quality=90&crop=false&gravity=center&url=$image_url
Where:
- width: integer, the fixed width of the output image.
- height (optional): integer, the fixed height of the output image. If not provided, it will maintain the aspect ratio of the image.
- format (optional): string enum, valid values are one of the format supported by sharp: https://sharp.pixelplumbing.com/api-output#toformat. Default:
webp
if supported else, the output format of the requested image. - progressive (optional): boolean, only for jpeg and png. Use
&progressive=true
to enable progressive scan. - quality (optional): integer (1–100). quality is a Number between 1 and 100. Default if 80.
- crop (optional): boolean. Use
&crop=true
to enable the sharp cropping feature. Default is false. Note: Bothwidth
andheight
params are neccessary for crop to work. - gravity(optional): string enum. When the crop option is activated you can specify the gravity of the cropping. Possible attributes of the optional
gravity
arenorth
,northeast
,east
,southeast
,south
,southwest
,west
,northwest
,center
andcenter
. Default iscenter
; - url: string. URL to original image.
Lets test this function locally and look for a publicly accessible image URL at Imgur. I will use this one: https://i.imgur.com/3a0qwRe.jpeg
The original image has resolution of 701x701 pixel and 56KB in size.
Lets run though this image with a few different parameters locally first with base URL of http://localhost:3000/sharp and HTTP method of GET in your Insomnia Client:
GET /resize/250/150?crop=true&gravity=north&url=https://i.imgur.com/3a0qwRe.jpeg
GET /resize/500?format=webp&quality=25&url=https://i.imgur.com/3a0qwRe.jpeg
The cropped and resized imaged above is much less than the original image (4.9KB and 6.3KB). Change the endpoint with base URL to http://api.lyrid.io/x/node/express/latest/entry/sharp and add your Access Key and Secret just like the previous section, and test it again. You just hosted an image processing service that you can use to dynamically resize, crop and convert any publicly accessible image.
Sharp is a very complex image processing library, and unfortunately we will not dive further into the what it can/cannot do. We just want to show you in this blog that we are able to integrate complex libraries and package them into a simple API using Lyrid.
Conclusion
In this tutorial, we want to show a basic use-case of our platform. Hopefully, this has given something that can be easily followed and to show how our platform works. More of these upcoming tutorial series will touch on examples that:
- Connects to a Database
- Connects to a Storage
- More Middlewares: CORS, JWT Authentication, etc2.
- Seamlessly moves your application to another public cloud (AWS or GCP) while maintaining the same endpoint.
Notice in this whole process, apart from our command line client, you did not even touch or download any library, framework, or tool to make this work on a different cloud provider. This follows our philosophy of “Only Focus on Your Code — BUT It Still Should Be Able to Run Anywhere”. We are abstracting anything that is not related to your code (the build, distribution and execution).
Along with NodeJS 12.x + ExpressJS, the same flow can be done with our support for:
- Django + Python 3.8
- Flask + Python 3.8
- Gin + Golang 1.x
- ASP.NET + .NET Core 3.1
- And more upcoming support
And with that, you can register a Free Lyrid account to get started with this following link and try these all yourself:
Lastly, please do not be shy to contact me at hsutanto@lyrid.io or join our Slack channel to say hi and let us know if there are any issues for you following this example.
Thank you for reading and stay safe!
Handoyo