/elm-serverless

Deploy an elm HTTP API to AWS Lambda using serverless

Primary LanguageElmMIT LicenseMIT

elm serverless

serverless elm-package npm version license CircleCI Coveralls gitter

Deploy an elm HTTP API to AWS Lambda using serverless. Define your API in elm and then use the npm package to bridge the interface between the AWS Lambda handler and your elm program.

NOTE: The master branch is on version 4.0.0 which is not yet released. This will include the following changes from release 3.

  • Opaque Conn and Plug types
  • A more efficient pipeline
  • Proper JavaScript interop (#2)

Intro

You define a Serverless.Program, which among other things, is configured with a Pipeline.

main : Serverless.Program Config Model Msg
main =
    Serverless.httpApi
        { configDecoder = configDecoder     -- Decode once per Lambda container
        , requestPort = requestPort
        , responsePort = responsePort
        , endpoint = Endpoint               -- Processing starts with this msg
        , initialModel = Model []           -- Fresh custom model per connection
        , pipeline = pipeline               -- Pipelines process connections
        , subscriptions = subscriptions
        }
  • pipelines are lists of Plugs
  • each plug receives a connection (called Conn) and transforms it in some way
  • connections contain the HTTP request, the as yet unsent response, and some other stuff which is specific to your application

Basically, the pipeline takes the place of the usual update function in a traditional elm app. And instead of transforming your Model, you transform a Conn, which contains your Model, but also has the request, response, and per deployment configuration.

pipeline : Plug
pipeline =
    pipeline
        |> plug (cors "*" [ GET, OPTIONS ]) -- Plugs transform a connection
        |> plug authentication              -- Plugs are chained in a pipeline
        -- ...
        |> fork router                      -- Routers fork pipelines

For routing, we use ktonon/url-parser, which is a fork of evancz/url-parser adapted for use outside of the browser. A router function can then be used to map routes to new pipelines for handling specific tasks. Router functions can be plugged into the pipeline.

router : Conn -> Plug
router conn =
    case                                    -- Route however you want, here we
        ( conn |> method                    -- use HTTP method
        , conn |> path |> parseRoute route NotFound -- and parsed request path
        )
    of
        ( GET, Home ) ->
            responder responsePort <|
                \_ -> ( 200, text "Home" )

            -- vvvvvvvvvv --                -- UrlParser gives structured routes
        ( GET, Quote lang ) ->
            Quote.pipeline lang             -- Defer to another module

        _ ->
            responder responsePort <|
                \conn -> ( 404, text <| (++) "Nothing at: " <| path conn )

Demo

There are two demos:

  • ./demo: which is kept in sync with the master branch of this repository
  • elm-serverless-demo: a separate repository which works with elm-package (the latest release)

Middleware

The following is a list of known middleware:

Contributing

elm-serverless targets Node.js 6.10. To get a development environment setup, fork and clone this repo. npm install will also install elm packages for the base library as well as the demo. npm test will perform the full range of tests including:

The demo tests are written in JavaScript using supertest and mocha and rely on a running test instance of the demo server, which is started automatically when you run npm test. You can also launch tests in watch mode with the command npm run test:watch.

AWS

An AWS Lambda function would be pretty limited without an interface to the rest of AWS. AWS SDK for elm is a work in progress. I don't think there is a huge amount of work to be done here as we can probably generate the elm interface from the AWS SDK json files. But it is definitely non-trivial.