如何用Servant实现基于Maybe结果返回200/404的GET接口?
解决Servant中处理IO (Maybe a)返回200/404的问题
首先,咱们来拆解下你代码里的问题:你把throwError放在了IO的fmap操作里,这直接导致了类型不匹配。throwError err404是属于Handler monad的操作(因为Handler实现了MonadError ServerError类型类),但你现在是在IO上下文里调用它——IO并没有实现MonadError ServerError,更别说报错里提到的[]了。本质上是fmap期望你传入的函数返回String,但你写的逻辑返回的是Handler String,编译器自然找不到对应的类型实例。
正确的实现方式
处理这种场景的标准做法是:先把IO (Maybe String)提升到Handler monad里,然后在Handler上下文里处理Maybe值——这时候throwError就能正常工作了。
咱们来修改你的stringHandler,用最直观的do语法实现:
stringHandler :: Handler String stringHandler = do maybeStr <- liftIO ioMaybeString case maybeStr of Just s -> pure s Nothing -> throwError err404
如果喜欢更简洁的风格,也可以用>>=配合模式匹配:
stringHandler :: Handler String stringHandler = liftIO ioMaybeString >>= \case Just s -> pure s Nothing -> throwError err404
完整可编译代码
把修改后的部分整合进去,完整代码如下:
{-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} import Servant import Control.Monad.IO.Class (liftIO) import Network.Wai.Handler.Warp (run) type MaybeAPI = "maybe" :> Get '[JSON] String server :: Server MaybeAPI server = stringHandler maybeAPI :: Proxy MaybeAPI maybeAPI = Proxy app :: Application app = serve maybeAPI server stringHandler :: Handler String stringHandler = do maybeStr <- liftIO ioMaybeString case maybeStr of Just s -> pure s Nothing -> throwError err404 ioMaybeString :: IO (Maybe String) ioMaybeString = return $ Just "foo" -- 可以改成return Nothing测试404场景 runServer :: IO () runServer = run 8081 app
补充说明
你用throwError返回错误状态码的思路完全正确——Servant会自动把ServerError类型的值转换成对应的HTTP响应(比如err404就对应404 Not Found),这是Servant中处理HTTP错误的标准实践,完全没问题。
内容的提问来源于stack exchange,提问作者l7r7
相关产品推荐
相关产品推荐

