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

additional instances of HasServer and HasClient for Throwing in apis that set Headers #4

Open
cdepillabout opened this issue May 2, 2017 · 4 comments

Comments

@cdepillabout
Copy link
Owner

cdepillabout commented May 2, 2017

Right now there are only a few instances of HasServer and HasClient for Throws and Throwing.

It would be nice to have more.

These should be relatively easy to write.

@cdepillabout
Copy link
Owner Author

I think this should be mostly fixed with #6.

I think the only thing left is to handle apis that set Headers.

@cdepillabout
Copy link
Owner Author

cdepillabout commented Nov 19, 2017

Today I tried to add support for handling APIs that set Headers, but I have run into some difficulty.

Here is the existing instance for Throwing:

-- | When @'Throwing' es@ comes before a 'Verb', change it into the same 'Verb'
-- but returning an @'Envelope' es@.
instance
    {-# OVERLAPPABLE #-}
    (HasServer (Verb method status ctypes (Envelope es a)) context) =>
    HasServer (Throwing es :> Verb method status ctypes a) context where

  type ServerT (Throwing es :> Verb method status ctypes a) m =
    ServerT (Verb method status ctypes (Envelope es a)) m

  route
    :: Proxy (Throwing es :> Verb method status ctypes a)
    -> Context context
    -> Delayed env (ServerT (Verb method status ctypes (Envelope es a)) Handler)
    -> Router env
  route _ = route (Proxy :: Proxy (Verb method status ctypes (Envelope es a)))

I tried to add an additional instance for use with Headers that looks like this:

instance
    {-# OVERLAPPING #-}
    (HasServer (Verb method status ctypes (Headers h (Envelope es a))) context) =>
    HasServer (Throwing es :> Verb method status ctypes (Headers h a)) context where

  type ServerT (Throwing es :> Verb method status ctypes (Headers h a)) m =
    ServerT (Verb method status ctypes (Headers h (Envelope es a))) m

  route
    :: Proxy (Throwing es :> Verb method status ctypes (Headers h a))
    -> Context context
    -> Delayed
         env
         ( ServerT
           (Verb method status ctypes (Headers h (Envelope es a)))
           Handler
         )
    -> Router env
  route _ =
    route (Proxy :: Proxy (Verb method status ctypes (Headers h (Envelope es a))))

However, this is failing with the following error:

src/Servant/Checked/Exceptions/Internal/Servant/Server.hs:61:8: error:
    Conflicting family instance declarations:

      forall k1 a (ctypes :: [*]) (status :: Nat) (method :: k1) (es :: [*]) (m :: * -> *).
        ServerT (Throwing es :> Verb method status ctypes a) m =
            ServerT (Verb method status ctypes (Envelope es a)) m
      -- Defined at src/Servant/Checked/Exceptions/Internal/Servant/Server.hs:61:8

      forall k1 a (h :: [*]) (ctypes :: [*]) (status :: Nat) (method :: k1) (es :: [*]) (m :: * -> *).
        ServerT (Throwing es :> Verb method status ctypes (Headers h a)) m =
            ServerT (Verb method status ctypes (Headers h (Envelope es a))) m
      -- Defined at src/Servant/Checked/Exceptions/Internal/Servant/Server.hs:80:8

Here are some links related to this error:

It doesn't look like there is an easy way to fix this.

@alpmestan
Copy link

Right, when type families conflict that much their answers have to "be compatible".

I'm thinking it might be worth putting all our brainpower on haskell-servant/servant#841 instead of fighting that kind of problem =) If we re-engineer Verb to allow us to specify an (optional) list of "sad paths" in addition to the happy path that it knows about at the moment, we might get the best of both worlds and get rid once and for all of all those overlapping instances, if we play our moves right.

@cdepillabout cdepillabout changed the title additional instances of HasServer and HasClient additional instances of HasServer and HasClient for Headers Jun 21, 2019
@cdepillabout cdepillabout changed the title additional instances of HasServer and HasClient for Headers additional instances of HasServer and HasClient for Throwing in apis that set Headers Jun 21, 2019
@cdepillabout
Copy link
Owner Author

It looks like servant-auth defines a single type class and related type family for determining how to modify the response type to add headers:

https://www.stackage.org/haddock/lts-13.26/servant-auth-server-0.4.4.0/Servant-Auth-Server.html#t:HasServer

https://www.stackage.org/haddock/lts-13.26/servant-auth-server-0.4.4.0/Servant-Auth-Server-Internal-AddSetCookie.html#t:AddSetCookies

I wonder if something similar to this could be adopted for servant-checked-exceptions.

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

No branches or pull requests

2 participants