Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,20 @@ module.exports = {
kitchensink: contentTypes['api::kitchensink.kitchensink'],
},
routes: {
actions: {
routes: [
{
method: 'POST',
path: '/kitchensinks/:id/wash',
handler: 'api::kitchensink.actions.wash',
},
{
method: 'GET',
path: '/kitchensinks/empty',
handler: 'api::kitchensink.actions.empty',
}
]
},
kitchensink: {
routes: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,17 @@ describe('Documentation plugin | Documentation service', () => {
expect(mockFinalDoc.paths['/kitchensinks/{id}'].put.responses['200']).toEqual(expectedOne);
});

it('generates the correct response component schema for custom routes', async () => {
const docService = documentation({ strapi: global.strapi });
await docService.generateFullDoc();
const lastMockCall = fse.writeJson.mock.calls[fse.writeJson.mock.calls.length - 1];
const mockFinalDoc = lastMockCall[1];
expect(mockFinalDoc.paths['/kitchensinks/{id}/wash'].post.parameters.length).toEqual(1);
expect(mockFinalDoc.paths['/kitchensinks/{id}/wash'].post.responses).toBeDefined();
expect(mockFinalDoc.paths['/kitchensinks/empty'].get.responses).toBeDefined();

});

describe('Determines the plugins that need documentation', () => {
it('generates documentation for the default plugins if the user provided nothing in the config', async () => {
const docService = documentation({ strapi: global.strapi });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const pathToRegexp = require('path-to-regexp');
const pascalCase = require('./utils/pascal-case');
const queryParams = require('./utils/query-params');
const loopContentTypeNames = require('./utils/loop-content-type-names');
const getApiResponses = require('./utils/get-api-responses');
const {getApiResponses, getApiErrorResponses } = require('./utils/get-api-responses');
const { hasFindMethod, isLocalizedPath } = require('./utils/routes');

/**
Expand Down Expand Up @@ -166,6 +166,47 @@ const getAllPathsForContentType = (apiInfo) => {
return paths;
};

/**
* @description Builds the Swagger paths object for each content type custom route
*
* @param {object} api - Information about the current api
* @property {string} api.name - The name of the api
*/
const loopCustomRoutes = (api) => {
const result = {};
const routes = api.getter === 'plugin' ? strapi.plugin(api.name).routes : strapi.api[api.name].routes;
for(const routeNamespace in routes) {
if(api.ctNames.includes(routeNamespace)) continue; // skip content types already processable by loopContentTypeNames
const routeInfo = routes[routeNamespace];
const routeInfoRoutes = (Array.isArray(routeInfo) ? routeInfo : routeInfo?.routes) || [];
for(const route of routeInfoRoutes) {
const methodVerb = route.method.toLowerCase();
const hasPathParams = route.path.includes('/:');
const pathWithPrefix = getPathWithPrefix(routeInfo.prefix, route);
const routePath = hasPathParams ? parsePathWithVariables(pathWithPrefix) : pathWithPrefix;
const responses = getApiErrorResponses();
const swaggerConfig = {
[routePath]: {
[methodVerb]: {
operationId: `${methodVerb}${routePath}`,
parameters: [],
responses,
tags: [_.upperFirst(api.name)],
}
}
};

if (hasPathParams) {
const pathParams = getPathParams(route.path);
swaggerConfig[routePath][methodVerb].parameters.push(...pathParams);
}
Object.assign(result, swaggerConfig);
}
}

return result;
};

/**
* @description - Builds the Swagger paths object for each api
*
Expand All @@ -180,7 +221,7 @@ const buildApiEndpointPath = (api) => {
// A reusable loop for building paths and component schemas
// Uses the api param to build a new set of params for each content type
// Passes these new params to the function provided
return loopContentTypeNames(api, getAllPathsForContentType);
return Object.assign(loopContentTypeNames(api, getAllPathsForContentType), loopCustomRoutes(api));
};

module.exports = buildApiEndpointPath;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,58 @@

const pascalCase = require('./pascal-case');

const getApiErrorResponses = () => ({
400: {
description: 'Bad Request',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
401: {
description: 'Unauthorized',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
403: {
description: 'Forbidden',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
404: {
description: 'Not Found',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
500: {
description: 'Internal Server Error',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
});
/**
* @description - Builds the Swagger response object for a given api
*
Expand All @@ -11,7 +63,7 @@ const pascalCase = require('./pascal-case');
*
* @returns The Swagger responses
*/
const getApiResponse = ({
const getApiResponses = ({
uniqueName,
route,
isListOfEntities = false,
Expand Down Expand Up @@ -48,58 +100,12 @@ const getApiResponse = ({
},
},
},
400: {
description: 'Bad Request',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
401: {
description: 'Unauthorized',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
403: {
description: 'Forbidden',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
404: {
description: 'Not Found',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
500: {
description: 'Internal Server Error',
content: {
'application/json': {
schema: {
$ref: '#/components/schemas/Error',
},
},
},
},
},
...getApiErrorResponses(),
}
};
};

module.exports = getApiResponse;
module.exports = {
getApiResponses,
getApiErrorResponses
};