向端点结果添加分页游标和其他功能
Adding pagination cursor and additional features to endpoint result
Strongloop api 非常适合开箱即用。但是,我目前正在尝试进行一些自定义。我正在尝试向 category
模型添加一个远程方法 returns 以及以下端点数据:perPage
、total
、paging
(显示下面详细介绍)。对于 paging
,before
和 after
是基于 gameId
的参数。如果值为 null
或大于 5
,limit
将默认为 5
。附加到前面提到的结果的最佳方法是什么?
例如,http://localhost:3000/api/Categories/1004/games/mature?before=1000053
将 return 所有 gameId
小于 1000053
和 before
所有 gameIds
大于 1000053
.
common/models/category.js
Category.findById(id, {}, function(err, category){
if (err) return callback(err);
//set limit
if (limit && limit > 5){
limit = 5;
}else if(limit === undefined){
limit = 5;
}
//set after cursor
Games.find({
"where": {
categoryId: id,
mature: true,
gameId: {gt: after}
},
"limit": limit
}, function(err, gameArr) {
if (err) return callback(err);
callback(null, gameArr);
});
});
/Categories/1004/games/mature
的端点结果
{
“perPage”: 5, //value from limit
“total”: 5, //total of return items from array
"data": [
... Endpoint data is here
],
"paging": {
"cursors": {
"after": 1000057, //last item in array
"before": 1000053 //first item in array
},
"previous": "http://localhost:3000/api/Categories/1004/games/mature?before=1000053" //url for previous
"next": "http://localhost:3000/api/Categories/1004/games/mature?after=1000057" //url for after
}
}
这里的问题是您使用类别模型作为入口点,而您似乎应该使用带有过滤器、限制和偏移量的游戏模型的内置查询方法,句号。这将使您无需添加所有这些复杂性即可进行分页以支持您的 before/after 概念。这是不必要的。 如果你的关系设置正确,你只需要在游戏上分页就是一个游戏模型查询!
例如,您似乎需要一个特定类别中成熟游戏的分页列表,对吗?要获得符合这些条件的 5 场比赛的结果,您可以像这样发送 json REST API 调用:
http://0.0.0.0:3000/api/Games?filter=%7B%20%22where%22%3A%20%7B%22mature%22%3Atrue%2C%20%22categoryId%22%3A%201004%7D%2C%20%22offset%22%3A%200%2C%20%22limit%22%3A%205%20%7D
这很难阅读,因为它是编码的,但底层过滤器是这样构造的:
{ "where": {"mature":true, "categoryId": 1004}, "offset": 0, "limit": 5 }
这将return以下数据集,这是1004 categoryId 中的前 5 个游戏:
[
{
"mature": true,
"gameName": "CODBlacOps3",
"categoryId": 1004,
"gameId": 1000053,
"description": "Published by Activision",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Evolve",
"categoryId": 1004,
"gameId": 1000054,
"description": "Published by Turtle Rock Studios",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Battlefield4",
"categoryId": 1004,
"gameId": 1000055,
"description": "Published by EA Digital Illusions",
"publishedDate": "2013-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Rainbow6",
"categoryId": 1004,
"gameId": 1000056,
"description": "Published by EUbisoft",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Destiny",
"categoryId": 1004,
"gameId": 1000057,
"description": "Published by Bungie",
"publishedDate": "2014-01-01T00:00:00.000Z"
}
]
要获取 5 场比赛的下一页,我们只需将偏移量更改为 5,这会告诉数据库跳过前 5 场,因为我们现在是第 2 场页数:
{ "where": {"mature":true, "categoryId": 1004}, "offset": 5, "limit": 5 }
这 return 结果如下:
[
{
"mature": true,
"gameName": "Wolfenstein",
"categoryId": 1004,
"gameId": 1000058,
"description": "Published by Bethesda",
"publishedDate": "2014-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "StarWarsBattleFront",
"categoryId": 1004,
"gameId": 1000059,
"description": "Published by EA DICE",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Test1",
"categoryId": 1004,
"gameId": 1000060,
"description": "Published by Test1",
"publishedDate": "2015-12-19T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Test2",
"categoryId": 1004,
"gameId": 1000061,
"description": "Published by Test2",
"publishedDate": "2015-12-19T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Test3",
"categoryId": 1004,
"gameId": 1000062,
"description": "Published by Test3",
"publishedDate": "2015-12-19T00:00:00.000Z"
}
]
默认情况下,游戏按 game_id 的顺序排列。无需自定义远程方法和嵌套查找 ()!
如果您想按字母顺序排列列表,您还可以添加 order
过滤器,并将其设置为 "order": "gameName ASC"
:
{ "where": {"mature":true, "categoryId": 1004}, "offset": 0, "limit": 5, "order": "gameName ASC" }
这将 return 一个新的(第 1 页,因为我将偏移量设置回 0)游戏数组,按 gameName
:
的字母顺序排列
[
{
"mature": true,
"gameName": "Battlefield4",
"categoryId": 1004,
"gameId": 1000055,
"description": "Published by EA Digital Illusions",
"publishedDate": "2013-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "CODBlacOps3",
"categoryId": 1004,
"gameId": 1000053,
"description": "Published by Activision",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Destiny",
"categoryId": 1004,
"gameId": 1000057,
"description": "Published by Bungie",
"publishedDate": "2014-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Evolve",
"categoryId": 1004,
"gameId": 1000054,
"description": "Published by Turtle Rock Studios",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Rainbow6",
"categoryId": 1004,
"gameId": 1000056,
"description": "Published by EUbisoft",
"publishedDate": "2015-01-01T00:00:00.000Z"
}
]
我能够如此快速地得到这个结果的方法是使用 API Explorer。我分叉了你的项目,更改了数据库连接值以匹配我的本地服务器,启动它然后转到 http://0.0.0.0/explorer/#!/Games/Games_find
然后在游戏模型上玩不同的 filter
值:
要将结果添加到响应中,首先将 Category.mature 远程方法 returns 的响应类型更改为对象:
Category.remoteMethod('mature', {
accepts: [
{arg: 'id', type: 'number', required: true},
{arg: 'limit',type: 'number',required: false},
{arg: 'after',type: 'number',required: false},
{arg: 'before',type: 'number',required: false}
],
// mixing ':id' into the rest url allows $owner to be determined and used for access control
http: {
path: '/:id/games/mature',
verb: 'get'
},
returns: {
arg: 'games',
type: 'object' // will be whatever you pass back as 2nd arg to callback()
}
});
然后只需将您想要的值添加到新游戏对象,使用您现有的 gameArr 作为 data
的值,并将限制、之前和之后的值传递到响应对象中作为成功回调的第二个参数:
callback(null, {
"perPage": limit,
"total": gameArray.length,
"data": gameArray,
"paging": {
"cursors": {
"after": gameArray[gameArray.length-1].game_id, // last game_id in result
"before": gameArray[0].game_id // first game_id in result
},
"previous": "http://localhost:3000/api/Categories/1004/games/mature?before=" + gameArray[0].game_id,
"next": "http://localhost:3000/api/Categories/1004/games/mature?after=" + gameArray[gameArray.length-1].game_id
}
})
正如我提到的使代码过于复杂的多个 Games.find() 调用一样,您也不应该复制该对象的 3 或 4 个副本。您可以在逻辑中包装对象的构造,然后调用单个 callback() 来简化远程方法的 I/O 管理并编写更少的代码。减少到单个 Games.find() 调用将使发送此结果更容易。
还要注意卷曲撇号字符和制表符与 space 缩进(选择一个并坚持使用,不要混用),在构建和组织代码时更容易提供帮助小心。
Strongloop api 非常适合开箱即用。但是,我目前正在尝试进行一些自定义。我正在尝试向 category
模型添加一个远程方法 returns 以及以下端点数据:perPage
、total
、paging
(显示下面详细介绍)。对于 paging
,before
和 after
是基于 gameId
的参数。如果值为 null
或大于 5
,limit
将默认为 5
。附加到前面提到的结果的最佳方法是什么?
例如,http://localhost:3000/api/Categories/1004/games/mature?before=1000053
将 return 所有 gameId
小于 1000053
和 before
所有 gameIds
大于 1000053
.
common/models/category.js
Category.findById(id, {}, function(err, category){
if (err) return callback(err);
//set limit
if (limit && limit > 5){
limit = 5;
}else if(limit === undefined){
limit = 5;
}
//set after cursor
Games.find({
"where": {
categoryId: id,
mature: true,
gameId: {gt: after}
},
"limit": limit
}, function(err, gameArr) {
if (err) return callback(err);
callback(null, gameArr);
});
});
/Categories/1004/games/mature
{
“perPage”: 5, //value from limit
“total”: 5, //total of return items from array
"data": [
... Endpoint data is here
],
"paging": {
"cursors": {
"after": 1000057, //last item in array
"before": 1000053 //first item in array
},
"previous": "http://localhost:3000/api/Categories/1004/games/mature?before=1000053" //url for previous
"next": "http://localhost:3000/api/Categories/1004/games/mature?after=1000057" //url for after
}
}
这里的问题是您使用类别模型作为入口点,而您似乎应该使用带有过滤器、限制和偏移量的游戏模型的内置查询方法,句号。这将使您无需添加所有这些复杂性即可进行分页以支持您的 before/after 概念。这是不必要的。 如果你的关系设置正确,你只需要在游戏上分页就是一个游戏模型查询!
例如,您似乎需要一个特定类别中成熟游戏的分页列表,对吗?要获得符合这些条件的 5 场比赛的结果,您可以像这样发送 json REST API 调用:
http://0.0.0.0:3000/api/Games?filter=%7B%20%22where%22%3A%20%7B%22mature%22%3Atrue%2C%20%22categoryId%22%3A%201004%7D%2C%20%22offset%22%3A%200%2C%20%22limit%22%3A%205%20%7D
这很难阅读,因为它是编码的,但底层过滤器是这样构造的:
{ "where": {"mature":true, "categoryId": 1004}, "offset": 0, "limit": 5 }
这将return以下数据集,这是1004 categoryId 中的前 5 个游戏:
[
{
"mature": true,
"gameName": "CODBlacOps3",
"categoryId": 1004,
"gameId": 1000053,
"description": "Published by Activision",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Evolve",
"categoryId": 1004,
"gameId": 1000054,
"description": "Published by Turtle Rock Studios",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Battlefield4",
"categoryId": 1004,
"gameId": 1000055,
"description": "Published by EA Digital Illusions",
"publishedDate": "2013-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Rainbow6",
"categoryId": 1004,
"gameId": 1000056,
"description": "Published by EUbisoft",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Destiny",
"categoryId": 1004,
"gameId": 1000057,
"description": "Published by Bungie",
"publishedDate": "2014-01-01T00:00:00.000Z"
}
]
要获取 5 场比赛的下一页,我们只需将偏移量更改为 5,这会告诉数据库跳过前 5 场,因为我们现在是第 2 场页数:
{ "where": {"mature":true, "categoryId": 1004}, "offset": 5, "limit": 5 }
这 return 结果如下:
[
{
"mature": true,
"gameName": "Wolfenstein",
"categoryId": 1004,
"gameId": 1000058,
"description": "Published by Bethesda",
"publishedDate": "2014-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "StarWarsBattleFront",
"categoryId": 1004,
"gameId": 1000059,
"description": "Published by EA DICE",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Test1",
"categoryId": 1004,
"gameId": 1000060,
"description": "Published by Test1",
"publishedDate": "2015-12-19T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Test2",
"categoryId": 1004,
"gameId": 1000061,
"description": "Published by Test2",
"publishedDate": "2015-12-19T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Test3",
"categoryId": 1004,
"gameId": 1000062,
"description": "Published by Test3",
"publishedDate": "2015-12-19T00:00:00.000Z"
}
]
默认情况下,游戏按 game_id 的顺序排列。无需自定义远程方法和嵌套查找 ()!
如果您想按字母顺序排列列表,您还可以添加 order
过滤器,并将其设置为 "order": "gameName ASC"
:
{ "where": {"mature":true, "categoryId": 1004}, "offset": 0, "limit": 5, "order": "gameName ASC" }
这将 return 一个新的(第 1 页,因为我将偏移量设置回 0)游戏数组,按 gameName
:
[
{
"mature": true,
"gameName": "Battlefield4",
"categoryId": 1004,
"gameId": 1000055,
"description": "Published by EA Digital Illusions",
"publishedDate": "2013-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "CODBlacOps3",
"categoryId": 1004,
"gameId": 1000053,
"description": "Published by Activision",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Destiny",
"categoryId": 1004,
"gameId": 1000057,
"description": "Published by Bungie",
"publishedDate": "2014-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Evolve",
"categoryId": 1004,
"gameId": 1000054,
"description": "Published by Turtle Rock Studios",
"publishedDate": "2015-01-01T00:00:00.000Z"
},
{
"mature": true,
"gameName": "Rainbow6",
"categoryId": 1004,
"gameId": 1000056,
"description": "Published by EUbisoft",
"publishedDate": "2015-01-01T00:00:00.000Z"
}
]
我能够如此快速地得到这个结果的方法是使用 API Explorer。我分叉了你的项目,更改了数据库连接值以匹配我的本地服务器,启动它然后转到 http://0.0.0.0/explorer/#!/Games/Games_find
然后在游戏模型上玩不同的 filter
值:
要将结果添加到响应中,首先将 Category.mature 远程方法 returns 的响应类型更改为对象:
Category.remoteMethod('mature', {
accepts: [
{arg: 'id', type: 'number', required: true},
{arg: 'limit',type: 'number',required: false},
{arg: 'after',type: 'number',required: false},
{arg: 'before',type: 'number',required: false}
],
// mixing ':id' into the rest url allows $owner to be determined and used for access control
http: {
path: '/:id/games/mature',
verb: 'get'
},
returns: {
arg: 'games',
type: 'object' // will be whatever you pass back as 2nd arg to callback()
}
});
然后只需将您想要的值添加到新游戏对象,使用您现有的 gameArr 作为 data
的值,并将限制、之前和之后的值传递到响应对象中作为成功回调的第二个参数:
callback(null, {
"perPage": limit,
"total": gameArray.length,
"data": gameArray,
"paging": {
"cursors": {
"after": gameArray[gameArray.length-1].game_id, // last game_id in result
"before": gameArray[0].game_id // first game_id in result
},
"previous": "http://localhost:3000/api/Categories/1004/games/mature?before=" + gameArray[0].game_id,
"next": "http://localhost:3000/api/Categories/1004/games/mature?after=" + gameArray[gameArray.length-1].game_id
}
})
正如我提到的使代码过于复杂的多个 Games.find() 调用一样,您也不应该复制该对象的 3 或 4 个副本。您可以在逻辑中包装对象的构造,然后调用单个 callback() 来简化远程方法的 I/O 管理并编写更少的代码。减少到单个 Games.find() 调用将使发送此结果更容易。
还要注意卷曲撇号字符和制表符与 space 缩进(选择一个并坚持使用,不要混用),在构建和组织代码时更容易提供帮助小心。