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

Make it easier to define more HTTP methods #190

Closed
wants to merge 7 commits into from
Closed

Make it easier to define more HTTP methods #190

wants to merge 7 commits into from

Conversation

Porges
Copy link

@Porges Porges commented Aug 12, 2015

Sending this for a bit of discussion.

This change factors out common functionality from the HasServer instances for
the various existing HTTP methods, so that there is only one real
datatype (HttpMethod) and the existing implementations are all just type
aliases for this.

This should hopefully make it near-trivial to define new HTTP methods.

I think this should be mostly source-compatible with the previous implementation?

Probably need to do something about the 'default' status codes as well (per #189).

@Porges
Copy link
Author

Porges commented Aug 12, 2015

Caution: I haven't actually tried to use this yet (stack build had some issues in the other projects about disabled components) so it's possible the entire idea is unworkable.

data Delete (contentTypes :: [*]) a
deriving Typeable

type Delete (contentTypes :: [*]) a = HttpMethod "DELETE" 200 contentTypes a
Copy link
Member

Choose a reason for hiding this comment

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

The doctest should say Delete <content-type> () (our mistake - only now are the doctests failing here because previously it'd still compile)

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I got quite confused starting out because the documentation says you can use Delete without arguments in a few places.

@jkarni
Copy link
Member

jkarni commented Aug 12, 2015

Great idea, by the way. Thanks!

@Porges
Copy link
Author

Porges commented Aug 13, 2015

Had a think about how to achieve #189 :

  1. Drop the default status code from the HttpMethod definition, so it's just the method name.
  2. Create a type family to map e.g. HttpMethod "GET" = 200, so we can preserve existing behaviour.
  3. Create a new result type ServantSucc(ess) (to go with ServantErr) defined as something like data ServantSuccess r = ServantSuccess Status r. If this is returned from a handler then the corresponding status code is used (this will be another overlap for HasServer - need to see how this plays with headers etc).
  4. Add some helpers like ok r = ServantSuccess ok200 r and created r = ServantSuccess created201 r. Then a handler looks something like handler _ = do { _; return $ created _ }

This should continue to have backwards compatibility while allowing more flexibility in status codes.

I'll write this up after work today and see how it goes.

@codedmart
Copy link
Contributor

I haven't been following along but any change I feel should allow the user to provide a status code. Regardless of what the specs say in case someone wants to provide a custome status code they should be able to. Is that where this is going?

@Porges
Copy link
Author

Porges commented Aug 13, 2015

Just realized I referenced #190 (this PR) instead of #189 in that comment - fixed. But yes, that's the idea.


import Data.Typeable (Typeable)
import GHC.TypeLits (Nat, Symbol)

Copy link
Member

Choose a reason for hiding this comment

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

Maybe some documentation saying you can use this to define your own status code response/method?

@jkarni
Copy link
Member

jkarni commented Aug 17, 2015

Looks great.

This changes the behaviour of methods to not return 204 when the type is (), as was previously the case. This is a trade-off: on the one hand, the correct thing in those cases is almost always 204; on the other, there are many other cases (sum types, more particularly) where there should be a 204 but there isn't, and thus the behaviour is incomplete and a little surprising. Also, our previous overlapping instances approach made certain things ugly (exponential blow-up in the number of instances). I'm on the fence about that change, but slightly in favour of it (not being too opinionated about things seems good). @alpmestan what do you think?

Otherwise (and aside from the small comment), this looks good to me.

@alpmestan
Copy link
Contributor

I'm really not sure about this. How wrong would it be to not give 204 when appropriate, but e.g 200 instead? Would it mess things up with external tools? Would it annoy people?

@Porges
Copy link
Author

Porges commented Aug 17, 2015

@jkarni the intention is to not remove special-casing 204 for () (and indeed, not to affect the behaviour of any existing code). The overlapping instances will still be there (but won't have n*m instances).

Porges added 7 commits August 20, 2015 08:14
This factors out common functionality from the HasServer instances for
the various existing HTTP methods, so that there is only one real
datatype (HttpMethod) and the existing implementations are all just type
aliases.

This should hopefully make it near-trivial to define new HTTP methods.
Instead we use a type family to set this, where it's needed (for
backwards compatibility).

type ServerT (Put ctypes a) m = m a
type ServerT (HttpMethod method ctypes (ServantSuccess a)) m = m (ServantSuccess a)
Copy link
Member

Choose a reason for hiding this comment

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

I like this idea. Another option maybe worth discussing is just putting in a StateT in the midst of the stack with the status code (initialized to 200 for GET, 201 for POST, 204 for (), etc.). In theory I guess we could then even remove the EitherT then (and have users themselves declare sum types when they may return very different datatypes. That would be a pretty fundamental change, though.

Copy link
Member

Choose a reason for hiding this comment

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

Hm, thinking more on it, I think we want to go in the direction of making HTTP status codes more rather than less knowable statically. (And the handlers less rather than more HTTP-aware.)

@jkarni
Copy link
Member

jkarni commented Oct 28, 2015

@Porges I like the type synonyms, but I'm not so sure about ServantSuccess. Do you want to separate out the changes, so we can discuss them independently?

EDIT: Or make this PR just about the type synonyms, and then open an issue for discussion of ServantSuccess.

@Porges
Copy link
Author

Porges commented Dec 22, 2015

Sorry about lack of movement on this - my personal laptop deaded itself and I haven't replaced it yet...

@jkarni
Copy link
Member

jkarni commented Jan 7, 2016

Closing in favour of #276 (and thanks!)

@jkarni jkarni closed this Jan 7, 2016
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.

4 participants