Custom headers for servant client

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Custom headers for servant client

Duy Vo
Hi,

I am using servant client to consume a REST API. The problem is that all requests must set a custom header to authenticate with the server.

Right now the way i do it look something likes this:


type API
= "users" :> Header "Accept" String :> Get '[JSON] [User]
               :<|> "posts" :> Header "Accept" String :> Get '
[JSON] [Post]

api
:: Proxy Api
api
= Proxy

getUsers
:: Maybe Text -> ClientM [User]
getPosts
:: Maybe Text -> ClientM [Post]

getUsers
:<|> getPosts = client api


Then when calls the api, `getUsers` and `getPosts` receive the same `Just "application/json"` as parameter.

So my question is can i set the header somewhere that can effect all api calls?

I have an idea that `client api` will return a `a :<|> b :<|> c` so if we can do something likes fmap (someone pointed me to enter https://hackage.haskell.org/package/servant-0.10/docs/Servant-Utils-Enter.html#v:enter) then we can inject the header before pattern matching back to `getUsers :<|> getPosts`.

Thanks

--
Reply | Threaded
Open this post in threaded view
|

Re: Custom headers for servant client

Alp Mestanogullari
Hello,

I put together a solution to the particular problem that you have, which is: I have a bunch of functions separated by :<|>s (e.g what's returned by 'client' in your example) but that all take the same (first of potentially many) argument type, e.g (+1) :<|> (*10). How can I apply them all to a given value and get back a bunch of answers separated by as many :<|>s as there was in the input, with the very same structure?

The code is at http://lpaste.net/352272

Feel free to ask any question about it, I'll do my best to explain.

On Thu, Feb 9, 2017 at 12:31 PM, Duy Vo <[hidden email]> wrote:
Hi,

I am using servant client to consume a REST API. The problem is that all requests must set a custom header to authenticate with the server.

Right now the way i do it look something likes this:


type API
= "users" :> Header "Accept" String :> Get '[JSON] [User]
               :<|> "posts" :> Header "Accept" String :> Get '
[JSON] [Post]

api
:: Proxy Api
api
= Proxy

getUsers
:: Maybe Text -> ClientM [User]
getPosts
:: Maybe Text -> ClientM [Post]

getUsers
:<|> getPosts = client api


Then when calls the api, `getUsers` and `getPosts` receive the same `Just "application/json"` as parameter.

So my question is can i set the header somewhere that can effect all api calls?

I have an idea that `client api` will return a `a :<|> b :<|> c` so if we can do something likes fmap (someone pointed me to enter https://hackage.haskell.org/package/servant-0.10/docs/Servant-Utils-Enter.html#v:enter) then we can inject the header before pattern matching back to `getUsers :<|> getPosts`.

Thanks

--



--
Alp Mestanogullari

--
Reply | Threaded
Open this post in threaded view
|

Re: Custom headers for servant client

Duy Vo
In reply to this post by Duy Vo
Thanks Alp, It looks like what i am looking for.

But Functions, Func is a bit difficult for me to understand (i am new to Haskell). Can you give me some quick explain and keyword on it. Does applyTo has something to do with Applicative?

Thank you

On Thursday, February 9, 2017 at 6:31:01 PM UTC+7, Duy Vo wrote:
Hi,

I am using servant client to consume a REST API. The problem is that all requests must set a custom header to authenticate with the server.

Right now the way i do it look something likes this:


type API
= "users" :> Header "Accept" String :> Get '[JSON] [User]
               :<|> "posts" :> Header "Accept" String :> Get '
[JSON] [Post]

api
:: Proxy Api
api
= Proxy

getUsers
:: Maybe Text -> ClientM [User]
getPosts
:: Maybe Text -> ClientM [Post]

getUsers
:<|> getPosts = client api


Then when calls the api, `getUsers` and `getPosts` receive the same `Just "application/json"` as parameter.

So my question is can i set the header somewhere that can effect all api calls?

I have an idea that `client api` will return a `a :<|> b :<|> c` so if we can do something likes fmap (someone pointed me to enter <a href="https://hackage.haskell.org/package/servant-0.10/docs/Servant-Utils-Enter.html#v:enter" target="_blank" rel="nofollow" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fhackage.haskell.org%2Fpackage%2Fservant-0.10%2Fdocs%2FServant-Utils-Enter.html%23v%3Aenter\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGABMiiclKNtM-PKBcPMu7093oM5A&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fhackage.haskell.org%2Fpackage%2Fservant-0.10%2Fdocs%2FServant-Utils-Enter.html%23v%3Aenter\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGABMiiclKNtM-PKBcPMu7093oM5A&#39;;return true;">https://hackage.haskell.org/package/servant-0.10/docs/Servant-Utils-Enter.html#v:enter) then we can inject the header before pattern matching back to `getUsers :<|> getPosts`.

Thanks

--
Reply | Threaded
Open this post in threaded view
|

Re: Custom headers for servant client

Alp Mestanogullari
Alright, given that you're new to Haskell, you may have a little bit of trouble understanding all of the code in that paste for now, but let me regardless explain what it does.

Our goal is to be able to have a function, "applyTo", which given some value of type 'a', will go into chains of :<|>s, where each component is of type (a -> something), and apply whatever functions it finds in there to that value of type 'a'. 'something' can be different from a component to another.

By the way, this 'applyTo' is really the only thing you should care about, everything above it in the paste is just "implementation details". Let's however look at those too, so that you get an intuition of what happens there.

First, the 'Func' class.

> class Func t where
>   type Arg t :: *
>   type Out t :: *
>   funcOf :: t -> Functions (Arg t) t (Out t)

This represents the types of things that "expect an argument of a given type" (and therefore return something of some type, too), that are "function-like" if you will. In our case, we will have two instances: good old functions and chains of functions separated by :<|>s where the type of the argument of those functions is the same accross the entire chain, so e.g a function Int -> String, a function Int -> Bool and a function Int -> [[[Int]]]. Or, in your case, functions of type Maybe String -> something, as all your endpoints depend on the value of the Accept header.

The 'Arg' and 'Out' type families are technical details, but let's just say that for a given 't' for which we'll instantiate Func, we will say "here's the type of the argument this whole thing takes" and here's the type returned by this whole thing after we've applied the argument to that function-like thing".

But what's this 'Functions' type?

> data Functions a t t' where
>   One :: (a -> b) -> Functions a (a -> b) b
>   More :: Functions a t1 t1'
>        -> Functions a t2 t2'
>        -> Functions a (t1 :<|> t2) (t1' :<|> t2')

This is using GADT syntax, and involves some type trickery, but the purpose of this data type is to express what a "function like" thing is precisely, what this whole concept boils down to.

A function-like thing is
- either a single function (the 'One' constructor), which given a function 'a -> b' creates a 'Functions a (a -> b) b'. You see that we explicitly make the input and return types parameters of our 'Function' type,
- or two "function like things" put together. They can have different types in them as long as the input type match (the 'a' in the 'More' constructor).

The first constructor, One, basically allows us to say "a normal function is a function like thing".

The second constructor, More, allows us to say that if we have two function like things, say functionLike1 and functionLike2, that take the same type of argument, then 'More functionLike1 functionLike2' is a function like thing too, and it has some fancy type that tracks the input and output type of everyone and make sure we only accept things that make sense.

Now, the Func instances...

> instance Func (a -> b) where
>   type Arg (a -> b) = a
>   type Out (a -> b) = b
>   funcOf = One

This simply says that a normal function 'a -> b' is a function like thing in the following way:
- its input is of type 'a'
- its output is of type 'b'
- it can be mapped to our 'Functions' data type by using the 'One' constructor. 'funcOf' shoehorns both normal functions and chains of :<|>-separated functions into this concept of 'function like thing'.

Now, the fancier instance:

> instance (Func t, Func t', Arg t ~ Arg t')
>       => Func (t :<|> t') where
>   type Arg (t :<|> t') = Arg t
>   type Out (t :<|> t') = Out t :<|> Out t'
>   funcOf (t :<|> t') = More (funcOf t) (funcOf t')

It says that if we have two "function like things" t and t', and that they take the same type of input (Arg t ~ Arg t'   means Arg t must be equal to Arg t'), then we can consider t :<|> t' as a function like thing too, in the following way:
- the input type for both t and t' being the same, we can simply take a single argument of that type and make it the input to both of our "function like things".
- the output type of " t :<|> t' " is " output-type-of-t :<|> output-type-of-t' "; i.e we simply group together with :<|> the result of t and t'
- to represent t :<|> t' using our 'Functions' data type, we use the 'More' constructor (the Arg t ~ Arg t' bit allows us to, because the 'More' constructor will see that t and t' have the same input type), by storing the result of recursively calling 'funcOf' on t and t'. Put in a simpler way, if we have two "function like things" (which can therefore be represented as a value of type 'Functions a t b'), then we represent t :<|> t' using More representation-of-t representation-of-t'.

Finally, the code that actually matters:

> runFunctions :: Functions a t b -> a -> b
> runFunctions (One f) x = f x
> runFunctions (More f1 f2) x =
>   runFunctions f1 x :<|> runFunctions f2 x
>
> applyTo :: Func t => Arg t -> t -> Out t
> applyTo arg t = runFunctions (funcOf t) arg

runFunctions takes a 'Functions a t b' value (recall that a = input type, t = type of the function like thing, b = return type) along with some input of type 'a', and returns a 'b'. It does so by handling the "just a normal function" and "two function like things put together" cases separately.

applyTo finally wraps it all up and calls 'runFunctions' on the representation of any "function like thing", which can be a simple function or many of them separated by :<|>s.

I suspect a lot of the technical details will be a bit hard to understand and I'm not claiming any of this is simple. It took me some time to be able to understand that kind of code, and even more time to be able to write it. Please do not feel intimidated by any of this. You'll understand it all eventually (if it's not already the case).

All you need to do to use it is stick that code in some module of your project, and just use 'applyTo' when you need it. It's unfortunate that one has to go through these hoops to do something so simple, yes. I'm hoping future servant versions will have ready to use functions out of the box to answer those needs, or better, a more general solution for traversing and transforming "chains of :<|> separated stuffs" with just a few simple and approachable functions.

On Thu, Feb 9, 2017 at 2:47 PM, Duy Vo <[hidden email]> wrote:
Thanks Alp, It looks like what i am looking for.

But Functions, Func is a bit difficult for me to understand (i am new to Haskell). Can you give me some quick explain and keyword on it. Does applyTo has something to do with Applicative?

Thank you

On Thursday, February 9, 2017 at 6:31:01 PM UTC+7, Duy Vo wrote:
Hi,

I am using servant client to consume a REST API. The problem is that all requests must set a custom header to authenticate with the server.

Right now the way i do it look something likes this:


type API
= "users" :> Header "Accept" String :> Get '[JSON] [User]
               :<|> "posts" :> Header "Accept" String :> Get '
[JSON] [Post]

api
:: Proxy Api
api
= Proxy

getUsers
:: Maybe Text -> ClientM [User]
getPosts
:: Maybe Text -> ClientM [Post]

getUsers
:<|> getPosts = client api


Then when calls the api, `getUsers` and `getPosts` receive the same `Just "application/json"` as parameter.

So my question is can i set the header somewhere that can effect all api calls?

I have an idea that `client api` will return a `a :<|> b :<|> c` so if we can do something likes fmap (someone pointed me to enter https://hackage.haskell.org/package/servant-0.10/docs/Servant-Utils-Enter.html#v:enter) then we can inject the header before pattern matching back to `getUsers :<|> getPosts`.

Thanks

--



--
Alp Mestanogullari

--
Reply | Threaded
Open this post in threaded view
|

Re: Custom headers for servant client

Duy Vo
Thank you very much, i think i get the idea now :D

On Thursday, February 9, 2017 at 10:17:57 PM UTC+7, Alp Mestanogullari wrote:
Alright, given that you're new to Haskell, you may have a little bit of trouble understanding all of the code in that paste for now, but let me regardless explain what it does.

Our goal is to be able to have a function, "applyTo", which given some value of type 'a', will go into chains of :<|>s, where each component is of type (a -> something), and apply whatever functions it finds in there to that value of type 'a'. 'something' can be different from a component to another.

By the way, this 'applyTo' is really the only thing you should care about, everything above it in the paste is just "implementation details". Let's however look at those too, so that you get an intuition of what happens there.

First, the 'Func' class.

> class Func t where
>   type Arg t :: *
>   type Out t :: *
>   funcOf :: t -> Functions (Arg t) t (Out t)

This represents the types of things that "expect an argument of a given type" (and therefore return something of some type, too), that are "function-like" if you will. In our case, we will have two instances: good old functions and chains of functions separated by :<|>s where the type of the argument of those functions is the same accross the entire chain, so e.g a function Int -> String, a function Int -> Bool and a function Int -> [[[Int]]]. Or, in your case, functions of type Maybe String -> something, as all your endpoints depend on the value of the Accept header.

The 'Arg' and 'Out' type families are technical details, but let's just say that for a given 't' for which we'll instantiate Func, we will say "here's the type of the argument this whole thing takes" and here's the type returned by this whole thing after we've applied the argument to that function-like thing".

But what's this 'Functions' type?

> data Functions a t t' where
>   One :: (a -> b) -> Functions a (a -> b) b
>   More :: Functions a t1 t1'
>        -> Functions a t2 t2'
>        -> Functions a (t1 :<|> t2) (t1' :<|> t2')

This is using GADT syntax, and involves some type trickery, but the purpose of this data type is to express what a "function like" thing is precisely, what this whole concept boils down to.

A function-like thing is
- either a single function (the 'One' constructor), which given a function 'a -> b' creates a 'Functions a (a -> b) b'. You see that we explicitly make the input and return types parameters of our 'Function' type,
- or two "function like things" put together. They can have different types in them as long as the input type match (the 'a' in the 'More' constructor).

The first constructor, One, basically allows us to say "a normal function is a function like thing".

The second constructor, More, allows us to say that if we have two function like things, say functionLike1 and functionLike2, that take the same type of argument, then 'More functionLike1 functionLike2' is a function like thing too, and it has some fancy type that tracks the input and output type of everyone and make sure we only accept things that make sense.

Now, the Func instances...

> instance Func (a -> b) where
>   type Arg (a -> b) = a
>   type Out (a -> b) = b
>   funcOf = One

This simply says that a normal function 'a -> b' is a function like thing in the following way:
- its input is of type 'a'
- its output is of type 'b'
- it can be mapped to our 'Functions' data type by using the 'One' constructor. 'funcOf' shoehorns both normal functions and chains of :<|>-separated functions into this concept of 'function like thing'.

Now, the fancier instance:

> instance (Func t, Func t', Arg t ~ Arg t')
>       => Func (t :<|> t') where
>   type Arg (t :<|> t') = Arg t
>   type Out (t :<|> t') = Out t :<|> Out t'
>   funcOf (t :<|> t') = More (funcOf t) (funcOf t')

It says that if we have two "function like things" t and t', and that they take the same type of input (Arg t ~ Arg t'   means Arg t must be equal to Arg t'), then we can consider t :<|> t' as a function like thing too, in the following way:
- the input type for both t and t' being the same, we can simply take a single argument of that type and make it the input to both of our "function like things".
- the output type of " t :<|> t' " is " output-type-of-t :<|> output-type-of-t' "; i.e we simply group together with :<|> the result of t and t'
- to represent t :<|> t' using our 'Functions' data type, we use the 'More' constructor (the Arg t ~ Arg t' bit allows us to, because the 'More' constructor will see that t and t' have the same input type), by storing the result of recursively calling 'funcOf' on t and t'. Put in a simpler way, if we have two "function like things" (which can therefore be represented as a value of type 'Functions a t b'), then we represent t :<|> t' using More representation-of-t representation-of-t'.

Finally, the code that actually matters:

> runFunctions :: Functions a t b -> a -> b
> runFunctions (One f) x = f x
> runFunctions (More f1 f2) x =
>   runFunctions f1 x :<|> runFunctions f2 x
>
> applyTo :: Func t => Arg t -> t -> Out t
> applyTo arg t = runFunctions (funcOf t) arg

runFunctions takes a 'Functions a t b' value (recall that a = input type, t = type of the function like thing, b = return type) along with some input of type 'a', and returns a 'b'. It does so by handling the "just a normal function" and "two function like things put together" cases separately.

applyTo finally wraps it all up and calls 'runFunctions' on the representation of any "function like thing", which can be a simple function or many of them separated by :<|>s.

I suspect a lot of the technical details will be a bit hard to understand and I'm not claiming any of this is simple. It took me some time to be able to understand that kind of code, and even more time to be able to write it. Please do not feel intimidated by any of this. You'll understand it all eventually (if it's not already the case).

All you need to do to use it is stick that code in some module of your project, and just use 'applyTo' when you need it. It's unfortunate that one has to go through these hoops to do something so simple, yes. I'm hoping future servant versions will have ready to use functions out of the box to answer those needs, or better, a more general solution for traversing and transforming "chains of :<|> separated stuffs" with just a few simple and approachable functions.

On Thu, Feb 9, 2017 at 2:47 PM, Duy Vo <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="NuG-GM_aCQAJ" rel="nofollow" onmousedown="this.href=&#39;javascript:&#39;;return true;" onclick="this.href=&#39;javascript:&#39;;return true;">voanhd...@...> wrote:
Thanks Alp, It looks like what i am looking for.

But Functions, Func is a bit difficult for me to understand (i am new to Haskell). Can you give me some quick explain and keyword on it. Does applyTo has something to do with Applicative?

Thank you

On Thursday, February 9, 2017 at 6:31:01 PM UTC+7, Duy Vo wrote:
Hi,

I am using servant client to consume a REST API. The problem is that all requests must set a custom header to authenticate with the server.

Right now the way i do it look something likes this:


type API
= "users" :> Header "Accept" String :> Get '[JSON] [User]
               :<|> "posts" :> Header "Accept" String :> Get '
[JSON] [Post]

api
:: Proxy Api
api
= Proxy

getUsers
:: Maybe Text -> ClientM [User]
getPosts
:: Maybe Text -> ClientM [Post]

getUsers
:<|> getPosts = client api


Then when calls the api, `getUsers` and `getPosts` receive the same `Just "application/json"` as parameter.

So my question is can i set the header somewhere that can effect all api calls?

I have an idea that `client api` will return a `a :<|> b :<|> c` so if we can do something likes fmap (someone pointed me to enter <a href="https://hackage.haskell.org/package/servant-0.10/docs/Servant-Utils-Enter.html#v:enter" rel="nofollow" target="_blank" onmousedown="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fhackage.haskell.org%2Fpackage%2Fservant-0.10%2Fdocs%2FServant-Utils-Enter.html%23v%3Aenter\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGABMiiclKNtM-PKBcPMu7093oM5A&#39;;return true;" onclick="this.href=&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fhackage.haskell.org%2Fpackage%2Fservant-0.10%2Fdocs%2FServant-Utils-Enter.html%23v%3Aenter\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNGABMiiclKNtM-PKBcPMu7093oM5A&#39;;return true;">https://hackage.haskell.org/package/servant-0.10/docs/Servant-Utils-Enter.html#v:enter) then we can inject the header before pattern matching back to `getUsers :<|> getPosts`.

Thanks

--



--
Alp Mestanogullari

--