haskell-servant / haskell-servant/servant
Generic: provide a suffix alternative to `:-`
- Dominant language
- Haskell
- Stars
- 2k
- Forks
- 427
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 5
Description
This is purely a cosmetic consideration, but one that has the potential of improving understand-ability of generic capabilities in servant.
Here's how the cookbook showcases generic support in servant:
> The usage is simple, if you only need a collection of routes. First you define a record with field types prefixed by a parameter route:
```
data Routes route = Routes
{ _get :: route :- Capture "id" Int :> Get '[JSON] String
, _put :: route :- ReqBody '[JSON] Int :> Put '[JSON] Bool
}
deriving (Generic)
```
In my experience with servant at work, this has sent a lot of people (myself included) down the wrong path: this gives the impression that the API types are appended to some `route` (based on the `:-` operator that looks like `:>`, and on the `route` parameter name).
Reading the code told me this not the case at all, actually. `route` is instead called `mode` in the lib internals, and the `:-` operator is not appending an API type to an existing route; rather it _projects_ an API type according to a _mode_ argument (`AsClient`, `AsServer`, …). This may not sound like a big issue, but this generated a lot of frustration when we migrated to record-based routes definitions, especially when it came to nested records.
# A modest suggestion
An alternate definition I've tried internally with good reception is to see the `:-` operator as some kind of annotation. In that case, a suffix definition works better (to align with type annotations):
```
infix 0 `As`
type As api mode = mode :- api
data Routes mode = Routes
{ _get :: Capture "id" Int :> Get '[JSON] String `As` mode
, _put :: ReqBody '[JSON] Int :> Put '[JSON] Bool `As` mode
}
deriving (Generic)
```
It's highly subjective, of course, but I think it helps reader "get" what's going on more clearly than `:-`.
I'm not sure where the definition should go, in the lib or in the cookbook, and if `As` is the best name (since `mode` will be instantiated to something like `AsServer` or `AsClient`, the `As` would be redundant).
I'd gladly open a PR to add the type alias and modify the relevant tests / cookbook examples if some kind of consensus is reached
Contributor guide
Assessment
This issue has not been assessed yet.