Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cookbooks #1542

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft

Cookbooks #1542

wants to merge 8 commits into from

Conversation

akhesaCaro
Copy link
Contributor

@akhesaCaro akhesaCaro commented Feb 22, 2022

Introducing NamedRoutes Cookbook (following #1538)

As requested by @alp,
We tried to tu put some consistency between the Generic Cookbook and this one.

The idea is to change a minimum of other cookbook as a first step.

The second step (in another PR) will be a thorough restructuration of the cookbooks.

@akhesaCaro akhesaCaro force-pushed the inserting_doc_NamedRoutes branch 9 times, most recently from dfce55c to bf5b1fd Compare February 23, 2022 06:15
@akhesaCaro akhesaCaro force-pushed the inserting_doc_NamedRoutes branch from bf5b1fd to 23edc45 Compare February 23, 2022 06:21
@akhesaCaro akhesaCaro force-pushed the inserting_doc_NamedRoutes branch from 23edc45 to 19e432c Compare February 23, 2022 06:21
structure. We only deal with non-nested APIs in which every endpoint is on the same
level.

If a you need nesting because you have different branches in your API tree, you
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"If a" => "If"

@@ -0,0 +1,383 @@
# Record-based APIs: the nested records case
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nested API*

It does indeed result in "nested records", but this merely mirrors the structure of the API, which is the central element that should be in the title IMO


*Available in Servant 0.19 or higher*

Servant offers a very natural way of constructing APIs with nested records, called `NamedRoutes`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it'd be good to clarify what "nested" means here? Describing the general pattern dividing up APIs in sub-APIs and being able to combine those easily, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic cookbook should have clarified this beforehand.

doc/cookbook/namedRoutes/NamedRoutes.lhs Outdated Show resolved Hide resolved

Finally, we can run the server and connect the API routes to the handlers as usual:

``` haskell
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't we want to use genericServe here? to stay in the "record world".

Copy link
Member

@arianvp arianvp Feb 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need as NamedRoutes has a HasServer instance. So no need to specialised functions that call toServant and fromServant

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't see the point of introducing genericServe here — it makes the overall story less uniform.

We checked yesterday, and genericServe produces the exact same error message as serve if Generic instances are missing (a relatively unhelpful message mentioning Generic) so we are not gaining anything.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well that forces people to use NamedRoutes at the top, which is completely unnecessary if your entire API is made of records. The most direct way to serve a record of handlers is genericServe, hence my suggestion.

It'd be good to have some place that really explains those ":<|> separated" and "record" worlds and how we can go from one to the other, at all levels. But in the meantime, in the interest of giving the simplest code possible in the cookbook, without having to explain that named routes is an "adaptator" of sorts to plug records into old-style APIs, I'd recommend personally recommend genericServe (but do as you wish, this is just my opinion).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think:

serveGeneric (Proxy @MyApi) myServer

isn't so much shorter than:

serve (Proxy @(NamedRoutes MyAPI)) myServer

as to warrant the introduction of another function in the cookbook. It gives off the feeling that record APIs still somewhat live in a different world — which they now don't.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That function is already introduced in the introductory cookbook: https://docs.servant.dev/en/stable/cookbook/generic/Generic.html#server

(and even the ServerT version)

And requires appending a few chars to serve vs another pair of parens and the NamedRoutes thing.

But I also suggested to @akhesaCaro at some point that another possibility could just be to pick one and show the equivalent with the other, in a commented-out (or not, could just be with a different name) line right below.


``` haskell
movieCatalogClient :: API (AsClientT ClientM)
movieCatalogClient = client api -- remember: api :: Proxy MovieCatalogAPI
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

genericClient ?

, delete = deleteMovieHandler movieId
}
```
As you might have noticed, we build our handlers out of the same record types we used to define our API: `MoviesAPI` and `MovieAPI`. What kind of magic is this ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might fit well in the generic cookbook? Where we introduce the whole record-API machinery.

Copy link
Contributor

@gdeest gdeest Feb 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two cookbooks should IMHO be merged into a single cookbook, the non-nested / flat API case being the first section, and the nested records one expanding upon the first. So we can move this section a bit up when we do so ; for now I think it is better if the NamedRoutes cookbook remains standalone.

Copy link
Contributor

@alpmestan alpmestan Feb 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is what I have advocated in favor of as well :-) And even putting the resulting thing in the tutorial. But in the interest of splitting that up into a bunch of much smaller steps, we're first consolidating the named routes one to make it stand as a nice follow up to the generic cookbook. Then slowly but surely proceeding with the rest of the plan.

for now I think it is better if the NamedRoutes cookbook remains standalone

We'd end up with 2 cookbooks which half-explain the same basics, before covering simple APIs and nested APIs respectively. Might not be the best option for users, no?

doc/cookbook/namedRoutes/NamedRoutes.lhs Outdated Show resolved Hide resolved
@akhesaCaro akhesaCaro changed the title NamedRoutes Cookbook Cookbooks Feb 24, 2022

If you are interested in further understanding the built-in Servant combinators, see [Structuring APIs](../structuring-apis/StructuringApis.html).

Since `NamedRoutes` is based on the Generic mechanism, you might want to have a look at [Sandy Maguire’s _Thinking with Types_ book](https://doku.pub/download/sandy-maguire-thinking-with-typesz-liborgpdf-4lo5ne7kdj0x).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not nice to put a piracy link. Better link the official website: https://thinkingwithtypes.com/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants