Skip to content

Commit 79e58ce

Browse files
committed
feat!: add pagination support
1 parent c40b3a6 commit 79e58ce

13 files changed

+336
-9
lines changed

example/openapi-v3/definitions.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* Example for openapi v3
33
* - using definitions option of service.docs to define all needed definitions
4+
* - service with pagination
45
* - using swagger ui with a custom indexFile
56
* - add parameter to find (globally)
67
* - set specific values and sub values for a operation
@@ -12,7 +13,7 @@ const memory = require('feathers-memory');
1213
const swagger = require('../../lib');
1314

1415
module.exports = (app) => {
15-
const messageService = memory();
16+
const messageService = memory({ paginate: { default: 10, max: 50 } });
1617
const uiIndexFile = path.join(__dirname, 'docs.html');
1718

1819
messageService.docs = {

example/swagger-v2/customTags.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ module.exports = (app) => {
5151
};
5252

5353
app.configure(swagger({
54+
openApiVersion: 2,
5455
prefix: 'v2/custom-tags/',
5556
docsJsonPath: '/v2/custom-tags.json',
5657
ui: swagger.swaggerUI({ docsPath: '/v2/custom-tags' }),

example/swagger-v2/definitionWithCustomizedSpec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ module.exports = (app) => {
3333
};
3434

3535
app.configure(swagger({
36+
openApiVersion: 2,
3637
prefix: 'v2/definition-with-customized-update/',
3738
docsJsonPath: '/v2/definition-with-customized-update.json',
3839
ui: swagger.swaggerUI({ docsPath: '/v2/definition-with-customized-update' }),

example/swagger-v2/definitions.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* Example for swagger v2
33
* - using definitions option of service.docs to define all needed definitions
4+
* - service with pagination
45
* - using swagger ui with a custom indexFile
56
* - add parameter to find (globally)
67
* - set specific values and sub values for a operation
@@ -11,7 +12,7 @@ const memory = require('feathers-memory');
1112
const swagger = require('../../lib');
1213

1314
module.exports = (app) => {
14-
const messageService = memory();
15+
const messageService = memory({ paginate: { default: 10 } });
1516
const uiIndexFile = path.join(__dirname, 'docs.html');
1617

1718
messageService.docs = {
@@ -54,6 +55,7 @@ module.exports = (app) => {
5455
};
5556

5657
app.configure(swagger({
58+
openApiVersion: 2,
5759
prefix: 'v2/definitions/',
5860
docsJsonPath: '/v2/definitions.json',
5961
ui: swagger.swaggerUI({ docsPath: '/v2/definitions', indexFile: uiIndexFile }),

example/swagger-v2/security.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ module.exports = (app) => {
5151
};
5252

5353
app.configure(swagger({
54+
openApiVersion: 3,
5455
prefix: 'v2/security/',
5556
docsJsonPath: '/v2/security.json',
5657
ui: swagger.swaggerUI({ docsPath: '/v2/security' }),

lib/helpers.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,7 @@ exports.assignWithSet = (object, ...sources) => {
4444
}
4545
return object;
4646
};
47+
48+
exports.isPaginationEnabled = function (service) {
49+
return service.options && service.options.paginate && service.options.paginate.default;
50+
};

lib/openapi.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class OpenApiGenerator {
9393
/* istanbul ignore next: abstract method */
9494
getOperationDefaults () {} // has to be implemented in sub class
9595
/* istanbul ignore next: abstract method */
96-
applyDefinitionsToSpecs (service, model) {} // has to implemented in sub class
96+
applyDefinitionsToSpecs (service, model, modelName, refs) {} // has to implemented in sub class
9797
/* istanbul ignore next: abstract method */
9898
getPathParameterSpec (name) {} // has to implemented in sub class
9999
/* istanbul ignore next: abstract method */
@@ -171,14 +171,16 @@ class OpenApiGenerator {
171171
const multiOperations = doc.multi || this.config.defaults.multi || determineMultiOperations(service);
172172
const idSeparator = (service.options && service.options.idSeparator) || ',';
173173

174-
this.applyDefinitionsToSpecs(service, model, modelName);
174+
const refs = this.getOperationsRefs(service, model);
175+
176+
this.applyDefinitionsToSpecs(service, model, modelName, refs);
175177

176178
const defaultArgumentObject = {
177179
idName,
178180
idType,
179181
...operationArgs,
180182
tags,
181-
refs: this.getOperationsRefs(service, model),
183+
refs,
182184
specs: this.specs,
183185
service,
184186
config: this.config,

lib/v2/generator.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const AbstractApiGenerator = require('../openapi');
2+
const { isPaginationEnabled } = require('../helpers');
23
const utils = require('../utils');
34

45
function idPathParameters (idName, idType, description) {
@@ -49,7 +50,7 @@ class OpenApiV2Generator extends AbstractApiGenerator {
4950
getOperationsRefs (service, model) {
5051
const modelList = `${model}_list`;
5152
const refs = {
52-
findResponse: modelList,
53+
findResponse: isPaginationEnabled(service) ? `${model}_pagination` : modelList,
5354
getResponse: model,
5455
createRequest: model,
5556
createResponse: model,
@@ -377,7 +378,7 @@ class OpenApiV2Generator extends AbstractApiGenerator {
377378
};
378379
}
379380

380-
applyDefinitionsToSpecs (service, model, modelName) {
381+
applyDefinitionsToSpecs (service, model, modelName, refs) {
381382
if (typeof service.docs.definition !== 'undefined') {
382383
this.specs.definitions[model] = service.docs.definition;
383384
this.specs.definitions[`${model}_list`] = {
@@ -395,6 +396,22 @@ class OpenApiV2Generator extends AbstractApiGenerator {
395396
this.config.defaults.schemasGenerator(service, model, modelName, this.specs.definitions)
396397
);
397398
}
399+
if (isPaginationEnabled(service) &&
400+
refs.findResponse === `${model}_pagination` &&
401+
typeof this.specs.definitions[`${model}_list`] !== 'undefined' &&
402+
typeof this.specs.definitions[`${model}_pagination`] === 'undefined'
403+
) {
404+
this.specs.definitions[`${model}_pagination`] = {
405+
title: `${modelName} pagination result`,
406+
type: 'object',
407+
properties: {
408+
total: { type: 'integer' },
409+
limit: { type: 'integer' },
410+
skip: { type: 'integer' },
411+
data: { $ref: `#/definitions/${model}_list` }
412+
}
413+
};
414+
}
398415
}
399416

400417
getPathParameterSpec (name) {

lib/v3/generator.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const AbstractApiGenerator = require('../openapi');
2+
const { isPaginationEnabled } = require('../helpers');
23
const utils = require('../utils');
34

45
function addDefinitionToSchemas (schemas, definition, model, modelName) {
@@ -93,7 +94,7 @@ class OpenApiV3Generator extends AbstractApiGenerator {
9394
getOperationsRefs (service, model) {
9495
const modelList = `${model}_list`;
9596
const refs = {
96-
findResponse: modelList,
97+
findResponse: isPaginationEnabled(service) ? `${model}_pagination` : modelList,
9798
getResponse: model,
9899
createRequest: model,
99100
createResponse: model,
@@ -414,7 +415,7 @@ class OpenApiV3Generator extends AbstractApiGenerator {
414415
};
415416
}
416417

417-
applyDefinitionsToSpecs (service, model, modelName) {
418+
applyDefinitionsToSpecs (service, model, modelName, refs) {
418419
if (typeof service.docs.definition !== 'undefined') {
419420
addDefinitionToSchemas(this.specs.components.schemas, service.docs.definition, model, modelName);
420421
}
@@ -433,6 +434,22 @@ class OpenApiV3Generator extends AbstractApiGenerator {
433434
this.config.defaults.schemasGenerator(service, model, modelName, this.specs.components.schemas)
434435
);
435436
}
437+
if (isPaginationEnabled(service) &&
438+
refs.findResponse === `${model}_pagination` &&
439+
typeof this.specs.components.schemas[`${model}_list`] !== 'undefined' &&
440+
typeof this.specs.components.schemas[`${model}_pagination`] === 'undefined'
441+
) {
442+
this.specs.components.schemas[`${model}_pagination`] = {
443+
title: `${modelName} pagination result`,
444+
type: 'object',
445+
properties: {
446+
total: { type: 'integer' },
447+
limit: { type: 'integer' },
448+
skip: { type: 'integer' },
449+
data: { $ref: `#/components/schemas/${model}_list` }
450+
}
451+
};
452+
}
436453
}
437454

438455
getPathParameterSpec (name) {
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
{
2+
"info": {
3+
"title": "swagger generator v2 tests",
4+
"version": "1.0.0"
5+
},
6+
"paths": {
7+
"/message": {
8+
"get": {
9+
"parameters": [
10+
{
11+
"description": "Number of results to return",
12+
"in": "query",
13+
"name": "$limit",
14+
"type": "integer"
15+
},
16+
{
17+
"description": "Number of results to skip",
18+
"in": "query",
19+
"name": "$skip",
20+
"type": "integer"
21+
},
22+
{
23+
"description": "Property to sort results",
24+
"in": "query",
25+
"name": "$sort",
26+
"type": "string"
27+
}
28+
],
29+
"responses": {
30+
"200": {
31+
"description": "success",
32+
"schema": {
33+
"$ref": "#/definitions/message_pagination"
34+
}
35+
},
36+
"401": {
37+
"description": "not authenticated"
38+
},
39+
"500": {
40+
"description": "general error"
41+
}
42+
},
43+
"description": "Retrieves a list of all resources from the service.",
44+
"summary": "",
45+
"tags": [
46+
"message"
47+
],
48+
"consumes": [
49+
"application/json"
50+
],
51+
"produces": [
52+
"application/json"
53+
],
54+
"security": []
55+
}
56+
}
57+
},
58+
"definitions": {
59+
"message": {
60+
"type": "object",
61+
"properties": {
62+
"content": {
63+
"type": "string"
64+
}
65+
}
66+
},
67+
"message_list": {
68+
"title": "message list",
69+
"type": "array",
70+
"items": {
71+
"$ref": "#/definitions/message"
72+
}
73+
},
74+
"message_pagination": {
75+
"title": "message pagination result",
76+
"type": "object",
77+
"properties": {
78+
"total": {
79+
"type": "integer"
80+
},
81+
"limit": {
82+
"type": "integer"
83+
},
84+
"skip": {
85+
"type": "integer"
86+
},
87+
"data": {
88+
"$ref": "#/definitions/message_list"
89+
}
90+
}
91+
}
92+
},
93+
"swagger": "2.0",
94+
"schemes": [
95+
"http"
96+
],
97+
"tags": [
98+
{
99+
"name": "message",
100+
"description": "A message service"
101+
}
102+
],
103+
"basePath": "/",
104+
"consumes": [
105+
"application/json"
106+
],
107+
"produces": [
108+
"application/json"
109+
]
110+
}

0 commit comments

Comments
 (0)