Closed vitalibarozzi closed 4 years ago
@vitalibarozzi your handler expects json payload and you send plain value 666
try valid json {..}
. Most probably servant fallback to plain text on wrong content type or conversion failure.
You can use Capture
and handle incoming Int as REST-like path parameter
I used a number here to make it shorter, but it has the same behaviour with a proper json object.
E.g.: `{-# LANGUAGE TypeOperators #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE DeriveGeneric #-}
module Main where
import Data.Proxy (Proxy(..)) import Data.Text (Text, append) import Servant import Servant.Server (serveSnap) import Snap.Http.Server (quickHttpServe) import Data.Aeson import GHC.Generics
data MyData = MyData { user :: String , pass :: String } deriving stock Generic deriving anyclass (FromJSON, ToJSON)
type Api = ReqBody '[JSON] MyData :> Post '[JSON] MyData
api = Proxy :: Proxy Api
main = quickHttpServe $ serveSnap api return`
and with curl:
curl -i -X POST -H "Content-Type: application/json" -d '{"user":"bar","pass":"foo"}' http://localhost:8000
ir returns 415
but with:
curl -i -X POST -H "Content-Type: application/json;=" -d '{"user":"bar","pass":"foooo"}' http://localhost:8000
it works as expected.
I'm going to avoid using the body for now and comeback to this eventually. Bu what puzzles me is that it works if i add anything with =
or even several =.
I've come to this result by trying to add charset=utf-8 to the end of the content-type, and shrink from there to the = sign only.
I can confirm the problem. Having "application/json; charset=utf-8" in a Content-Type header works but having "application/json" doesn't and results in a 415 error code when sending a json payload.
Hey there. I ran into this bug recently and it was quite surprising - this seems like quite a core bug. I can take a look at trying to fix if you point in the right direction.
As an aside, should I be using servant-snap? I saw some mention of attempting to have servant-snap be the intended usage of servant?
@santiweight Thank you for bumping this issue - it's definitely surprising! I see that 4 years ago I updated the test suite to set charset=utf-8
for every Content-Type
header in the test suite, and I didn't document why.
I'll first try to reproduce the issue locally, then I'll try to reproduce it for POST
endpoints (a GET
should not have a request body, so I wonder if servant's aberrant support of GET/ReqBody is involved).
Thank you for the quick help :) This is a great fix!
I think this will be fixed by https://github.com/haskell-servant/servant-snap/pull/31
Looking at the code before this change, I really don't see how it ever could have worked with Content-Type: application/json
. Changing the test-suites to accommodate the unintended requirement on charset=utf-8
masked this problem for years. It's one of those cases where you look at your old habits and can only shake your head. Hopefully I've learned something for next time :)
Given:
`type Api = ReqBody '[JSON] Int :> Get '[JSON] Int
api = Proxy :: Proxy Api
main = quickHttpServe (serveSnap api return)`
with:
curl -i -X GET -H "Content-Type: application/json" -d '666' http://localhost:8000/
i get back a "415 Unsupported Media Type", witch is weird to me. But if i try:
curl -i -X GET -H "Content-Type: application/json;foo=bar" -d '666' http://localhost:8000/
or even:
curl -i -X GET -H "Content-Type: application/json;=" -d '666' http://localhost:8000/
ir returns the expected 666. I don't understand why. Any clues?