docs: readme

This commit is contained in:
Orion Kindel
2025-03-01 16:18:10 -06:00
parent a58facc982
commit e646cf9c08
2 changed files with 75 additions and 15 deletions

View File

@@ -5,15 +5,73 @@
HTTP server library inspired by [`axum`](https://docs.rs/latest/axum), allowing best-in-class
expressive routing.
## Example
This example implements this REST interface in 36LoC:
- `GET /cheeses` - Lists all cheeses (strings) known to server
- `POST /cheeses` - Add a cheese to the in memory cheese list
- `DELETE /cheeses/:cheese` - Remove a cheese from the cheese list
```purs
root :: Get -> Path "/" _ -> Aff String
root _ _ = pure "Hello, world!"
module Main where
import Prelude
import Axon as Axon
import Axon.Request.Handler as Handler
import Axon.Request.Parts.Class (Delete, Get, Path(..), Post)
import Axon.Request.Parts.Path (type (/))
import Axon.Response (Response)
import Axon.Response.Construct (Json(..), toResponse)
import Axon.Response.Status as Status
import Data.Filterable (filter)
import Data.Foldable (elem)
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff, launchAff_, joinFiber)
import Effect.Aff as Aff
import Effect.Class (liftEffect)
import Effect.Ref (Ref)
import Effect.Ref as Ref
main :: Effect Unit
main = Axon.serve (root `Handle.or` Handle.Default.notFound)
main = launchAff_ do
cheeses :: Ref (Array String) <- liftEffect $ Ref.new
[ "cheddar", "swiss", "gouda" ]
-- GET localhost:8000/ -> 200 OK "Hello, world!"
-- GET localhost:8000/foo -> 404 Not Found
let
getCheeses :: Get -> Path ("cheeses") _ -> Aff Response
getCheeses _ _ = liftEffect do
cheeses' <- Ref.read cheeses
toResponse $ Status.ok /\ Json cheeses'
deleteCheese :: Delete -> Path ("cheeses" / String) _ -> Aff Response
deleteCheese _ (Path id) = liftEffect do
cheeses' <- Ref.read cheeses
if not $ elem id cheeses' then
toResponse Status.notFound
else
Ref.modify_ (filter (_ /= id)) cheeses
*> toResponse Status.accepted
postCheese :: Post -> Path "cheeses" _ -> String -> Aff Response
postCheese _ _ cheese =
let
tryInsert as
| elem cheese as = { state: as, value: false }
| otherwise = { state: as <> [ cheese ], value: true }
in
liftEffect
$ Ref.modify' tryInsert cheeses
>>= if _ then toResponse Status.accepted else toResponse Status.conflict
handle <-
Axon.serveBun
{ port: 8080, hostname: "localhost" }
(getCheeses `Handler.or` postCheese `Handler.or` deleteCheese)
joinFiber handle.join
```
## Request Handlers

View File

@@ -29,7 +29,8 @@ main = runSpecAndExitProcess [ specReporter ] $ describe "Axon" do
Test.Header.spec
pending' "example" do
cheeses :: Ref.Ref (Array String) <- liftEffect $ Ref.new ["cheddar", "swiss", "gouda"]
cheeses :: Ref.Ref (Array String) <- liftEffect $ Ref.new
[ "cheddar", "swiss", "gouda" ]
let
getCheeses :: Get -> Path ("cheeses") _ -> Aff Response
@@ -50,19 +51,20 @@ main = runSpecAndExitProcess [ specReporter ] $ describe "Axon" do
postCheese _ _ cheese =
let
tryInsert as
| elem cheese as = {state: as, value: false}
| otherwise = {state: as <> [cheese], value: true}
| elem cheese as = { state: as, value: false }
| otherwise = { state: as <> [ cheese ], value: true }
in
liftEffect
$ Ref.modify' tryInsert cheeses
>>= if _ then
toResponse $ Status.accepted
else
toResponse $ Status.conflict
liftEffect
$ Ref.modify' tryInsert cheeses
>>=
if _ then
toResponse $ Status.accepted
else
toResponse $ Status.conflict
handle <-
Axon.serveBun
{port: 8080, hostname: "localhost"}
{ port: 8080, hostname: "localhost" }
(getCheeses `Handler.or` postCheese `Handler.or` deleteCheese)
Aff.joinFiber $ handle.join