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

Get '[JSON] does not imply a header Accept: application/json #1715

Open
alt-romes opened this issue Nov 20, 2023 · 4 comments
Open

Get '[JSON] does not imply a header Accept: application/json #1715

alt-romes opened this issue Nov 20, 2023 · 4 comments

Comments

@alt-romes
Copy link
Contributor

I am using servant-client to request JSON information from the hackage API, but it turns out that specifying '[JSON] in the Get request will not add a header Accept: application/json to the Request, even though requestAccept seems to have the correct application types.

Here's a reproducer:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
module Main where

import GHC.Generics
import Data.Proxy
import Data.Aeson
import Servant.API
import Network.HTTP.Client (newManager, defaultManagerSettings, requestHeaders)
import Servant.Client

data Package
  = Package
    { packageName :: String
    , downloads :: Int
    }
    deriving stock Show
    deriving stock Generic
    deriving anyclass FromJSON

type API = "top" :> Get '[JSON] [Package]

getTop :: ClientM [Package]
getTop = client (Proxy @API)

main :: IO ()
main = do
  manager' <- newManager defaultManagerSettings
  let clientEnv = mkClientEnv manager' (BaseUrl Http "hackage.haskell.org" 80 "packages")
  res <- runClientM getTop (clientEnv{makeClientRequest = \b r -> makeClientRequest clientEnv b r >>=
                                                            \r' -> return r'{requestHeaders = [("Accept", "application/json")]}})
  case res of
    Left err -> putStrLn $ "Error: " ++ show err
    Right packages -> print packages

with build-depends: base, servant, servant-client, aeson, http-client

Expected behaviour

I was expecting the Accept: application/json to be automatically added to the request, since I'm using a Get request and JSON as the decoding format.

@tchoutri
Copy link
Contributor

tchoutri commented Apr 2, 2024

@alt-romes Quite unfortunately your code works perfectly fine on my machine, which confirms my theory that Hackage is a bad HTTP server to query. Not too sure what can be done at Servant's level, since we put the right headers (https://hackage.haskell.org/package/servant-0.20.1/docs/src/Servant.API.ContentTypes.html#line-134).

PS: download numbers on Hackage are unreliable because it doesn't use the data from its CDN, so the numbers are not representative at all of any kind of trend (except perhaps that a package has been downloaded at least once).

@alt-romes
Copy link
Contributor Author

I don't recall if I analyzed the request generated by servant. Perhaps one could look to see whether Get '[JSON] [Package] is sufficient to add the correct header to the request.

I see now that my reproducer may be wrong in the sense that it is the one that works. If you remove the part where requestHeaders is manually edited to introduce the needed header, does it still work?

@tchoutri
Copy link
Contributor

tchoutri commented Apr 2, 2024

Ah, how quaint! I'll toy with your code and hit httpbin.org to see where it fails.

@tchoutri
Copy link
Contributor

tchoutri commented Apr 2, 2024

Hmm I'm not seeing anything explicitly wrong in this result:

{
  "headers": {
    "Accept": "application/json;charset=utf-8,application/json", 
    "Accept-Encoding": "gzip", 
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-660c6e2c-75bb6dfc08b3f13056f4c4d0"
  }
}

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