haskell-servant / haskell-servant/servant
Deriving an API server by using a "HasHandler" class for each API endpoint
- Dominant language
- Haskell
- Stars
- 2k
- Forks
- 427
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 5
Description
If we have an API like this:
``` haskell
type GetUser = "users" :> Get '[JSON] [User]
type GetAlbert = "albert" :> Get '[JSON] User
type GetIsaac = "isaac" :> Get '[JSON] User
type UserAPI2 = GetUser :<|> GetAlbert :<|> GetIsaac
```
we currently define a server for the API by referencing the position of the endpoint within the API type:
``` haskell
server2 :: Server UserAPI2
server2 = return users2
:<|> return albert
:<|> return isaac
```
How about using a `HasHandler` class instead, for each endpoint within the API, like this:
``` haskell
class HasHandler endpoint where
handle :: Server endpoint
instance HasHandler GetUser where
handle = return users2
instance HasHandler GetAlbert where
handle = return albert
instance HasHandler GetIsaac where
handle = return isaac
```
Now, `server2` can be automatically derived by servant, and if an API endpoint doesn't have a `HasHandler` instance, the user sees a nice error like "no instance for HasHandler ("albert" :> Get '[JSON] User)" rather than the often unintelligible output of eg. plugging in handlers in the wrong order, or missing a handler, when using the `:<|>` combinator.
Is there something I'm missing here, or would this be a superior way to define servers for an API?
I think we could also use a similar class for the client functions, to make it easy get the appropriate client functions, such that we here also reference endpoints within an API, rather than the position of the endpoints within the API. But I'm not sure exactly how this should be structured.
Contributor guide
Assessment
This issue has not been assessed yet.