Haskell Swagger镜头自动生成

时间:2018-05-03 17:23:55

标签: haskell swagger lens

我有以下代码:

import Control.Lens ((&), (.~), (?~), (%~))
import Data.Swagger (Swagger)
import Data.Swagger.Lens (paths, operationId, info, description)
import qualified Data.HashMap.Strict.InsOrd as InsOrdHashMap
import Data.Text (Text(..), pack)

genOpIds :: Swagger -> Swagger
genOpIds = paths %~ InsOrdHashMap.mapWithKey (\k v -> v & operationId ?~ (pack "hello"))

生成以下编译错误:

    • No instance for (Data.Swagger.Lens.HasOperationId
                         Data.Swagger.Internal.PathItem (Maybe Text))
        arising from a use of ‘operationId’
    • In the first argument of ‘(?~)’, namely ‘operationId’
      In the second argument of ‘(&)’, namely
        ‘operationId ?~ (pack "hello")’
      In the expression: v & operationId ?~ (pack "hello")
   |
12 | genOpIds = paths %~ InsOrdHashMap.mapWithKey (\k v -> v & operationId ?~ (pack "hello"))
   |                                                           ^^^^^^^^^^^

我发现诊断有点困难,因为我认为makeLenses用于生成类实例。我正在苦苦挣扎,看看这与以下内容有何不同(编译得很好):

writeInfoTitle :: Swagger -> Swagger
writeInfoTitle = info.description ?~ (pack "whatever description")

因为所涉及的类型层次结构在底部是类似的。我怀疑我在这里缺少一点基本的理解,但我已经阅读了镜头教程,包括关于遍历的部分;仆人招摇代码的各个部分,以及其他一些例子并没有设法解决这个问题。

要轻松重新创建错误消息,您可以克隆以下repo和stack build

https://github.com/msk-/improved-spork

1 个答案:

答案 0 :(得分:2)

免责声明:我从未使用过Swagger。 但是,看一下它的文档,我可以在Swagger类型中看到以下元素:
_swaggerPaths :: InsOrdHashMap FilePath PathItem - 与paths镜头相对应 查看PathItem的定义表明它不是HasOperationId的实例 - 它本身是由

组成的
PathItem     
  _pathItemGet :: Maybe Operation   
  _pathItemPut :: Maybe Operation   
  _pathItemPost :: Maybe Operation  
  _pathItemDelete :: Maybe Operation    
  _pathItemOptions :: Maybe Operation   
  _pathItemHead :: Maybe Operation  
  _pathItemPatch :: Maybe Operation 
  _pathItemParameters :: [Referenced Param]

这似乎表明你在镜头组成中缺少什么 (\k v -> v & (??? . operationId) ?~ (pack "hello"));类似于的东西 (\k v -> v & (itemGet . operationId) ?~ (pack "hello"))

编辑: 通过使用Monoid记录的PathItem实例,可以轻松完成您尝试实现的目标(设置简单的路径操作),如下所示:

genOpsId = paths %~ InsOrdHashMap.mapWithKey (\k v -> v & get ?~ (mempty & operationId ?~ (pack "hello")))



编辑#2: 根据要求,这是迭代PathItem记录的字段并设置存在的那些的operationId的一种方法。
为了记录,我非常确定有一种方法,方式,更清洁的方式来做到这一点,但这里有。

dokey :: PathItem -> PathItem
dokey v = foldl 
  (\acc nv -> acc & nv %~ (fmap $ operationId ?~ (pack "hello")))
  v 
  [get, put, post, delete, options, head_, patch]  

genOpIds :: Swagger -> Swagger
genOpIds = paths %~ InsOrdHashMap.mapWithKey (\k -> doKey)

希望有所帮助! :)