Deploying a Symfony Application to AWS Lambda

First, let’s understand what a serverless architecture is and when is it needed.

Serverless architecture allows you to execute snippets of code without the hassle of infrastructure: in this case, the cloud provider handles the management of the web server, physical hardware and administration, allowing you to focus solely on the code.

AWS Lambda provides high availability and you are billed only for the actual compute time spent. This service can be very useful for such tasks as starting cron jobs, sending notifications in real time, providing API access, handling some events when performing various operations, etc. You can find a lot of examples of using the service on the web. …

Our use case

Provide access to an API built with Symfonywhich posts messages to LinkedIn… The development process will include the stages from writing to deploying the code.

Writing the code

Symfony version 5 has a new component called Notifier, which makes it possible to send notifications through different services (Slack, Twitter, Twilio and etc.).

Symfony has no built-in support LinkedIn, so a few months ago I created a gateway on top of Notifier for publishing content on this social network. The source code of the gateway can be viewed link, we will use it in this demo as well.

Let’s get started

$ symfony new --full aws-lambda-linkedin-notifier
$ cd aws-lambda-linkedin-notifier
$ composer require eniams/linkedin-notifier

Turn on the gateway (see documentation)

<?php
// config/bundles.php
return [
// others bundles,
EniamsNotifierLinkedInLinkedInNotifierBundle::class => ['all' => true]];
// .env
LINKEDIN_DSN=

Content publishing logic


<?php

class PostContentController
{
    /**
     * @Route("/contents", name="post_content", methods="POST")
     */
    public function __invoke(NotifierInterface $notifier, Request $request)
    {
        if(null !== $message = (json_decode($request->getContent(), true)['message'] ?? null)) {
            $notifier->send(new Notification($message, ['chat/linkedin']));
            return new JsonResponse('message posted with success', 201);
        }

        throw new BadRequestException('Missing "message" in body');
    }
}

The logic is simple: we provide API access via a route /contentswhich accepts a POST request with a message message in his body.

On line 11, we send the post to LinkedIn – thanks to Symfony and the gateway, this is very easy!

As a professional developer, let’s cover this code with autotests:


<?php
class PostContentControllerTest extends WebTestCase
    /**
     * @dataProvider methodProvider
     */
    public function testANoPostRequestShouldReturnA405(string $method)
    {
        $client = static::createClient();

        $client->request($method, '/contents');

        self::assertEquals(405, $client->getResponse()->getStatusCode());
    }

    public function testAPostRequestWithoutAMessageInBodyShouldReturnA400()
    {
        $client = static::createClient();

        $client->request('POST', '/contents');

        self::assertEquals(400, $client->getResponse()->getStatusCode());
    }

    public function testAPostRequestWithAMessageInBodyShouldReturnA201()
    {
        $request = new Request([],[],[],[],[],[], json_encode(['message' => 'Hello World']));

        $notifier = new class implements NotifierInterface {
            public function send(Notification $notification, Recipient ...$recipients): void
            {
            }
        };

        $controller = new PostContentController();
        $response = $controller->__invoke($notifier, $request);

        self::assertEquals(201, $response->getStatusCode());
    }

    public function methodProvider()
    {
        return [
            ['GET'],
            ['PUT'],
            ['DELETE'],
        ];
    }
view rawTestPostContentController.php hosted with ​ by GitHub

The code is ready! It’s time to turn it around

Stop! What?! AWS Lambda does not support PHP!

That’s right: AWS Lambda does not support all programming languages, but only a few, including Go, Java, Python, Ruby, NodeJS and .NET

Now you need to learn a new language and rewrite the code? I hope not!

No need to rewrite anything thanks to Matthieu Nappoli, the creator Bref.sh, and a great team helping him maintain this project is open source

Bref allows you to deploy PHP applications to AWS and run them on AWS Lambda

Deployment configuration

Let’s add log processing to kernel.php:

<?php
    // Kernel.php
    public function getLogDir(): string
    {
        if (getenv('LAMBDA_TASK_ROOT') !== false) {
            return '/tmp/log/';
        }

        return parent::getLogDir();
    }

    public function getCacheDir()
    {
        if (getenv('LAMBDA_TASK_ROOT') !== false) {
            return '/tmp/cache/'.$this->environment;
        }

        return parent::getCacheDir();
    }

Let’s prepare the Serverless framework (see documentation):

$ npm install -g serverless
$ serverless config credentials --provider aws --key  --secret
$ composer require bref/bref

Let’s set the configuration in the serverless.yaml file:

service: notifier-linkedin-api

provider:
    name: aws
    region: eu-west-3
    runtime: provided
    environment: # env vars
        APP_ENV: prod
        LINKEDIN_DSN: YOUR_DSN


plugins:
    - ./vendor/bref/bref

functions:
    website:
        handler: public/index.php # bootstrap 
        layers:
            - ${bref:layer.php-73-fpm} # https://bref.sh/docs/runtimes/index.html#usage 
        timeout: 28 # Timeout to stop the compute time
        events:
            - http: 'POST /contents' # Only POST to /contents are allowed

package:
    exclude:
        - 'tests/**'
view rawserverless.yaml hosted with ​ by GitHub

We are deploying!

$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service notifier-linkedin-api.zip file to S3 (10.05 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
....................
Serverless: Stack update finished...
Service Information
service: notifier-linkedin-api
stage: dev
region: eu-west-3
stack: notifier-linkedin-api-dev
resources: 15
api keys:
  None
endpoints:
  POST - https://xxx.execute-api.eu-west-3.amazonaws.com/dev/contents
functions:
  website: notifier-linkedin-api-dev-website
layers:
  None
Serverless: Removing old service artifacts from S3...
Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.

Our code is now deployed to AWS Lambda and the API is available at https://xxx.execute-api.eu-west-3.amazonaws.com/dev/contents

Let’s try:


The translation of the material was prepared as part of the course “Symfony Framework”… If you are interested in learning more about the course, we invite you to Open Day online, where the teacher will talk about the format and training program.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *