Testing serverless code with serverless
Testing serverless code with serverless
Recently, I was assigned a task, to figure out how to run serverless code in local environment. I actually seldom code for the most of my time, and my knowledge of running an app is with command like node app.js
or python main.py
, and the interpreter will stay there, listening for connection on some random port, then I would use curl
or something to reach endpoint. But that’s not how serverless worked.
What is serverless?
When we talk about “serverless”, we must also mention AWS Lambda, AWS Lambda
is something called “serverless computing”.
Before we explain what is “serverless computing”, let’s think how we deploy our code.
Usually we have some code, whether it’s Python
or PHP
, then we need to use some kind of program to “serve” our code, like php-fpm
or uWSGI
, things like that. Then we would need a web server, to proxy client’s connection to the program, so the request can reach our code, then our code can respond to that request.
Now, imagine a service, that you only need to provide your code, select the environment, then the service will take care “everythig”, spawning instance, running your code, providing endpoint, auto-scaling…and much more. Isn’t it terrific? Developer won’t need to worry about failing servers, they can focus on their code.
This is basically “serverless computing”. You provide your code, then someone run that code for you, maintain the server for you, scale your app for you.
AWS Lambda
is the first cloud platform that provides serverless computing, and people started noticing this concept. It’s easier to deploy small-sized code, and it’s easy to use. AWS Lambda
can also be used with AWS API Gateway
, so you can control your application API.
How serverless work?
“serverless” would require you to provide your code, then select your environment, right? For most of the serverless service, or so called FaaS (function as a service)
out there, this is how they manage your code.
- Select the base container image using the environment you chosed.
- Insert the code you provided into the image, then create a new image.
- Spawn multiple container with new image, then enable a port or socket, so the code inside the container can communicate with outside.
- Some kind of load balancer will create a new route to those containers, and you get an endpoint, which can reach your code via services they created.
There’s a major difference between deploying code the old fashion way and using serverless computing. Serverless computing is stateless, since you don’t know when or why the service provider is going to shut down the container, or generate a new container, or even route your request to different container.
Serverless example
Below is a sample code, which can be deployed on FaaS platform.
1 | ; |
Now here comes the question, if I want to test this code, how can I run it locally?
You can’t run this code directly, it would terminate as soon as it starts, since there are no request to the code. The only way to test it is to deploy the code and test on the cloud, or is it?
Enter the application serverless
What is serverless, again
serverless
is a framework written in Node.js
. Just like it’s name, it’s very helpful when developing serverless code. It can help you build, test and deploy your code, all in one package.
You need to write serverless.yml
, it’s config file, in this file you can define the function, set up deployment, and much more.
Now let’s say we want to run the code above in local environment, how can we do that?
First, install serverless
with npm install serverless -g
. Then save the YAML config below as serverless.yml
1 | service: 'serverless-sample' |
Now, we can use the command below to trigger this function.
1 | $ serverless invoke local -f hello |
You should see output like this
1 | { |
If you have read the code above, you should notice something called event
, this is the variable where client can pass it’s request into the function. For the code above, you can pass a data with variable name
to change the output. Let’s give it a shot.
1 | $ serverless invoke local -f hello -d '{"name": "John"}' |
1 | { |
Now, the invoke local
command is really convenient, but I would want to have a HTTP endpoint instead of triggering the function via command-line, how can I do that?
serverless-offline
serverless-offline
is a plugin for serverless
, it can emulate an AWS Lambda
and AWS API Gateway
envioronment locally, so you can test your code just like using AWS services
.
Install the package with npm install serverless-offline
, then add code below into serverless.yml
1 | plugins: |
You can use serverless --verbose
to verify if serverless-offline
plugin is loaded or not.
After adding the line, now you should be able to test you code using HTTP endpoint, just run
1 | $ serverless offline |
You should see output like
1 | offline: Starting Offline: dev/us-east-1. |
Now, try to reach HTTP endpoint using cURL
1 | $ curl -X POST -H 'content-type: application/json' http://localhost:3000/dev/hello |
Then you can see the result
1 | {"message":"Hello World!"} |
Now try to reach HTTP endpoint with data using cURL
1 | $ curl -X POST -H 'content-type: application/json' -d '{"name": "John"}' http://localhost:3000/dev/hello |
The name didn’t change! Why?
After some digging, I found that when you’re emulating AWS
environment locally, it would also emulate a feature called Lambda Proxy
. It’s a feature that would pass more information into your code. For example, if I send {"name": "John"}
as data with Lambda Proxy
off, the code would receive {"name": "John"}
, but if Lambda Proxy
is enabled, it would receive…
1 | { |
and the data would be in event.body
, so if you want to test your code locally using HTTP endpoint, you need to modify your code to use event.data
instead of using event
directly.
The new code should look like this
1 | ; |
Now test the code using serverless offline
again, with data, you should see the correct result.
It’s easy, right?