More cookbook improvements (#1305)
* Simplify code in CurlMock cookbook recipe * Link to latest versions of packages on hackage * Fix grammar in the OpenIdConnect recipe * HasForeignType -> HasForeign
This commit is contained in:
parent
b9d8fbcdc1
commit
8e7b538921
5 changed files with 24 additions and 36 deletions
|
@ -86,7 +86,7 @@ listFromAPI :: (HasForeign lang ftype api, GenerateList ftype (Foreign ftype api
|
|||
```
|
||||
|
||||
This looks a bit confusing...
|
||||
[Here](https://hackage.haskell.org/package/servant-foreign-0.11.1/docs/Servant-Foreign.html#t:HasForeignType) is the documentation for the `HasForeign` typeclass.
|
||||
[Here](https://hackage.haskell.org/package/servant-foreign/docs/Servant-Foreign.html#t:HasForeign) is the documentation for the `HasForeign` typeclass.
|
||||
We will not go into details here, but this allows us to create a value of type `ftype` for any type `a` in our API.
|
||||
|
||||
In our case we want to create a mock of every type `a`.
|
||||
|
@ -130,24 +130,12 @@ generateCurl :: (GenerateList Mocked (Foreign Mocked api), HasForeign NoLang Moc
|
|||
generateCurl p host =
|
||||
fmap T.unlines body
|
||||
where
|
||||
body = foldr (\endp curlCalls -> mCons (generateEndpoint host endp) curlCalls) (return [])
|
||||
body = mapM (generateEndpoint host)
|
||||
$ listFromAPI (Proxy :: Proxy NoLang) (Proxy :: Proxy Mocked) p
|
||||
```
|
||||
|
||||
To understand this function, better start at the end:
|
||||
|
||||
`listFromAPI` gives us a list of endpoints. We iterate over them (`foldr`) and call `generateEndpoint` for every endpoint.
|
||||
|
||||
As generate endpoint will not return `Text` but `IO Text` (remember we need some random bits to mock), we cannot just use the cons operator but need to build `IO [Text]` from `IO Text`s.
|
||||
|
||||
``` haskell
|
||||
mCons :: IO a -> IO [a] -> IO [a]
|
||||
mCons ele list =
|
||||
ele >>= \e -> list >>= \l -> return ( e : l )
|
||||
```
|
||||
|
||||
|
||||
Now comes the juicy part; accessing the endpoints data:
|
||||
First, `listFromAPI` gives us a list of `Req Mocked`. Each `Req` describes one endpoint from the API type.
|
||||
We generate a curl call for each of them using the following helper.
|
||||
|
||||
``` haskell
|
||||
generateEndpoint :: Text -> Req Mocked -> IO Text
|
||||
|
@ -169,7 +157,7 @@ generateEndpoint host req =
|
|||
`servant-foreign` offers a multitude of lenses to be used with `Req`-values.
|
||||
|
||||
`reqMethod` gives us a straigthforward `Network.HTTP.Types.Method`, `reqUrl` the url part and so on.
|
||||
Just take a look at [the docs](https://hackage.haskell.org/package/servant-foreign-0.11.1/docs/Servant-Foreign.html).
|
||||
Just take a look at [the docs](https://hackage.haskell.org/package/servant-foreign/docs/Servant-Foreign.html).
|
||||
|
||||
But how do we get our mocked json string? This seems to be a bit to short to be true:
|
||||
|
||||
|
@ -201,7 +189,7 @@ And now, lets hook it all up in our main function:
|
|||
``` haskell
|
||||
main :: IO ()
|
||||
main =
|
||||
generateCurl api "localhost:8081" >>= (\v -> T.IO.putStrLn v)
|
||||
generateCurl api "localhost:8081" >>= T.IO.putStrLn
|
||||
```
|
||||
|
||||
Done:
|
||||
|
@ -213,6 +201,6 @@ curl -X POST -d '{"email":"wV_b:z!(3DM V","age":10,"name":"=|W"}
|
|||
```
|
||||
|
||||
This is of course no complete curl call mock generator, many things including path arguments are missing.
|
||||
But it correctly generate mock calls for simple POST requests.
|
||||
But it correctly generates mock calls for simple POST requests.
|
||||
|
||||
Also, we now know how to use `HasForeignType` and `listFromAPI` to generate anything we want.
|
||||
|
|
|
@ -34,16 +34,16 @@ app = serve api server
|
|||
```
|
||||
|
||||
It's now time to actually run the `Application`.
|
||||
The [`warp-tls`](https://hackage.haskell.org/package/warp-tls-3.2.4/docs/Network-Wai-Handler-WarpTLS.html)
|
||||
The [`warp-tls`](https://hackage.haskell.org/package/warp-tls/docs/Network-Wai-Handler-WarpTLS.html)
|
||||
package provides two functions for running an `Application`, called
|
||||
[`runTLS`](https://hackage.haskell.org/package/warp-tls-3.2.4/docs/Network-Wai-Handler-WarpTLS.html#v:runTLS)
|
||||
and [`runTLSSocket`](https://hackage.haskell.org/package/warp-tls-3.2.4/docs/Network-Wai-Handler-WarpTLS.html#v:runTLSSocket).
|
||||
[`runTLS`](https://hackage.haskell.org/package/warp-tls/docs/Network-Wai-Handler-WarpTLS.html#v:runTLS)
|
||||
and [`runTLSSocket`](https://hackage.haskell.org/package/warp-tls/docs/Network-Wai-Handler-WarpTLS.html#v:runTLSSocket).
|
||||
We will be using the first one.
|
||||
|
||||
It takes two arguments,
|
||||
[the TLS settings](https://hackage.haskell.org/package/warp-tls-3.2.4/docs/Network-Wai-Handler-WarpTLS.html#t:TLSSettings)
|
||||
[the TLS settings](https://hackage.haskell.org/package/warp-tls/docs/Network-Wai-Handler-WarpTLS.html#t:TLSSettings)
|
||||
(certificates, keys, ciphers, etc)
|
||||
and [the warp settings](https://hackage.haskell.org/package/warp-3.2.12/docs/Network-Wai-Handler-Warp-Internal.html#t:Settings)
|
||||
and [the warp settings](https://hackage.haskell.org/package/warp/docs/Network-Wai-Handler-Warp-Internal.html#t:Settings)
|
||||
(port, logger, etc).
|
||||
|
||||
We will be using very simple settings for this example but you are of
|
||||
|
|
|
@ -9,7 +9,7 @@ some login token would be saved in the user agent local storage.
|
|||
Workflow:
|
||||
|
||||
1. user is presented with a login button,
|
||||
2. when the user click on the button it is redirected to the OIDC
|
||||
2. when the user clicks on the button it is redirected to the OIDC
|
||||
provider,
|
||||
3. the user login in the OIDC provider,
|
||||
4. the OIDC provider will redirect the user and provide a `code`,
|
||||
|
@ -221,7 +221,7 @@ The `AuthInfo` is about the infos we can grab from OIDC provider.
|
|||
|
||||
To be more precise, the user should come with a `code` (a token) and
|
||||
POSTing that code to the correct OIDC provider endpoint should return a JSON
|
||||
object. One of the field should be named `id_token` which should be a
|
||||
object. One of the fields should be named `id_token` which should be a
|
||||
JWT containing all the information we need. Depending on the scopes we
|
||||
asked we might get more information.
|
||||
|
||||
|
@ -252,12 +252,12 @@ The `handleLoggedIn` is that part that will retrieve the information from
|
|||
the user once he is redirected from the OIDC Provider after login.
|
||||
|
||||
If the user is redirected to the `redirect_uri` but with an `error` query
|
||||
parameter then it means something goes wrong.
|
||||
parameter then it means something went wrong.
|
||||
If there is no error query param but a `code` query param it means the user
|
||||
successfully logged in. From there we need to make a request to the token
|
||||
endpoint of the OIDC provider. Its a POST that should contains the code
|
||||
as well as the client id & secret.
|
||||
This is the role of the `requestTokens` to make this HTTP POST.
|
||||
endpoint of the OIDC provider. It's a POST that should contain the code
|
||||
as well as the client id and secret.
|
||||
Making this HTTP POST is the responsibility of `requestTokens`.
|
||||
|
||||
From there we extract the `claims` of the JWT contained in one of the value
|
||||
of the JSON returned by the POST HTTP Request.
|
||||
|
@ -329,12 +329,12 @@ data Customer = Customer {
|
|||
}
|
||||
```
|
||||
|
||||
Here is the code that display the homepage.
|
||||
Here is the code that displays the homepage.
|
||||
It should contain a link to the the `/login` URL.
|
||||
When the user will click on this link it will be redirected to Google login page
|
||||
When the user clicks on this link it will be redirected to Google login page
|
||||
with some generated information.
|
||||
|
||||
The page also display the content of the local storage.
|
||||
The page also displays the content of the local storage.
|
||||
And in particular the items `api-key` and `user-id`.
|
||||
Those items should be set after a successful login when the user is redirected to
|
||||
`/login/cb`.
|
||||
|
|
|
@ -86,7 +86,7 @@ In the second step it actually sends our message to Sentry with the `register` f
|
|||
|
||||
- the configured Sentry service which we just created
|
||||
- the name of the logger
|
||||
- the error level (see [SentryLevel](https://hackage.haskell.org/package/raven-haskell-0.1.2.0/docs/System-Log-Raven-Types.html#t:SentryLevel) for the possible options)
|
||||
- the error level (see [SentryLevel](https://hackage.haskell.org/package/raven-haskell/docs/System-Log-Raven-Types.html#t:SentryLevel) for the possible options)
|
||||
- the message we want to send
|
||||
- an update function to handle the specific `SentryRecord`
|
||||
|
||||
|
|
|
@ -620,7 +620,7 @@ In short, this means that a handler of type `Handler a` is simply
|
|||
equivalent to a computation of type `IO (Either ServerError a)`, that is, an IO
|
||||
action that either returns an error or a result.
|
||||
|
||||
The module [`Control.Monad.Except`](https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Except.html#t:ExceptT)
|
||||
The module [`Control.Monad.Except`](https://hackage.haskell.org/package/mtl/docs/Control-Monad-Except.html#t:ExceptT)
|
||||
from which `ExceptT` comes is worth looking at.
|
||||
Perhaps most importantly, `ExceptT` and `Handler` are instances of `MonadError`, so
|
||||
`throwError` can be used to return an error from your handler (whereas `return`
|
||||
|
@ -634,7 +634,7 @@ kind and abort early. The next two sections cover how to do just that.
|
|||
|
||||
Other important instances from the list above are `MonadIO m => MonadIO
|
||||
(ExceptT e m)`, and therefore also `MonadIO Handler` as there is a `MonadIO IO` instance.
|
||||
[`MonadIO`](http://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-IO-Class.html)
|
||||
[`MonadIO`](http://hackage.haskell.org/package/base/docs/Control-Monad-IO-Class.html#t:MonadIO)
|
||||
is a class from the **transformers** package defined as:
|
||||
|
||||
``` haskell ignore
|
||||
|
|
Loading…
Reference in a new issue