Is there a unit of the :<|> operator defined anywhere? I can't immediately think why it shouldn't exist, but nor can we find it.
The use case is that we're defining APIs in a handful of places and want to combine them together, but sometimes there's nothing to serve in one of the places. Clearly we can define a dummy route that returns NoContent in this situation, but a unit would seem slicker.
Cheers,
David
--
You received this message because you are subscribed to the Google Groups "haskell-servant" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-servant+unsubscribe@googlegroups.com.
To post to this group, send email to haskell-servant@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/haskell-servant/ad04b166-47cd-4093-8a88-1e1c063e85e5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
The problem that I see with a notion of unit for :<|> is that you need a unit in API types, in server handlers, in client functions and in any other place where one uses :<|>. I never could come up with a notion of unit that made sense in all those places, or even in one of them.Usually, people want a unit because they think of :<|> as an heterogeneous list, while it's actually closer to a pair. a :<|> b :<|> c ~ (a, (b, c)).Would you mind expanding on your use case, so that we can try and figure something out?
On Mon, May 15, 2017 at 7:24 PM, David Turner <dave.c...@gmail.com> wrote:
Hi,
Is there a unit of the :<|> operator defined anywhere? I can't immediately think why it shouldn't exist, but nor can we find it.
The use case is that we're defining APIs in a handful of places and want to combine them together, but sometimes there's nothing to serve in one of the places. Clearly we can define a dummy route that returns NoContent in this situation, but a unit would seem slicker.
Cheers,
David
--
You received this message because you are subscribed to the Google Groups "haskell-servant" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-serva...@googlegroups.com.
To post to this group, send email to haskell...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/haskell-servant/ad04b166-47cd-4093-8a88-1e1c063e85e5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
----Alp Mestanogullari
You received this message because you are subscribed to the Google Groups "haskell-servant" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-serva...@googlegroups.com.
To post to this group, send email to haskell...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/haskell-servant/CADZnDvBcafaOh%3D1BX3%2B13VUKey-_jKUSJp9tHwV%3Dotto7ZpsKg%40mail.gmail.com.
The problem is that we have some endpoints that should be POST endpoints, but some clients (SmartTVs in our case) surprisingly don't support POST. Other clients have some weird settings, driving POST unreasonable for them to use. So for a part of our API we have a GET endpoint for every POST endpoint. This means that we need to duplicate everything — API types, server handlers, client functions.
To avoid this code duplication it would be nice to use Verb with a list of methods. In fact Verb is already poly-kinded and we can use a list of methods already:
type PostGet = Verb '[POST, GET] 200For a server we can probably write something like this (untested): https://gist.github.com/fizruk/3bc23c90a33cd85f0e55167355ca6bdaThere's an obvious corner case for Verb '[] and that'd be exactly the same as a unit for :<|>.
Also Verb '[method] would be equivallent to Verb method.As you can see, handling Verb '[] is not really important for our project since we're only dealing with non-empty lists. However I still see the point in having empty API.Just like David, we combine our API from a set of subAPIs which can have subAPIs of their own. When designing APIs it's sometimes known that there would be a certain subAPI, but its form is not defined yet. E.g.:type MyAPI= "books" :> BooksAPI:<|> "services" :> ServicesAPItype BooksAPI = ... -- some defined APItype ServicesAPI = EmptyAPI -- we're not sure what is going to be hereCurrently one would have to resort to something liketype ServicesAPI = Get '[JSON] NoContentWhich does not describe well what's going on.With EmptyAPI we can even add an optional type-level checker that'll ensure that there are no EmptyAPIs left.
To address Alp's concerns about instances (interpretations):
- I think that to serve an empty API is to always fail (with 404). That way when you combine empty API with :<|> you immediately consider a non-empty part.
- A Haskell client for an empty API is something isomorphic to (). E.g. data NoClient = NoClient
- A JS client for an empty API would consist of no functions (empty module).
- Documentation for an empty API is empty documentation with no endpoints.
Overall I think empty API can and should be a logically consistent part of Servant. There might be more nice uses for it. I would think there might be some uses in (whole) API manipulation functions.
Kind regards,Nick
On Mon, 15 May 2017 at 20:35 Alp Mestanogullari <alpm...@gmail.com> wrote:
The problem that I see with a notion of unit for :<|> is that you need a unit in API types, in server handlers, in client functions and in any other place where one uses :<|>. I never could come up with a notion of unit that made sense in all those places, or even in one of them.Usually, people want a unit because they think of :<|> as an heterogeneous list, while it's actually closer to a pair. a :<|> b :<|> c ~ (a, (b, c)).Would you mind expanding on your use case, so that we can try and figure something out?
On Mon, May 15, 2017 at 7:24 PM, David Turner <dave.c...@gmail.com> wrote:
Hi,
Is there a unit of the :<|> operator defined anywhere? I can't immediately think why it shouldn't exist, but nor can we find it.
The use case is that we're defining APIs in a handful of places and want to combine them together, but sometimes there's nothing to serve in one of the places. Clearly we can define a dummy route that returns NoContent in this situation, but a unit would seem slicker.
Cheers,
David
--
You received this message because you are subscribed to the Google Groups "haskell-servant" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-servant+unsubscribe@googlegroups.com.
To post to this group, send email to haskell-servant@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/haskell-servant/ad04b166-47cd-4093-8a88-1e1c063e85e5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
----Alp Mestanogullari
You received this message because you are subscribed to the Google Groups "haskell-servant" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-servant+unsubscribe@googlegroups.com.
To post to this group, send email to haskell-servant@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/haskell-servant/CADZnDvBcafaOh%3D1BX3%2B13VUKey-_jKUSJp9tHwV%3Dotto7ZpsKg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Couldn't you do some type-level and value-level transformations to do the duplication for you? You'd write the "sane" API and have some code inserting the GET-equivalents of each POST endpoint for you. It's admittedly not exactly trivial to do it, but allows you to simply build on top of the existing servant DSL.
Verb '[] would mean "any method" I guess?
This is the bit I dislike the most I think. While for the other interpretations you can rely on some kind of `mempty` (empty docs, empty JS module, dummy server), this one just feels hacky to me. It makes no sense to me that we could derive something that we can't use. I think I'd prefer a solution where Client does not do anything on EmptyAPI. It's easy if you have say, 'Client (foo :<|> EmptyAPI), where you could just say it's 'Client foo', but what if you just ask for 'Client EmptyAPI'?
A client for EmptyAPI should do nothing; a server for EmptyAPI should never succeed. So I'd guess:
`Client EmptyAPI = ()`
`ServerT EmptyAPI m = m Void`