# axon **WIP** HTTP server library inspired by [`axum`](https://docs.rs/latest/axum), allowing best-in-class expressive routing. ```purs root :: Get -> Path "/" _ -> Aff String root _ _ = pure "Hello, world!" main :: Effect Unit main = Axon.serve (root `Handle.or` Handle.Default.notFound) -- GET localhost:8000/ -> 200 OK "Hello, world!" -- GET localhost:8000/foo -> 404 Not Found ``` ## Request Handlers Request handler functions have any number of parameters that are `RequestParts` and return an `Aff Response` (or any `MonadAff`).
`RequestParts` - `Request` - Always succeeds; provides the entire request - **Combinators** - `Unit` - Always succeeds - `a /\ b` - Tuple of `a` and `b`, where `a` and `b` are `RequestParts`. - `Maybe a` - `a` must be `RequestParts`. If `a` can't be extracted, the handler will still succeed and this will be `Nothing`. If `a` was extracted, it's wrapped in `Just`. - `Either a b` - `a` and `b` must be `RequestParts`. Succeeds if either `a` or `b` succeeds (preferring `a`). Fails if both fail. - **Body** - `String` - succeeds when request has a non-empty body that is valid UTF-8 - `Json a` - succeeds when request has a `String` body (see above) that can be parsed into `a` using `DecodeJson`. - `Buffer` - succeeds when request has a nonempty body. - `Stream` - succeeds when request has a nonempty body. - **Headers** - `Header a` - `a` must be `TypedHeader` from `Axon.Header.Typed`. Allows statically (ex. `ContentType Type.MIME.Json`) or dynamically (ex. `ContentType String`) matching request headers. - `HeaderMap` - All headers provided in the request - **Path** - `Path a c` - Statically match the path of the request, and extract parameters. See `Axon.Request.Parts.Path`. (TODO: this feels too magical, maybe follow axum's prior art of baking paths into the router declaration?) - **Method** - `Get` - `Post` - `Put` - `Patch` - `Delete` - `Options` - `Connect` - `Trace`
Similarly to the structural extraction of request parts; handlers can use `Axon.Response.Construct.ToResponse` for easily constructing responses.
`ToResponse` - **Combinators** - `Status /\ a` - Special case to make sure any `Status` in a tuple will take priority over any default statuses within. TODO: This case (overlapping with `a /\ b` requires the class to be "sealed" in an instance chain. Want a clean way around this so consumers can implement `ToResponse`.) - `a /\ b` - Merges `toResponse a` and `toResponse b`, using `b` on conflicts - **Status** - `Axon.Response.Status.Status` - **Body** - `Axon.Response.Body.Body` - `String` - `Node.Buffer.Buffer` - `Node.Stream.Readable a` (for all `a`) - `Axon.Response.Construct.Json a` - `a` must be `EncodeJson`. This will set the body to `a` stringified, and set `Content-Type` to `application/json`. - **Headers** - `ToResponse` is implemented for all implementors of `TypedHeader` - TODO: `Map String String`