1
votes

The project I'm working on involve calling to CloudFlare API. I've already define the API using Servant (client) and I'm able to make a client out of it. However, CloudFlare API requires authentication headers, so all of my API types end up with duplication. Is there any way to get rid of those at the type level? I'm happy with the client derived functions require those parameters.

Example code:

type ListZones = "zones"
  :> Header "X-Auth-Email" Text
  :> Header "X-Auth-Key" Text
  :> Get '[JSON] (Result [Zone])

type ListRecords = "zones"
  :> Header "X-Auth-Email" Text
  :> Header "X-Auth-Key" Text
  :> Capture "zone_uuid" Text
  :> "dns_records"
  :> Get '[JSON] (Result [Record])

type CreateRecord = "zones"
  :> Header "X-Auth-Email" Text
  :> Header "X-Auth-Key" Text
  :> Capture "zone_uuid" Text
  :> "dns_records"
  :> ReqBody '[JSON] Record
  :> Post '[JSON] (Result Record)

type UpdateRecord = "zones"
  :> Header "X-Auth-Email" Text
  :> Header "X-Auth-Key" Text
  :> Capture "zone_uuid" Text
  :> "dns_records"
  :> Capture "record_uuid" Text
  :> ReqBody '[JSON] Record
  :> Patch '[JSON] (Result Record)
1
I suspect this cookbook recipe will be of interest: haskell-servant.readthedocs.io/en/stable/cookbook/… -- especially the part about factoring things out. - Alp Mestanogullari

1 Answers

1
votes

I believe you'll want to pull the common bits out in a similar fashion to the one outlined here: http://www.parsonsmatt.org/2018/03/14/servant_route_smooshing.html

He goes from:

type Api
    = "player" 
        :> Capture "playerId" Int 
        :> "x" 
        :> Get '[JSON] Int
    :<|> "player" 
        :> Capture "playerId" Int 
        :> "y" 
        :> Get '[JSON] Int

to

type Api'
    = "player" 
    :> Capture "playerId" Int
    :> (     "y" :> Get '[JSON] Int
        :<|> "x" :> Get '[JSON] Int
       )

which is simpler than what you need to do, but shows how to get started.

Hope that helps.