xp-forge / lambda-ws
AWS Lambda Webservices for the XP Framework
Requires
- php: >=7.0.0
- xp-forge/lambda: ^5.0
- xp-forge/web: ^4.0 | ^3.0
- xp-framework/core: ^12.0 | ^11.0 | ^10.0
Requires (Dev)
- xp-framework/test: ^2.0 | ^1.0
README
Run XP web applications on AWS lambda using API Gateway or Lambda Function URLs. Unlike other implementations, this library does not spawn PHP-FPM but runs requests directly, resulting in an overhead of less than 1ms.
Example
Put this code in a file called Greet.class.php:
use com\amazon\aws\lambda\HttpIntegration; class Greet extends HttpIntegration { /** * Returns routes * * @param web.Environment $env * @return web.Application|web.Routing|[:var] */ public function routes($env) { return ['/' => function($req, $res) { $greeting= sprintf( 'Hello %s from PHP %s on stage %s @ %s', $req->param('name') ?? $req->header('User-Agent') ?? 'Guest', PHP_VERSION, $req->value('request')->stage, $req->value('context')->region ); $res->answer(200); $res->send($greeting, 'text/plain'); }]; } }
The request context is passed into a request value named request and contains a RequestContext instance. The lambda context is passed in context.
To run existing web applications, return an instance of your web.Application
subclass from the routes() method.
Development & testing
To run the HTTP APIs locally, this library integrates with xp-forge/web via a wrapper:
$ xp web lambda Greet @xp.web.srv.Standalone(HTTP @ peer.ServerSocket(Resource id #124 -> tcp://127.0.0.1:8080)) Serving prod:Lambda<Greet>[] > web.logging.ToConsole ════════════════════════════════════════════════════════════════════════ > Server started: http://localhost:8080 in 0.057 seconds Sat, 18 Nov 2023 12:19:32 +0100 - PID 18668; press Ctrl+C to exit # ...
By adding -m develop
, these can be run in the development webserver.
Setup and deployment
Follow the steps shown on the xp-forge/lambda README to create the runtime layer, the service role and the lambda function itself. Next, create the function URL as follows:
$ aws lambda create-function-url-config \ --function-name greet \ --auth-type NONE \ --invoke-mode RESPONSE_STREAM
The URL will be returned by this command.
Invocation
You can either open the HTTP endpoint in your browser or by using curl:
$ curl -i https://XXXXXXXXXX.lambda-url.eu-central-1.on.aws/?name=$USER Date: Sun, 18 Jun 2023 20:00:55 GMT Content-Type: text/plain Transfer-Encoding: chunked Connection: keep-alive x-amzn-RequestId: 3505bbff-e39e-42d3-98d7-9827fb3eb093 x-amzn-Remapped-content-length: 59 Set-Cookie: visited=1687118455; SameSite=Lax; HttpOnly X-Amzn-Trace-Id: root=1-648f6276-672c96fe6230795d23453441;sampled=0;lineage=83e616e2:0 Hello timmf from PHP 8.2.7 on stage $default @ eu-central-1
Deploying changes
After having initially created your lambda, you can update its code as follows:
$ xp lambda package Greet.class.php $ aws lambda update-function-code \ --function-name greet \ --zip-file fileb://./function.zip \ --publish
Streaming
This library implements HTTP response streaming as announced by AWS in April 2023, improving TTFB and memory consumption of web applications. Response streaming is available for lambda function URLs which have their invoke mode set to RESPONSE_STREAM.
Inherit from the HttpStreaming base class instead of HttpApi:
use com\amazon\aws\lambda\HttpStreaming; class Greet extends HttpStreaming { public function routes($env) { /* Shortened for brevity */ } }
Next, deploy the change, then update the function configuration:
$ aws lambda update-function-url-config --function-name greet --invoke-mode RESPONSE_STREAM
Request context
The request context passed via the request value is defined as follows:
public class com.amazon.aws.lambda.RequestContext implements lang.Value { public string $accountId public string $apiId public string $domainName public string $domainPrefix public string $requestId public string $routeKey public string $stage public util.Date $time public [:string] $http public function __construct(array $context) public function toString(): string public function hashCode(): string public function compareTo(var $value): int }