【发布时间】:2011-04-28 19:53:51
【问题描述】:
所以有点背景。我正在创建一个具有相当全面的 api 的网站。 api应该能够处理更改,因此我对api进行了版本化,api url相当于/api/0.2/$apiKey/$controller/$action/$id。
我希望能够为 api 以及标准 html 视图重用我的控制器。解决方案首先是在我的所有操作中使用 withFormat 块(通过在我的操作块中使用的私有函数之间共享)。
我不喜欢重复的代码,因此我想集中 withFormat 功能。因此,与其让一堆控制器和操作拥有自己的 withFormat 块,我希望它是一个服务(但是,我们无权访问服务上的render(),对吗?),或者有一个过滤器可以根据grails内容协商渲染输出。
我当前的解决方案定义了这个过滤器:
after = { model ->
def controller = grailsApplication.controllerClasses.find { controller ->
controller.logicalPropertyName == controllerName
}
def action = applicationContext.getBean(controller.fullName).class.declaredFields.find{ field -> field.name == actionName }
if(model && (isControllerApiRenderable(controller) || isActionApiRenderable(action))){
switch(request.format){
case 'json':
render text:model as JSON, contentType: "application/json"
return false
case 'xml':
render text:model as XML, contentType: "application/xml"
return false
default:
render status: 406
return false
}
}
return true
}
作为一个例子,我在控制器中渲染 xml 或 json 所要做的就是:
@ApiRenderable
def list = {
def collectionOfSomething = SomeDomain.findAllBySomething('someCriteria')
return [someCollection:collectionOfSomething]
}
现在,如果我访问触发此操作列表的 url,(/api/0.2/apikey/controller/list.json 或 /api/0.2/apikey/controller/list?format=json 或带有标题:content- type: application/json) 那么响应将被编码如下:
{
someCollection: [
{
someData: 'someData'
},
{
someData: 'someData2'
}
]
}
如果我总是想返回一个哈希图(目前这是控制器的要求),这一切都很好,但在这个例子中,我只想返回实际的列表!不是包含在 hashmap 中的列表....
是否有人对如何创建一个强大且灵活且遵循 DRY 原则、可以处理版本控制(/api/0.1/、/api/0.2/)以及可以处理不同编组的良好 api 功能有任何指示方法取决于它返回的上下文?任何提示表示赞赏!
【问题讨论】:
-
@ApiRenderable 是我制作的自定义注释,在过滤器中我检查它是否存在于控制器类或操作/字段本身上。
-
我一直在收集这方面的信息,因为我需要在路上做同样的事情。 trac.maflt.org/web/ibidem/ticket/180
-
假设我有一个 package.api.0.1.UserController 和一个 package.api.0.2.UserController 我可以将这两个类注册为人工制品,然后定义一个过滤器,将请求转发到正确的基于版本参数的用户控制器?