提问人:Ibrahim 提问时间:10/30/2014 最后编辑:CommunityIbrahim 更新时间:4/5/2021 访问量:3651
Grails REST API - 使用分页、元数据和来自参数的自定义包含字段呈现 JSON
Grails REST API - Render JSON with paging, metadata and custom include fields from params
问:
我正在寻找一种最佳方法,根据Les Hazlewood的演示设计漂亮的REST + JSON API,在Grails中为RESTful API设计自定义JSON响应。
这是我的 Domain 类
class TaxiType {
Date dateCreated, lastUpdated
String description
User createdBy
static hasMany = [taxis: Taxi]
static constraints = {
}
}
列表所需的响应格式为
{
"meta": {
"href": "https://api.mydomain.com/taxi-types",
"otherData": "..."
},
"paging": {
"offset": 0,
"limit": 10,
"total": 100,
"first": "https://api.mydomain.com/taxi-types?offset=0&limit=10",
"previous": null,
"next": "https://api.mydomain.com/taxi-types?offset=90&limit=10",
"last": "https://api.mydomain.com/taxi-types?offset=90&limit=10"
},
"data": [
{
"href": "https://api.mydomain.com/taxi-types/1",
"id": 1,
"description": "description 1",
"taxis": {
"href": "https://api.mydomain.com/taxi-types/1/taxis"
}
},
...
]
}
TaxiTypeController.groovy
def index(Integer limit) {
params.max = Math.min(limit ? : 10, 100)
params.offset = params ? .offset ? .toInteger()
withFormat {
json {
respond TaxiType.list(params),
[includes : includeFields,
paging : [total : TaxiType.count(), limit : params ? .max, offset : params ? .offset ? : 0]
]
}
}
}
private getIncludeFields() {
params.fields ? .tokenize(', ')
}
SumoJsonCollectionRenderer.groovy
class SumoJsonCollectionRenderer extends JsonCollectionRenderer {
SumoJsonCollectionRenderer(Class componentType) {
super(componentType)
}
public SumoJsonCollectionRenderer(Class componentType, MimeType...mimeTypes) {
super(componentType, mimeTypes)
}
@ CompileStatic(SKIP)
@ Override
protected void renderJson(object, RenderContext context) {
log.debug(object)
log.debug(object.size())
log.debug(object.getTotalCount())
Map tObject = ['data' : object]
if (context.arguments ? .paging) {
tObject['paging'] = context ? .arguments ? .paging
}
super.renderJson(tObject, context)
}
}
必需的功能包括:
1) API 用户应该只能获取必填字段(部分表示)
GET https://api.mydomain.com/taxi-types??fields=id,description,taxis
此请求的预期响应应为
{
"meta" : {...}
"paging" : {...}
"data" : [{
"href" : "https://api.mydomain.com/taxi-types/1",
"id" : 1,
"description" : "Taxi Type1",
"taxis" : [{
"href" : "https://api.mydomain.com/taxis/123"
},
...
]
},
...
]
}
我得到的是
{
"data" : [{
"id" : 1,
"description" : "Taxi Type1",
"taxis" : [{
"class" : "com.domain.project.Taxi",
"id" : 1
}
]
},
...
],
"paging" : {
"total" : 80,
"limit" : 10,
"offset" : 0
}
}
我参考了这个问题的答案:渲染元数据以从 Grails RestfulController 索引/搜索操作进行分页。
但仍然需要在分页中包含链接,如上面所需的格式所述。first, previous, next & last
2) 自定义输出
例如
默认情况下,具有关系的属性应呈现为taxis
hasMany
"taxis": {
"href": "https://api.mydomain.com/taxis/12345"
}
如果用户更喜欢扩展属性,例如: ,JSON 格式应为taxis
GET /taxi-types?expand=taxis
"taxis": {
"href": "https://api.mydomain.com/taxis/12345"
"name": "Taxi name",
"type": "https://api.mydomain.com/taxi-types/1"
...
}
3)将元
对象添加到所有响应中
"meta": {
"href": "https://api.mydomain.com/taxi-types",
...
}
我尝试了 Json Marshaller 来自定义响应。这是我的 Marshaller 代码
JSON.registerObjectMarshaller(TaxiType) {TaxiType taxiType->
return [
id : taxiType ? .id,
description : taxiType ? .description
]
}
但它总是在返回数组中使用这两个属性进行渲染,即使我想要一些其他属性,例如 .id & description
taxis
如何实现上述 3 个要求?提前致谢。
答:
我为 grails 3 创建了一个插件,它允许您向 API 添加分页、自定义元数据和其他有用的功能。您可以使用 LinkGenerators 以及我的插件添加 HAL 功能。
评论
那么 Beapi-API-Framework 插件是 grails 的 #1 api 插件,默认情况下提供分页。请参阅 github 存储库,获取所有功能、文档和安装说明的完整列表
评论