请考虑以下数据类型:
data Get (statusCode :: Nat)
Run Code Online (Sandbox Code Playgroud)
实际上,它是来自servant的简化类型构造函数,然后在类型级API中使用,如下所示:
type API = "users" :> Verb 'GET 200 '[JSON] [User]
Run Code Online (Sandbox Code Playgroud)
出于我们的目的,我们可以将API减少到
type API = Get 200
Run Code Online (Sandbox Code Playgroud)
现在,限制状态代码Nat是太松散了,允许定义不存在的HTTP状态代码:
type API = Get 999
Run Code Online (Sandbox Code Playgroud)
因此,问题是:有没有办法限制可以应用于Get类型构造函数的自然集?
为清楚起见,我将省略代码示例中的所有编译指示和导入.
statusCode解决这个问题的一个明显方法是为状态代码定义一个单独的ADT,并使用它代替Nat利用数据类型提升.
data StatusCode = HTTP200 | HTTP201 | HTTP202
data Get (statusCode :: StatusCode)
Run Code Online (Sandbox Code Playgroud)
但是,这是一个重大变化,需要修改主要版本并重写所有用户的定义.我怀疑限制代码的好处是值得的.
此扩展允许对我们的类型变量进行直接约束
data IsStatusCode statusCode => Get (statusCode :: Nat)
Run Code Online (Sandbox Code Playgroud)
但它要求用户将约束添加到他们的所有声明中.再次,一个突破性的变化.此外,DatatypeContexts已被弃用.
我们可以Get'使用类型族从下面的示例中有条件地创建,但由于某种原因,声明类型别名可以快速编译.为了得到一个错误,我们需要构造一个这种类型的值,这也是一个突破性的变化.
data …Run Code Online (Sandbox Code Playgroud) 我正在阅读Servant 文档并遇到了这一行:
type UserAPI = "users" :> QueryParam "sortby" SortBy :> Get '[JSON] [User]
Run Code Online (Sandbox Code Playgroud)
什么是'做这一名单?
使Servant处理程序响应重定向的适当方法是什么?我正在使用导航REST应用程序,我想响应POST请求,这些请求通过重定向到相应的GET资源列表路径来创建资源.因此,例如POST/foos应该在创建foo后重定向到GET/foos.我在文档中找不到明确的方法.
我正在按照本教程http://www.parsonsmatt.org/programming/2015/06/07/servant-persistent.html通过servant创建API.我想自定义服务器以提供静态文件,但无法找到方法.
我正在使用stack构建工具.
我将Main.hs文件的运行修改为include static(run port $ static $ logger $ app cfg)并导入Network.Wai.Middleware.Static (static).我还添加wai-middleware-static >=0.7.0 && < 0.71到我的cabal文件中.
当我运行(更新:这部分完全是我的错误,我添加了封装到错误的小集团文件..跛脚导入Network.Wai.Middleware.Static作品和静态文件留在以下情况下,错误.任何人都搜索它并发现它很有用.)stack build我得到:
Could not find module ‘Network.Wai.Middleware.Static’
Perhaps you meant
Network.Wai.Middleware.Gzip (from wai-extra-3.0.7.1@waiex_GpotceEdscHD6hq9p0wPOJ)
Network.Wai.Middleware.Jsonp (from wai-extra-3.0.7.1@waiex_GpotceEdscHD6hq9p0wPOJ)
Network.Wai.Middleware.Local (from wai-extra-3.0.7.1@waiex_GpotceEdscHD6hq9p0wPOJ)
Run Code Online (Sandbox Code Playgroud)
接下来我尝试使用servant serveDirectory如下(简化):
type API = "users" :> Get '[JSON] [Person]
:<|> "static" :> Raw
server = createPerson :<|> serveDirectory "/static"
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
Couldn't match type ‘IO’ …Run Code Online (Sandbox Code Playgroud) 我正在尝试向我的servant服务器添加一个功能,该功能将从Amazon S3获取文件并将其传回给用户.因为文件可能很大,我不想在本地下载它们然后将它们提供给客户端,我宁愿将它们直接从S3流式传输到客户端.
我使用AmazonkaS3做的事情,我可以获得S3文件的流作为接收Conduit器.
但现在我不知道如何从中获取Sink到EitherT ServantErr IO a.
任何人都可以解释我该怎么做或向我展示如何做到这一点的一些例子?
我试图弄清楚如何CORS在Servant中添加响应头(基本上,设置响应头"Access-Control-Allow-Origin:*").我在下面用addHeader函数编写了一个小测试用例,但是它出错了.我将非常感谢帮助找出下面的错误.
码:
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Aeson
import GHC.Generics
import Network.Wai
import Servant
import Network.Wai.Handler.Warp (run)
import Control.Monad.Trans.Either
import Control.Monad.IO.Class (liftIO)
import Control.Monad (when, (<$!>))
import Data.Text as T
import Data.Configurator as C
import Data.Maybe
import System.Exit (exitFailure)
data User = User
{ name :: T.Text
, password :: T.Text
} deriving …Run Code Online (Sandbox Code Playgroud) 我试图将一些ByteString回传给客户端(浏览器).客户端将不知道所请求文档的内容类型,因此我尝试将适当的内容类型响应发送回客户端.该文件可以是图像或pdf或word文档等.
例如,客户端将请求/document?id=55并且服务器将使用适当的内容类型和关联的内容进行响应ByteString.
我按照这里的例子:我为图像创建了一些东西.
data IMAGE
instance Accept IMAGE where
contentType _ = "image" M.// "jpeg"
instance MimeRender IMAGE LBS.ByteString where
mimeRender _ = id
Run Code Online (Sandbox Code Playgroud)
挑战是客户端不会发送带有某些特定Accept:标头的请求,因此我无法像在此处所做的那样对适当的Mime类型做出反应.加上上面将只图像工作(假设浏览器将推断png,即使我发回jpeg),但不适合pdf,docx等.
我想过一个类似于paramaterized的类型MyDynamicContent String,我会在运行时传入内容类型,但我不确定如何声明我的API,即我将使用什么代替'[JSON].不确定这样的事情是否可能,因为示例只是一个简单的数据类型.
所以我的问题是,如果我想发送一些ByteString作为响应并Content-Type动态设置标题,那么使用它的最佳方法是什么servant
更新:我已经开了一个问题
我有以下代码从分页的API端点抓取两页数据.我想修改query函数以保持获取页面,直到它找不到更多数据(因此take 2在下面的代码中替换为查看API响应的内容).
我的问题是,可以在不改变query功能的情况下实现这一点IO.如果是这样,我该怎么做呢.如果没有,有没有办法在不编写递归函数的情况下这样做?
这是代码:
#!/usr/bin/env stack
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import Servant.Client
import Network.HTTP.Client (newManager, defaultManagerSettings)
import Data.Proxy
import Servant.API
import Data.Aeson
import GHC.Generics
-- data type
data BlogPost = BlogPost
{ id :: Integer
, title :: String
} deriving (Show, Generic)
instance FromJSON BlogPost
-- api client
type API = "posts" :> QueryParam "_page" Integer :> Get '[JSON] [BlogPost]
api :: Proxy …Run Code Online (Sandbox Code Playgroud) 我想编写 API 端点,根据传入参数和外部世界的状态返回不同的 http 代码。在python中,它看起来像以下(wsgi):
def application(environ, start_response):
if check_foo():
start_response("200 OK", [])
return b'42'
else:
start_response("201 Created", [])
return b'43'
Run Code Online (Sandbox Code Playgroud)
如何使用Servant做到这一点并不陌生:
type UserAPI = Verb 'GET 201 '[JSON] Int :<|> Verb 'GET 200 '[JSON] Int
server :: Server UserAPI
server = pure 42 :<|> pure 43
Run Code Online (Sandbox Code Playgroud)
编译并运行,但只返回 42,http 代码 201。当然,我可以用ServerError偷偷摸摸任何我想要的东西,但是这样我就失去了仆人的所有优点,并且必须自己进行序列化。
或者,我可以将 200 和 201 之间的区别推到返回数据中,但保持 http 代码的信息量对我来说很重要。
那么,有没有办法让一个端点返回不同的两个不同的 http 代码,并将它们都视为“成功”?
仆人服务器处理程序是 , 的新类型包装器ExceptT,并且具有MonadThrow, MonadCatch,MonadError等的实例。
这可能是一个有点人为的例子,但它显示了我经常面临的一个问题:
\n\n在处理程序中,我想调用三个返回的函数Either String Int,然后执行类型的计算,获取之前的Int -> Int -> Int -> IO (Either SomeError Text)三个s 。Int
我应该如何构造这段代码以确保尽早返回错误?
\n\n我看到我可以使用Either\'sMonad实例将 \xe2\x80\x9ccollapse\xe2\x80\x9d 的前三个Either String Int计算放入 eg 中Either String (Int,Int,Int),然后将IO计算绑定到某个结果值,然后用于case决定是否返回成功结果或用于throwError抛出SomeError类型(转换后?),但我希望能够执行以下操作:
f, g, h :: Either String Int\na :: Int -> Int -> Int -> IO (Either SomeError …Run Code Online (Sandbox Code Playgroud)