servant-clientの新しいバージョンではステータスコードのチェックが厳密になっていました
Post
のような汎用的な名前でなく厳密なPostCreated
などを使えば解決。
問題
servant-clientを、
GHC 9.2でコンパイルするために、まだリリースされてないGitHubに上げられているバージョンに切り替えたら、とあるAPIが常にFailureResponse
例外になって呼び出せなくなりました。
原因
そのAPIは200
ではなく201
で成功を表します。
最新バージョンではどこで決定しているのかは、
Proxy
で型経由で呼び出していて複雑さに追うのをとりあえずやめたのですが、
runRequestAcceptStatus (Just [status]) req
あたりを見る限り、少なくとも成功ステータスコードを一つに絞っているようです。
解決を模索
Proxy
からstatusコードを取り出しているのならばAPI設定で、このAPIは201
を返すと指定してやれば良さそうです。
返り値Foo
を(WithStatus 201 Foo)
に変えてやることで可能?
ただ単純にWithStatus
を追加するだけだとhoistClient
した後、型がWithStatus
のついたものになってしまいます。
ステータスコードなんてAPI部分で閉じてしまって成功失敗だけ分かれば良いので解きたいですね。
そもそも呼び出してもWithStatus
がついて剥がれない…
雑にパターンマッチしろということか?
WithStatus x <- hoistClient fooApi (toRIO (config ^. fooEndpoint)) (client fooApi) req
でもこれでもエラーのまま。
よくわからないのでとりあえず型は置いといてラップしたままVerb形式をshow
してみることにします。
type FooApi
= "tokens" :> ReqBody '[JSON] FooConf :> UVerb 'POST '[JSON] '[WithStatus 201 Foo]
Post
じゃなくて全て大文字のPOST
になることに注意。
これだとUnion
やWithStatus
でラップされてますが実行できることがわかりました。後はアンラップするだけですね。
matchUnion
やfoldMapUnion
で適切にアンラップする方法がイマイチわからない…
単純な解決
なんで結果が一つかエラーだけに定まるのに、結果のUnionと私は戦っているんだと疑問になってきたので、
UじゃないVerb
を調べてみたら普通に存在しました。
-- | 'POST' with 201 status code. type PostCreated = Verb 'POST 201servant/Verbs.hs at 38f519a290da2d4eca4effc39ad96b4ab04ba80e · haskell-servant/servant
これ使って、
type FooApi
= "tokens" :> ReqBody '[JSON] FooConf :> PostCreated '[JSON] Foo
すれば何も思い悩むことはなくなります。実装も一切変更不要です。適切に検索して厳密な型を使うだけでしたね。