だから、私は単純な Id タイプを持っています:
newtype Id = Id String
deriving (Show, Eq, Ord, Generic)
instance ToJSON Id
instance FromJSON Id
instance FromHttpApiData Id where parseUrlPiece = Right . Id . Text.unpack
そして、そのように定義されたサーバント ルート:
type SetEntryOrder = "entries" :> "order" :> ReqBody '[JSON] [Id] :> Post '[JSON] [Id]
以下のように、ヘッダーとリクエスト本文を使用してリクエストを送信します。
POST /entries/order HTTP/1.1
Host: localhost:9090
Connection: keep-alive
Content-Length: 199
Pragma: no-cache
Cache-Control: no-cache
Origin: http://localhost:9090
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
Content-Type: application/json
Accept: */*
Referer: http://localhost:9090/
Accept-Encoding: gzip, deflate
Accept-Language: en
["0pAWSlIHH38sApt0n101X2brrCkyYp","1aaaaaaaaaaaaaaaaaaaaaaaaaaaaa","2aaaaaaaaaaaaaaaaaaaaaaaaaaaaa","7T84N81O7T84N81O7T84N81Obeu4JU","vMfOGs2LvMfOGs2LvMfOGs2LzjlQIP","j1Ew8Ju7HzAIv2yH9ohcdl9Wm2o7qx"]
しかし、次の本文で 400 が返されます (ルートはまったく入力されていません)。
Error in $: expected record (:*:), encountered Array
github サーバント リポジトリのクローンを作成し、さまざまな部分を grep しましたが、何も見つかりませんでした。
うまく機能する他のルートがたくさんあることは、おそらく注目に値するでしょう。
おそらく私のId
タイプが適切にデコードされていないと思っていましたが (Aeson はレコードか何かを予期していました)、GHCI で問題なくボンネットの下でサーバントが行うのと同じことを使用できます:
> import Servant.API.ContentTypes (eitherDecodeLenient)
> eitherDecodeLenient "[\"hello\",\"hi\"]" :: Either String [Id]
Right [Id "hello",Id "hi"]
Id タイプのカスタム JSON ハンドラーを次のように定義しても役に立ちません。
instance ToJSON Id where
toJSON (Id s) = String $ Text.pack s
instance FromJSON Id where
parseJSON (String s) = return $ Id $ Text.unpack s
parseJSON _ = empty
すっごく、なぜ Servant が Id の配列をデコードしようとして立ち往生し、私のルートに入るのではなく 400 をスローするのか、誰にもわかりませんか? :)
バージョン
スタック LTS 6.15、つまり:
GHC 7.10.3、サーバント 0.7.1、サーバント サーバ 0.7.1、エイソン 0.11.2.1
(servant-0.8.1もテストしましたが変化なし)
オリジナルコード
https://github.com/jsdw/talklicker/tree/master/server (ルート定義については Routes.hs を、Id の定義については Types.hs を参照)
アップデート!
したがって、問題は、正しいデータをルートに渡すことによって、サーバントが間違ったルートに一致して/entries/orders
いるように見えます (実際、「注文」を任意の文字列に置き換えることができ、末尾のスラッシュは違いはありません!)、私は実際に私の/entries
ルートに到達できます。別のルート ピース (例: :> "dadada"
) を SetEntryOrder に追加し、それを使用して正しいルートをターゲットにすることができます。
重複する問題のルートは次のとおりです。
type SetEntryOrder = HasSession :> "order" :> ReqBody '[JSON] [Id] :> Post '[JSON] [Id]
と
type AddEntry = HasSession :> ReqBody '[JSON] AddEntryInput :> Post '[JSON] Entry
Routes.hs ファイルの先頭で、これらの両方に「エントリ」というプレフィックスが付いていることに注意してください。なぜこれが事実なのかはまだわかりませんが、それは始まりです!
アップデート2!
問題が解決しました!実はルートが重複していたので、私のせいです!重複するルートはほとんどすべての入力を受け入れるので、私は自分で物事を難しくしました(しかし、これを忘れていました!)。ルートを交換すると修正されました。