【问题标题】:Grails REST API - Render JSON with paging, metadata and custom include fields from paramsGrails REST API - 使用分页、元数据和来自参数的自定义包含字段呈现 JSON
【发布时间】:2014-10-29 16:15:06
【问题描述】:

我正在寻找一种最佳方法,根据Les Hazlewood 的此演示文稿Design Beautiful REST + JSON APIs 在 Grails 中为 RESTful API 设计自定义 JSON 响应。

这是我的域类

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
    }
}

我提到了这个问题的答案Render metadata for pagination from Grails RestfulController index/search actions

但仍需要在分页中包含first, previous, next & last 的链接,如上述所需格式。

2) 自定义输出

例如 具有hasMany 关系的taxis 属性应默认呈现为

"taxis": {
    "href": "https://api.mydomain.com/taxis/12345"
}

如果用户喜欢扩展taxis属性,例如:GET /taxi-types?expand=taxis,则JSON格式应该是

"taxis": {
    "href": "https://api.mydomain.com/taxis/12345"
    "name": "Taxi name",
    "type": "https://api.mydomain.com/taxi-types/1"
    ...
}

3) 将meta 对象添加到所有响应中

"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 个要求?提前致谢。

【问题讨论】:

  • 以下是一些可以帮助您入门的示例:mrhaki.blogspot.com/2014/07/… 另请参阅页面底部的“相关帖子”,mrhaki 的文章和笔记本是所有有关 Groovy 和 Grails 的优秀资源。
  • 这个问题本身就有很多有用的知识......我用它作为回答(!)

标签: json rest grails


【解决方案1】:

我创建了一个plugin for grails 3,它允许您向您的 api 添加分页、自定义元数据和其他有用的功能。您也可以使用 LinkGenerators 以及我的插件添加 HAL 功能。

【讨论】:

  • 我注意到缺乏安全性(没有用于您的 api 调用的令牌)、没有 CORS 支持、没有 api 文档、没有开发人员 SDK、没有支持工具(基准测试/分析)。为什么这比 Grails 自带的标准 rest 插件好?
【解决方案2】:

Beapi-API-Framework 插件是 grails 的#1 api 插件,默认提供分页。有关所有功能、文档和安装说明的完整列表,请参阅 the github repo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    • 2022-01-26
    • 2016-05-24
    • 2017-04-01
    • 2023-01-08
    • 2015-12-20
    相关资源
    最近更新 更多