【问题标题】:Making a request inside an API endpoint in Servant在 Servant 的 API 端点内发出请求
【发布时间】:2016-02-11 13:37:53
【问题描述】:

我正在尝试使用 telegram-api 构建 Telegram 机器人。到目前为止,我没有遇到任何问题,因为我可以阅读测试以了解事情是如何工作的,但是在使用 Servant 构建 webhook 端点时遇到了很多麻烦。总体思路是,当我收到来自 webhook 的 Update 时,我会发回回复。

问题与我的postWebhook 代码有关,它希望收到Message,但收到IO Message。我认为这是因为 Servant 不希望我在该函数中发出请求,因为我的类型为 EitherT ServantError IO (IO Message)(部分由 BotHandler 应用),而实际上它应该是 EitherT ServantError IO Message

我仍在学习 Haskell,但我知道我必须以某种方式从 IO monad 中获取消息?更新BotAPI 以返回Post '[JSON] (IO Message) 给了我这个:No instance for (Foldable IO) arising from a use of ‘serve’,这超出了我的初学者知识范围,我可以看到摆弄这些类型只会将相同的问题转移到代码的不同部分。我只是不知道如何解决它。

这是删除敏感字符串的代码:

{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators     #-}

module Main where

import           Control.Monad
import           Control.Monad.Trans.Either
import           Data.Proxy
import           Data.Text                  (Text, pack)
import           Network.Wai.Handler.Warp
import           Servant
import           Web.Telegram.API.Bot

reply :: Token -> Message -> Text -> IO Message
reply token msg response = do
  Right MessageResponse { message_result = m } <-
    sendMessage token $ SendMessageRequest chatId response (Just Markdown) Nothing Nothing Nothing
  return m
  where chatId = pack . show $ chat_id (chat msg)

type BotAPI = "webhook" :> ReqBody '[JSON] Update :> Post '[JSON] Message
type BotHandler a = EitherT ServantErr IO a

botApi :: Proxy BotAPI
botApi = Proxy

initWebhook :: Token -> IO Bool
initWebhook token = do
  Right SetWebhookResponse { webhook_result = w } <-
    setWebhook token $ Just "https://example.com/webhook"
  return w

postWebhook :: Token -> Update -> BotHandler (IO Message)
postWebhook token update = case message update of
  Just msg -> return $ reply token msg "Testing!"
  Nothing -> left err400

server :: Token -> Server BotAPI
server = postWebhook

main :: IO ()
main = do
  initWebhook token
  run port $ serve botApi (server token)
  where token = Token "<token>"
        port = 8080

对于可能不是理想的 Haskell 代码,我们深表歉意。提前谢谢你:)

【问题讨论】:

  • 哇,有人在用它!

标签: haskell servant


【解决方案1】:

你的错误是在

Just msg → return $ reply token msg "Testing!"

你在

EitherT ServantErr IO Message

monad 但reply 有类型

reply :: Token → Message → Text → IO Message

然后只需 liftIO 操作到你的 monad 中,它就可以工作了

postWebhook :: Token → Update → BotHandler Message
postWebhook token update = case message update of
  Just msg → lift $ reply token msg "Testing!"
  Nothing  → left err400

(对我来说解释这里所涉及的所有事情并不容易)我认为你应该在这些复杂的例子之前多练习一下 monads、transformers 等,但你很勇敢! :)

【讨论】:

    猜你喜欢
    • 2018-12-10
    • 2017-05-05
    • 1970-01-01
    • 2015-12-24
    • 2021-06-08
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多