如何在Servant中复用API类型并传递多段路径参数?
解决Servant框架中复用API类型传递多段路径的问题
问题根源
- 直接传递
"hello/world"会被Servant当作单段路径,无法正确拆分; ("hello" :> "world")的kind是Type -> Type(需要后续拼接API终点),但原MyAPI定义要求第一个参数为Type,导致类型不匹配;- 未开启必要扩展时,Haskell不允许将部分应用的类型构造器作为参数传递。
可行解决方案
方案1:调整API类型参数为类型构造器(推荐)
开启PolyKinds扩展,让API接受Type -> Type类型的构造器参数,直接拼接多段路径:
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE PolyKinds #-} import Servant.API -- 复用的API类型,endpointTail为类型构造器(Type -> Type) type MyAPI (endpointTail :: Type -> Type) result = "blah" :> Capture "a" A :> endpointTail (Get '[JSON] result) -- 定义多段路径的构造器 type HelloWorldTail t = "hello" :> "world" :> t -- 使用示例:单段/多段路径均支持 type MyHelloAPI = MyAPI ("hello" :> ) HelloT -- 单段路径,用部分应用的:> type MyHelloWorldAPI = MyAPI HelloWorldTail HelloWorldT
方案2:用类型家族处理路径列表
通过类型家族将类型级字符串列表转换为:>连接的路径,更灵活支持任意段数的路径:
{-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DataKinds #-} import Servant.API import GHC.TypeLits -- 类型家族:将路径列表转换为Servant API片段 type family PathSegments (segments :: [Symbol]) (next :: Type) :: Type where PathSegments '[] next = next PathSegments (s ': ss) next = s :> PathSegments ss next -- 复用的API类型,接受路径列表参数 type MyAPI (segments :: [Symbol]) result = "blah" :> Capture "a" A :> PathSegments segments (Get '[JSON] result) -- 使用示例 type MyHelloAPI = MyAPI '["hello"] HelloT -- 单段路径 type MyHelloWorldAPI = MyAPI '["hello", "world"] HelloWorldT -- 多段路径
方案3:基于Servant Generic的组件化复用
适合大型API场景,通过Generic定义可复用的API组件:
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE PolyKinds #-} import Servant.API import Servant.API.Generic import GHC.Generics -- 定义可复用的基础API片段 data BlahAPI route = BlahAPI { _blahEndpoint :: route :- "blah" :> Capture "a" A :> route } deriving Generic -- 组合多段路径与终点 type MyHelloWorldAPI = ToServantApi (BlahAPI (RecursiveRoute "hello" :> "world" :> Get '[JSON] HelloWorldT))
内容的提问来源于stack exchange,提问作者Clinton
相关产品推荐
相关产品推荐

