Running a Serverless Lumen REST API on AWS Lambda

Running a Serverless Lumen REST API on AWS LambdaPietro IglioBlockedUnblockFollowFollowingJan 12In this post I’ll go through the process of setting up a Lumen-powered API running as an AWS Lambda function.

I’ll use the latest Lambda extension to support custom runtimes, so that the Lambda is pure PHP without the need of a NodeJS proxy.

Lumen is a “micro-framework”, meaning it’s a smaller, faster, leaner version of Laravel, which is the full web application framework.

Lumen has the same foundation as Laravel, but it is built for microservices.

AWS Lambda is a service that lets you run code without provisioning or managing servers.

AWS Lambda executes your code only when needed and scales automatically, from a few requests per day to thousands per second.

Although Lambda does not support PHP natively, it has been recently extended to support AWS Lambda runtime API and layers capabilities.

Because of this, it is possible to build a native PHP runtime for Lambda functions.

In this post, I’ll show you how to build a PHP runtime to start powering your PHP applications on AWS Lambda and how to create a simple serverless Lumen REST API that queries an AWS RDS Postgresql database instance.

AWS API Gateway is intercepting REST requests from the external world and routing them to AWS Lambda functions, as shown in the following diagram:Throughout the rest of this article I am assuming that you are familiar with basic AWS and Lumen concepts.

Part I: PHP RuntimeFirst of all, you need a PHP runtime that is suitable for running a Lumen API.

Once you have created your runtime, you are going to reuse it for all APIs.

You can build a runtime completely from scratch, as explained here.

However, I decided to start from the Stackery PHP Lambda Layer.

Up to now, the Stackery layer does not support mbstring and PDO, which are requirements for Lumen 5.

7.

So, I forked the original Stackery repository to make my own version.

You have two options here:use a pre-built PHP runtime that I have created;build the PHP runtime using Docker.

1.

Use a pre-built runtimeJust download the zip file from this link on your local disk.

2.

Build the PHP runtimeYou can skip this step if you decided to download the pre-build runtime.

You need to install Docker first.

Git is required as well.

If you are running on a Windows workstation, it is recommended to turn off CR/LF, otherwise your bash scripts won’t work:git config –global core.

autocrlf falseMake sure the Docker daemon is running.

Clone the repository and run “make”:git clone https://github.

com/code-runner-2017/php-lambda-layer.

gitcd php-lambda-layermakeIf no error occurs, a file named php71.

zip is created.

This is the same file that you can download from the previously supplied link.

For Windows users using GIT Bash: if you need the Make utility, download it here .

Unzip it and copy the make.

exe file to the following directory:C:Program FilesGitmingw64inCreating a new LayerYou have either downloaded or built the new PHP runtime.

Now you need to upload the php71.

zip package in your AWS account.

Log into AWS, click on “Services”, and choose “Lambda”.

Click on “Levels” on the left menu and click on the “Create Level” button on the right.

Enter the layer name (eg.

MyPHPLayer), a description (eg.

“Stackery PHP runtime with mbstring support”) and upload the zip package.

Write down the Version ARN, that is used to identify your runtime.

For example:arn:aws:lambda:eu-west-1:5320652344506:layer:php7_1-stackery_mbstring:1You have now fhe first part.

You have your PHP runtime and you are ready to deploy a Lumen REST API.

Part II: Creating the Sample Lumen REST APII have prepared an example Git repository that you can use as a starter template:git clone https://github.

com/code-runner-2017/lambda-lumen-test.

gitcd lambda-lumen-test/src/php/lumencomposer updateYou have to edit the template.

yaml file and paste the Version ARN in the Layer: !Subsection.

You can also change other parameters such as Memory, Timeout, etc.

You can edit the php.

ini file to enable/disable the PHP modules that you need.

For instance, if you want to try the provided example that runs a query against an RDS database, your php.

ini should have the following extensions enabled:extension=curl.

soextension=json.

soextension=mbstring.

soextension=pdo.

soextension=pdo_pgsql.

soThe src/php/lumen contains a regular Lumen 5.

7 project.

In addition:the composer.

json file already contains the AWS SDK, as it is very likely that your Lambda is going to interact with the rest of the AWS ecosystem (DynamoDB, S3, …).

If you don’t need it, you can remove that entry.

I have configured Monolog to not write on the file system, as the Lambda function would fail.

You must create your own .

env file copying the .

env.

example file.

It is important that you have this configuration in it: LOG_CHANNEL=errorlogI have created two test REST endpoints:/hello that returns “hello world!”;/test that returns a JSON object.

You can optionally pass a name parameter on the URL (eg.

 ?name=Pietro).

It will be returned in the JSON response, just to test that you can read URL params.

You can test locally before you create the Lambda function:# Run this from the lambda-lumen-test/src/php/lumen folderphp -S localhost:8000 -t publicTry to open thehttp://localhost:8000/hello URL to check that it works.

You can edit the routes/web.

php file to create your own endpoints.

Creating the AWS LambdaNow you are ready to upload your API to AWS to create the Lambda function.

You need the following command line tools:the latest version of AWS CLI (Windows users can download it here)AWS SAM (available here)I am not going through the details of installing and configuring AWS CLI and SAM.

I assume that you are familiar with them and that you have already configured AWS CLI with your account credentials.

Create an S3 bucket “yourbucketname”, choosing any name you like.

Now you are ready to package and deploy the Lambda function:$ sam package — template-file template.

yaml — output-template-file serverless-output.

yaml — s3-bucket yourbucketname$ sam deploy –template-file serverless-output.

yaml –stack-name my-first-serverless-lumen-api –capabilities CAPABILITY_IAMReplace yourbucketname with the name of your S3 bucket.

Testing the AWS LambdaLog into your AWS console again and select “Services” > “Lambda” > “Functions”.

Click on “my-first-serverless-lumen-api”, then click on “API Gateway” in the Designer view.

AWS Lambda DesignerOnce you click on “API Gateway”, the API Endpoint section appears in the lower part of the above figure.

It should be something like this:https://ua12345ai.

execute-api.

eu-west-1.

amazonaws.

com/Prod/{proxy+}Open that endpoint in your browser (or use curl, if you wish to use the command line).

Replace {proxy+} with “hello” and yourhostname with the value of your API Endpoint:https://yourhostname/Prod/helloIf that works, you should get a “Hello world!” response from Lumen.

Next StepsNow you are ready to use the whole AWS ecosystem.

For example, you can use services such as:DynamoDB (NoSQL)ElastiCache (Redis/Memcache)ElasticSearchAuroraand so on.

Covering the benefits of AWS services is not within the scope of this post.

Most of these services are serverless, like the Lambda service.

This means that they automatically scale and you are charged in a pay-per-use model.

Therefore, you can setup an API that can serve a huge amount of requests without setting up a cluster of servers.

Querying an RDS Postgresql instanceFinally, we are going to query an RDS Postgresql instance following the Lumen guidelines for database access.

This example can be easily adapted to use an RDS MySQL or Aurora instance type.

First, create a public RDS Postgresql instance and write down the database host, name, user, and password.

Connect to the DBMS using your favourite SQL client to create a “users” table and insert a record in it:CREATE TABLE users ( user_id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, login_name VARCHAR(64) NOT NULL, email VARCHAR(64) NOT NULL ) insert into users (login_name, email) values (‘pietro.

iglio’, ‘igliop@gmail.

com’);The PHP code to query the database is already included in the sample routes/web.

php file:$router->get('/testdb', function (Request $request) use ($router) { $users = app('db')->select("SELECT * FROM users"); return response()->json($users);});As you can see, the database name, host and credentials are taken from the environment.

You might add them to your .

env file, but I recommend setting them as Lambda Environment variables.

So, log into your AWS console again and select “Services” > “Lambda” > “Functions”.

Click on “my-first-serverless-lumen-api” to open the Lambda page.

Click again on the Lambda function in the Designer.

If you scroll down in the page, you will find a section where you can insert your environment variables.

Set the DB_CONNECTION=pgsql, and DB_HOST, DB_DATABASE, DB_USER and DB_PASSWORD variables according to your RDS configuration.

Now you are ready to invoke the REST endpoint:https://yourhostname/Prod/testdbThe output should be something like:[ { "user_id": 1, "login_name": "pietro.

iglio", "email": "igliop@gmail.

com" }]Done!Final ConsiderationsIn this example, we have created a public instance of the RDS database.

You should be aware that this is not considered best practice from a security point of view.

However, if you create the RDS database in a VPC, as recommended, you need to run the Lambda function in the VPC as well.

This method has several drawbacks.

For example, it increases to about 10 seconds the boot time for cold starts.

In addition, if you query your database from the Lambda function, you need to take into account that Lambda can quickly scale, so your database might receive hundreds of connections.

A serverless database would be much better for this scenario.

In future posts, I’ll explain how to use AWS serverless services from the Lumen API, so stay tuned.

I hope you found this article helpful!.

. More details

Leave a Reply