| CARVIEW |
wai-handler-hal: Wrap WAI applications to run on AWS Lambda
This library provides a function Network.Wai.Handler.Hal.run to
lift a wai Network.Wai.Application into a function that can be
passed to hal's AWS.Lambda.Runtime.mRuntime. This allows you to
run applications written in mature web frameworks (e.g., servant)
on AWS Lambda, as proxy integrations of API Gateway REST APIs.
More details, including deployment advice, are available in the
repository's README.md.
[Skip to Readme]
Downloads
- wai-handler-hal-0.5.0.0.tar.gz [browse] (Cabal source package)
- Package description (as included in the package)
Maintainer's Corner
For package maintainers and hackage trustees
Candidates
- No Candidates
| Versions [RSS] | 0.1.0.0, 0.1.1.0, 0.1.2.0, 0.2.0.0, 0.3.0.0, 0.4.0.0, 0.4.0.1, 0.4.0.2, 0.5.0.0 (info) |
|---|---|
| Change log | CHANGELOG.md |
| Dependencies | base (>=4.12 && <4.22), base64-bytestring (>=1.0.0.0 && <1.3), bytestring (>=0.10.8 && <0.13), case-insensitive (>=1.2.0.0 && <1.3), hal (>=0.4.7 && <0.4.11 || >=1.0.0 && <1.2), http-media (>=0.8.1.1 && <0.9), http-types (>=0.12.3 && <0.13), network (>=3.2.3.0 && <3.3), text (>=2.0 && <2.2), unordered-containers (>=0.2.10.0 && <0.3), vault (>=0.3.1.0 && <0.4), wai (>=3.2.2 && <3.3) [details] |
| Tested with | ghc ==9.6.7 || ==9.8.4 || ==9.10.3 || ==9.12.2 |
| License | BSD-3-Clause |
| Copyright | Copyright (C) 2021, 2024 Bellroy Pty Ltd |
| Author | Bellroy Tech Team <haskell@bellroy.com> |
| Maintainer | Bellroy Tech Team <haskell@bellroy.com> |
| Uploaded | by kokobd at 2025-12-15T20:11:39Z |
| Category | AWS, Cloud |
| Home page | https://github.com/bellroy/wai-handler-hal |
| Bug tracker | https://github.com/bellroy/wai-handler-hal/issues |
| Source repo | head: git clone https://github.com/bellroy/wai-handler-hal.git |
| Distributions | |
| Downloads | 965 total (43 in the last 30 days) |
| Rating | (no votes yet) [estimated by Bayesian average] |
| Your Rating |
|
| Status | Docs available [build log] Last success reported on 2025-12-15 [all 1 reports] |
Readme for wai-handler-hal-0.5.0.0
[back to package description]wai-handler-hal
This library lets you run wai Applications on AWS Lambda, which
means you can now use mature web frameworks like
servant.
The main entry point is Network.Wai.Handler.Hal.run, which wraps an
Application and returns a function that can be passed to hal's
AWS.Lambda.Runtime.mRuntime.
NOTE: The function returned by Network.Wai.Handler.Hal.run is
only for Lambda Proxy
Integrations
of AWS API Gateway REST APIs (AWS::ApiGateway::RestApi in
CloudFormation). If you try to use such a Lambda with an API Gateway
HTTP API (AWS::ApiGatewayV2::Api in CloudFormation), it will
return 500s.
For code examples, see this repository, which contains:
wai-handler-hal-example: A simpleservantAPI set up to run on bothhalandwarp; andwai-handler-hal-cdk: A small AWS CDK application that deploys an API backed bywai-handler-hal-example.
Developing
Instead of serving your application with something like
warp, you will set up an
executable that serves your application with
hal. The necessary glue
code looks something like this:
import AWS.Lambda.Runtime (mRuntime)
import Network.Wai (Application)
import qualified Network.Wai.Handler.Hal as WaiHandler
app :: Application
app = undefined -- From Servant or wherever else
main :: IO ()
main = mRuntime $ WaiHandler.run app
Local testing
Compiled Lambda functions can be awkward to test, especially if you're
relying on an API Gateway integration to translate HTTP
requests. Consider defining a second executable target that serves
your Application using warp, which you can use for local
testing.
Caveats
-
The Lambda is never told the port that the API Gateway is listening on. Most APIs will listen on
443(HTTPS), so that's what the library reports by default. SeerunWithContextif you need to change this. -
The Lambda is never told the HTTP version that the client uses when talking with the API Gateway. We assume HTTP 1.1.
Packaging
Lambda functions are packaged in one of two ways: as .zip files or
as Docker container images. The wai-handler-hal-cdk example uses
.zip files for simplicity. CDK doesn't give us an easy way to build
container images using nix build, so a container-based deployment
using CDK would need to push to ECR first and then reference the image
by name.
.zip files
You will need to create a .zip file containing (at
least)
an executable named bootstrap. This executable needs to run in
Amazon's runtime environment, and there are multiple ways to ensure
this.
Static linking
IOHK's haskell.nix
can build static Haskell binaries by cross-compiling against musl
libc. This is convenient, but consider copyleft implications (of
libgmp; wai-handler-hal is BSD-3-Clause) if you are distributing
the binaries to other people.
Dynamic linking
The other option is to compile the executable in an environment with packages that match the Lambda runtime environment. Some ideas:
- Build the executable in an "imitation environment" like the
lambci/lambdaDocker container; or - (Untested) build the executable on an Amazon Linux 2 EC2 instance.
Docker container images
It is possible to package Lambdas into Docker containers for
deployment. Amazon provide base containers for custom runtimes in the
repository
amazon/aws-lambda-provided. One
nice feature of these images is that they provide a runtime interface
emulator,
which they fall back to when not running "for real". This makes it
possible to directly invoke the lambda and see how it behaves. (This
is less important here because we can serve our application off
warp, but for writing Lambdas not invoked by an API Gateway Proxy
Integration, it's handy.)
At the time of writing (2021-04-06), the
amazon/aws-lambda-provided:al2 (Amazon Linux 2 tag) is the newest
base image that Amazon recommends for custom runtimes. You can use a
Dockerfile to build your images; there are also commented .nix files
in the example repository,
showing a couple of different approaches to building container images using Nix.
Integrating
Actually calling the Lambda is done with a Lambda proxy integration from an API Gateway REST API.
The simplest possible integration sends every request to the Lambda
(where the wai Application can return 404 or whatever if the
endpoint doesn't match). This is done by mapping the paths / and
/{proxy+} for the HTTP method ANY. We do this in our CDK example,
and CDK provides a Construct which encapsulates this pattern, making
it extremely simple to deploy.
Splitting Servant applications
While it's simplest to back the entire API with a single Lambda, it
does mean that you risk one Lambda carrying an ever-expanding set of
IAM permissions. Servant's combinators make it easy to break the API
into parts that are served by individual Lambdas, which can each have
the minimal set of permissions attached to their role. If your Servant
service had endpoints foo, bar, and baz, you'd serve them all
from Warp with an expression like Warp.runEnv 8080 . Servant.serve $ foo :<|> bar :<|> baz. But Servant.serve foo, Servant.serve bar,
and Servant.serve baz are also all WAI Applications, and can each
be bundled into distinct Lambda functions using wai-handler-hal.
Other caveats
- The stage name in a path segment is not passed to the Lambda, so it
is not passed to the
waiApplication. An invoke URL likehttps://abcde12345.execute-api.us-east-1.amazonaws.com/prod/hootwill sendpathInfo = ["hoot"]to theApplication.
Formatters
The formatters used in this repo are provided by shell.nix:
*.hs:ormolu*.cabal:cabal-fmt(cabal-fmt --inplace wai-handler-hal.cabal)*.nix:nixpkgs-fmt(nixpkgs-fmt *.nix)
Regenerate CI
This repo uses haskell-ci, which is provided by flake.nix:
haskell-ci regenerate