Skip to content

Commit

Permalink
Merge pull request #55 from anton-k/send-as-monad
Browse files Browse the repository at this point in the history
Send as monad
  • Loading branch information
anton-k authored Nov 2, 2023
2 parents 9a8092b + ffed027 commit 2786fe2
Show file tree
Hide file tree
Showing 17 changed files with 345 additions and 398 deletions.
4 changes: 1 addition & 3 deletions docs/src/00-foreword.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ The main features are:

* easy to use. It has simple design on purpose

* it defines no custom server monads. I promise you

* expressive DSL to compose servers

* type-safe route handlers and conversions
Expand Down Expand Up @@ -40,7 +38,7 @@ server = "api/v1/hello" /. hello

-- | The handler definition as a function
hello :: Get (Resp Text)
hello = Send $ pure $ ok "Hello World"
hello = pure $ ok "Hello World"
```


Expand Down
8 changes: 5 additions & 3 deletions docs/src/01-hello-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ We have type synonyms for all HTTP-methods (`Get`, `Post`, `Put` etc).

It's interesting to know that library mig does not use any custom monads for operation.
Instead it runs on top of monad provided by the user. Usually it would be `IO` or `Reader` over `IO`.
Also for convenience `Send` is also `Monad`, `MonadTrans` and `MonadIO`.
So we can omit `Send` constructor in many cases.

### HTTP-response type

Expand Down Expand Up @@ -143,7 +145,7 @@ Let's complete the example and define a handler which returns static text:

```haskell
hello :: Get IO (Resp Json)
hello = Send $ pure $ ok "Hello World!"
hello = pure $ ok "Hello World!"
```

We have several wrappers here:
Expand Down Expand Up @@ -193,7 +195,7 @@ server :: Server IO
server = "api/v1/hello" /. hello

hello :: Get IO (Resp Json Text)
hello = Send $ pure $ ok "Hello World!"
hello = pure $ ok "Hello World!"
```

If we run the code we can test it with `curl` in command line:
Expand All @@ -210,7 +212,7 @@ Let's define another handler to say `bye`:

```haskell
bye :: Get IO (Resp Json)
bye = Send $ pure $ ok "Goodbye"
bye = pure $ ok "Goodbye"
```

We can add it to the server with monoid method as `Server m` is a `Monoid`:
Expand Down
26 changes: 13 additions & 13 deletions docs/src/02-request-anatomy.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ by the name:
```haskell
hello :: Query "who" Text -> Get (Resp Text)
hello (Query name) = Send $
hello (Query name) =
pure $ ok $ "Hello " <> name
```

Expand Down Expand Up @@ -109,7 +109,7 @@ queries in the handler. For example if we want to greet two persons we can write

```haskell
hello :: Query "personA" Text -> Query "personB" Text -> Get (Resp Text)
hello (Query nameA) (Query nameB) = Send $
hello (Query nameA) (Query nameB) =
pure $ ok $ "Hello " <> nameA <> " and " <> nameB
```

Expand All @@ -118,7 +118,7 @@ For example let's add two numbers:

```haskell
add :: Query "a" Int -> Query "b" Int -> Get (Resp Int)
add (Query a) (Query b) = Send $
add (Query a) (Query b) =
pure $ ok (a + b)
```

Expand All @@ -131,7 +131,7 @@ Let's for example query numbers for addition as capture parameters:

```haskell
add :: Capture "a" Int -> Capture "b" Int -> Get (Resp Int)
add (Query a) (Query b) = Send $
add (Query a) (Query b) =
pure $ ok (a + b)
```

Expand Down Expand Up @@ -176,7 +176,7 @@ For the example we haven't altered the server and our example:

```haskell
add :: Query "a" Int -> Query "b" Int -> Get (Resp Int)
add (Query a) (Query b) = Send $
add (Query a) (Query b) =
pure $ ok (a + b)

server = "api/v1/add" /. add
Expand Down Expand Up @@ -223,7 +223,7 @@ data AddInput = AddInput

-- | Using JSON as body request
handleAddJson :: Body AddInput -> Post (Resp Int)
handleAddJson (Body (AddInput a b)) = Send $
handleAddJson (Body (AddInput a b)) =
pure $ ok $ a + b
```

Expand Down Expand Up @@ -291,7 +291,7 @@ server =

-- | Simple getter
helloWorld :: Get (Resp Text)
helloWorld = Send $ do
helloWorld = do
pure $ ok "Hello world!"

newtype TraceId = TraceId Text
Expand All @@ -301,25 +301,25 @@ newtype TraceId = TraceId Text
and using conditional output status
-}
handleSucc :: Header "Trace-Id" TraceId -> Query "value" Int -> Get (Resp Int)
handleSucc (Header _traceId) (Query n) = Send $ do
handleSucc (Header _traceId) (Query n) =
pure $ ok (succ n)

-- | Using optional query parameters.
handleSuccOpt :: Optional "value" Int -> Get (Resp Int)
handleSuccOpt (Optional n) = Send $ do
handleSuccOpt (Optional n) =
pure $ case n of
Just val -> ok (succ val)
Nothing -> ok 0

{-| Using several query parameters
-}
handleAdd :: Query "a" Int -> Query "b" Int -> Get (Resp Int)
handleAdd (Query a) (Query b) = Send $ do
handleAdd (Query a) (Query b) =
pure $ ok $ a + b

-- | Using query flag if flag is false returns 0
handleAddIf :: Query "a" Int -> Query "b" Int -> QueryFlag "perform" -> Get (Resp Int)
handleAddIf (Query a) (Query b) (QueryFlag addFlag) = Send $ do
handleAddIf (Query a) (Query b) (QueryFlag addFlag) = do
pure $
ok $
if addFlag
Expand All @@ -332,7 +332,7 @@ captured in URL. For example:
> http://localhost:8085/hello/api/mul/3/100
-}
handleMul :: Capture "a" Int -> Capture "b" Int -> Get (Resp Int)
handleMul (Capture a) (Capture b) = Send $ do
handleMul (Capture a) (Capture b) = do
pure $ ok (a * b)

data AddInput = AddInput
Expand All @@ -343,7 +343,7 @@ data AddInput = AddInput

-- | Using JSON as input
handleAddJson :: Body AddInput -> Post (Resp Int)
handleAddJson (Body (AddInput a b)) = Send $ do
handleAddJson (Body (AddInput a b)) =
pure $ ok $ a + b
```

Expand Down
4 changes: 2 additions & 2 deletions docs/src/03-response-anatomy.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ server =
"square-root" /. squareRoot

squareRoot :: Body Float -> Post (RespOr Text Float)
squareRoot (Body arg) = Send $ pure $
squareRoot (Body arg) = pure $
if arg >= 0
then ok (sqrt arg)
else bad badRequest400 "Argument for square root should be non-negative"
Expand All @@ -161,7 +161,7 @@ trace id from request to the response. Let's do it with `addHeaders`:

```haskell
passTrace :: Header "trace-id" Text -> Post (Resp ())
passTrace (Header traceId) = Send $
passTrace (Header traceId) =
pure $ addHeaders [("trace-id", toHeader traceId)] $ ok ()
```

Expand Down
2 changes: 1 addition & 1 deletion examples/mig-example-apps/HelloWorld/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ server = "api/v1/hello" /. hello

-- | Handler takes no inputs and marked as Get HTTP-request that returns Text response as Json.
hello :: Get IO (Resp Json Text)
hello = Send $ pure $ ok "Hello World!"
hello = pure $ ok "Hello World!"
23 changes: 11 additions & 12 deletions examples/mig-example-apps/RouteArgs/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ routeArgs =

-- | Simple getter
helloWorld :: Get (Resp Text)
helloWorld = Send $ do
helloWorld = do
pure $ ok "Hello world!"

newtype TraceId = TraceId Text
Expand All @@ -56,7 +56,7 @@ newtype TraceId = TraceId Text
and using conditional output status
-}
handleSucc :: Header "Trace-Id" TraceId -> Query "value" Int -> Get (Resp Int)
handleSucc (Header traceId) (Query n) = Send $ do
handleSucc (Header traceId) (Query n) = do
pure $ setHeader "Trace-Id" traceId $ setStatus st $ ok (succ n)
where
st
Expand All @@ -65,7 +65,7 @@ handleSucc (Header traceId) (Query n) = Send $ do

-- | Using optional query parameters and error as RespOr.
handleSuccOpt :: Optional "value" Int -> Get (RespOr Text Int)
handleSuccOpt (Optional n) = Send $ do
handleSuccOpt (Optional n) = do
pure $ case n of
Just val -> ok (succ val)
Nothing -> bad status500 "error: no input"
Expand All @@ -75,14 +75,14 @@ Note that function can have any number of arguments.
We encode the input type with proper type-wrapper.
-}
handleAdd :: Query "a" Int -> Query "b" Int -> Get (Resp Int)
handleAdd (Query a) (Query b) = Send $ do
handleAdd (Query a) (Query b) = do
pure $ addHeaders headers $ ok $ a + b
where
headers = [("args", "a, b")]

-- | Using query flag if flag is false returns 0
handleAddIf :: Query "a" Int -> Query "b" Int -> QueryFlag "perform" -> Get (Resp Int)
handleAddIf (Query a) (Query b) (QueryFlag addFlag) = Send $ do
handleAddIf (Query a) (Query b) (QueryFlag addFlag) = do
pure $
ok $
if addFlag
Expand All @@ -95,7 +95,7 @@ captured in URL. For example:
> http://localhost:8085/hello/api/mul/3/100
-}
handleMul :: Capture "a" Int -> Capture "b" Int -> Get (Resp Int)
handleMul (Capture a) (Capture b) = Send $ do
handleMul (Capture a) (Capture b) = do
pure $ ok (a * b)

data AddInput = AddInput
Expand All @@ -106,13 +106,12 @@ data AddInput = AddInput

-- | Using JSON as input
handleAddJson :: Body AddInput -> Post (Resp Int)
handleAddJson (Body (AddInput a b)) = Send $ do
handleAddJson (Body (AddInput a b)) = do
pure $ ok $ a + b

handleSquareRoot :: Body Float -> Post (RespOr Text Float)
handleSquareRoot (Body arg) =
Send $
pure $
if arg >= 0
then ok (sqrt arg)
else bad badRequest400 "Argument for square root should be non-negative"
pure $
if arg >= 0
then ok (sqrt arg)
else bad badRequest400 "Argument for square root should be non-negative"
Loading

0 comments on commit 2786fe2

Please sign in to comment.