haskell-servant / haskell-servant/servant

Passing values from `addAuthCheck` to `tweakResponse`

Open
#1,208 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Haskell
Stars
2k
Forks
427
Avg merge
2d 23h
Merged PRs (30d)
5

Description

# Problem

How can I:
* `tweakResponse :: (RouteResult Response -> RouteResult Response) -> Router env -> Router env `

based on some value generated in `DelayedIO`, in
* `addAuthCheck :: Delayed env (a -> b) -> DelayedIO a -> Delayed env b`,

in `HasServer` for some custom combinator of mine?

# Use case

E.g. to add a response header based on auth check result — behind the combinator’s user’s back, i.e. without requiring the user to do anything particular in their handlers.

# Current solutions

`HasServer.route` is called only once ever.

So… for now, I went with `unsafePerformIO` to create a `TVar (Map (Mem.StableName Wai.Request) SomeData)` (or `StmContainers.Map`) shared by `tweakResponse` and `addAuthCheck` — in the scope of this particular `HasServer` instance.

It'’s not really `tweakResponse`, since it doesn’t have access to `Request` (to use as the `Map` key), but if you have a function like:

```haskell
addRespHeader :: Wai.Request -> RouteResult Wai.Response -> IO (RouteResult Wai.Response)
```

then it can be used:

```haskell
route Proxy context subserver =
map
(\app req cont -> app req (cont <=< addRespHeader req))
(route (Proxy @api) context (addAuthCheck subserver someAuthCheck))
```

Also, you have to remember to clean up these map’s entries in `Request`’s finalizer…

```haskell
liftIO $ Mem.addFinalizer req (atomically $ Map.delete reqId headerStore)
```

But this is sooooo hackish… Halp. \^.\^

-----

/cc @alpmestan

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.