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:
Jan Hrcek 2020-06-10 18:36:23 +02:00 committed by GitHub
parent b9d8fbcdc1
commit 8e7b538921
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 24 additions and 36 deletions

View file

@ -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.

View file

@ -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

View file

@ -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`.

View file

@ -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`

View file

@ -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