docs: readme

This commit is contained in:
Orion Kindel
2025-02-25 14:55:22 -06:00
parent c2a247ba5f
commit 5c9f8ac853

View File

@@ -1 +1,91 @@
# 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`).
<details>
<summary>
`RequestParts`
</summary>
- `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`
</details>
Similarly to the structural extraction of request parts; handlers can use `Axon.Response.Construct.ToResponse` for easily constructing responses.
<details>
<summary>
`ToResponse`
</summary>
- **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`
</details>