In the last post I built a PHP capable sample project for the Serverless Framework. In this post, I’ll show a concrete use of it.
The service I’m building connects runs a PHP function for pretty-printing chess games from the lichess online chess server. James Clarke has written a PHP function to do this using fpdf17.
The lichess exporter takes the game id of any game that has been played on the lichess server and produced a PDF output. Take for example, Game 8 of the current World Championship which is here. When I open the resulting file, I see this:
In this blog post I’ll describe how I turned this into a serverless service. The goal is to create:
- Add an endpoint which takes the game id as a parameter
- Run the PHP function via an AWS lambda function
- Return the result as a stream
Prerequisites
First check everything we need is installed.
$ serverless --version
1.2.1
$ node --version
v7.1.0
Initial setup
$ mkdir serverless-lichess-to-pdf
$ cd serverless-lichess-to-pdf
$ sls install --url https://github.com/ZeroSharp/serverless-php
Next copy in the source from https://github.com/clarkerubber/lichessPDFExporter.
You can check it works by running the following.
$ php main.php COQChpzH > COQChpzH.pdf
What’s going on here? The php binary (from the serverless-php project) is running main.php (from the lichess-pdf-exporter project) with argument COQChpzH
(which corresponds to a chess game on the lichess server. The main.php function downloads the game from the lichess API and passes it through the fpdf17 library to create a pdf stream which is written out to the COQChpzH.pdf
file.
Lessons learned
I learned a few things while trying to get this project working. The basic plan is to modify handler.js so that it return the output of the call described above. Turns out there are quite a few gotchas along the way.
Lesson 1 - Defining a path parameter
I want my API to look like this:
http://.../serverless-lichess-to-pdf/export/{gameid}
I could not find an example in the serverless docs for getting a parameter that is passed in the URL.
Turns out your serverless.yml
file should look like this:
1 2 3 4 5 6 7 |
|
Then, in your handler.js you can retrieve the parameter with:
1 2 3 4 |
|
Lesson 2 - API Gateway does not support binary data
I was hoping I could just do something like this:
1 2 3 4 5 6 7 8 |
|
At present, you cannot return a binary file. Amazon have just (November 2016) released support for binary types in API Gateway but it’s currently an open issue in the Serverless Framework.
Lesson 3 - You can redirect the response to an S3 bucket
So instead of returning the binary output, I can write the output to an S3 bucket and return a 302 redirection to the S3 resource. Like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Lesson 4 - You can automatically delete S3 objects after a number of days
Each S3 bucket has optional lifecycle rules where you can specify that files are automatically removed after a time period. I wanted to set this up within the serverless.yml
resources section, but the syntax for the lifecycle rules were not very obvious and I could not find any examples online. The following seems to work:
1 2 3 4 5 6 7 8 9 10 11 |
|
It’s all working now
You can check it out by visiting this link.
I also wrote a Chrome extension which injects the link into the lichess page.