# Serverless Haskell [![Build status](https://img.shields.io/travis/seek-oss/serverless-haskell.svg)](https://travis-ci.org/seek-oss/serverless-haskell) [![Hackage](https://img.shields.io/hackage/v/serverless-haskell.svg)](https://hackage.haskell.org/package/serverless-haskell) [![Stackage LTS](https://www.stackage.org/package/serverless-haskell/badge/lts)](https://www.stackage.org/lts/package/serverless-haskell) [![Hackage dependencies](https://img.shields.io/hackage-deps/v/serverless-haskell.svg)](https://packdeps.haskellers.com/feed?needle=serverless-haskell) [![npm](https://img.shields.io/npm/v/serverless-haskell.svg)](https://www.npmjs.com/package/serverless-haskell) Deploying Haskell code onto [AWS Lambda] using [Serverless]. ## Requirements * AWS account * [Stack] * [NPM] * [Docker] ## Usage * Create a [Stack] package for your code: ```shell stack new mypackage ``` LTS 9-12 are supported, older versions are likely to work too but untested. * Initialise a Serverless project inside the Stack package directory and install the `serverless-haskell` plugin: ```shell cd mypackage npm init . npm install --save serverless serverless-haskell@x.y.z ``` The version of the NPM package to install must match the version of the Haskell package. * Create `serverless.yml` with the following contents: ```yaml service: myservice provider: name: aws runtime: haskell functions: myfunc: handler: mypackage.myfunc # Here, mypackage is the Haskell package name and myfunc is the executable # name as defined in the Cabal file. The handler field may be prefixed # with a path of the form `dir1/.../dirn`, relative to `serverless.yml`, # which points to the location where the Haskell package `mypackage` is # defined. This prefix is not needed when the Stack project is defined at # the same level as `serverless.yml`. plugins: - serverless-haskell ``` * Write your `main` function: ```haskell import qualified Data.Aeson as Aeson import AWSLambda main = lambdaMain handler handler :: Aeson.Value -> IO [Int] handler evt = do putStrLn "This should go to logs" print evt pure [1, 2, 3] ``` * Use `sls deploy` to deploy the executable to AWS Lambda. The `serverless-haskell` plugin will build the package using Stack and upload it to AWS together with a JavaScript wrapper to pass the input and output from/to AWS Lambda. You can test the function and see the invocation results with `sls invoke myfunc`. To invoke the function locally, use `sls invoke local -f myfunc`. ### API Gateway This plugin supports handling API Gateway requests. Declare the HTTP events normally in `serverless.yml` and use [AWSLambda.Events.APIGateway](https://hackage.haskell.org/package/serverless-haskell/docs/AWSLambda-Events-APIGateway.html) in the handler to process them. [Serverless Offline] can be used for local testing of API Gateway requests. ### Notes * Only AWS Lambda is supported at the moment. Other cloud providers would require different JavaScript wrappers to be implemented. See [AWSLambda](https://hackage.haskell.org/package/serverless-haskell/docs/AWSLambda.html) for documentation, including additional options to control the deployment. ## Development Currently, apart from the `master` branch, an `v0.6.x` branch is maintained with no breaking changes since 0.6.0, for inclusion into Stackage LTS 12. For bugfixes and new features that do not change the existing behavior, please target `v0.6.x`. For anything else, target `master`. Changes to the LTS branch will be forward ported to the `master` branch after releasing. ### Testing * Haskell code is tested with Stack: `stack test`. * JavaScript code is linted with `eslint`. ### Integration tests Integration test verifies that the project can build and deploy a complete function to AWS, and it runs with expected functionality. Integration test is only automatically run up to deployment due to the need for an AWS account. To run manually: * Ensure you have the required dependencies: `curl`, [jq], [NPM], `pwgen` and [Stack]. * Get an AWS account and add the access credentials into your shell environment. * Run `./integration-test/run.sh`. The exit code indicates success. * To verify just the packaging, without deployment, run `./integration-test/run.sh --dry-run`. * By default, the integration test is run with LTS 12. To specify a different series, use `RESOLVER_SERIES=lts-9`. ### Releasing * Ensure you are on a correct branch (`v0.6.x` or `master`). * Ensure that all the changes are reflected in the changelog. * Run the integration tests. * Run `./bumpversion major|minor|patch`. This will increment the version number, update the changelog, create and push the Git tag and the branch. * If you have released an LTS version, merge the version branch into `master`, taking care of the conflicts around version numbers and changelog, and release the latest version as well. [AWS Lambda]: https://aws.amazon.com/lambda/ [Docker]: https://www.docker.com/ [jq]: https://stedolan.github.io/jq/ [NPM]: https://www.npmjs.com/ [Serverless]: https://serverless.com/framework/ [Serverless Offline]: https://github.com/dherault/serverless-offline [Stack]: https://haskellstack.org