2021-09-02 11:25:24 +02:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const _ = require('lodash');
|
|
|
|
const pathToRegexp = require('path-to-regexp');
|
|
|
|
|
2022-03-17 16:54:37 +01:00
|
|
|
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');
|
2021-09-02 11:25:24 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Parses a route with ':variable'
|
|
|
|
*
|
|
|
|
* @param {string} routePath - The route's path property
|
2021-10-13 12:39:34 -04:00
|
|
|
* @returns {string}
|
2021-09-02 11:25:24 +02:00
|
|
|
*/
|
|
|
|
const parsePathWithVariables = routePath => {
|
|
|
|
return pathToRegexp
|
|
|
|
.parse(routePath)
|
|
|
|
.map(token => {
|
|
|
|
if (_.isObject(token)) {
|
|
|
|
return token.prefix + '{' + token.name + '}';
|
|
|
|
}
|
|
|
|
|
|
|
|
return token;
|
|
|
|
})
|
|
|
|
.join('');
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Builds the required object for a path parameter
|
|
|
|
*
|
|
|
|
* @param {string} routePath - The route's path property
|
|
|
|
*
|
2021-10-13 12:39:34 -04:00
|
|
|
* @returns {object } Swagger path params object
|
2021-09-02 11:25:24 +02:00
|
|
|
*/
|
|
|
|
const getPathParams = routePath => {
|
|
|
|
return pathToRegexp
|
|
|
|
.parse(routePath)
|
|
|
|
.filter(token => _.isObject(token))
|
|
|
|
.map(param => {
|
|
|
|
return {
|
|
|
|
name: param.name,
|
|
|
|
in: 'path',
|
|
|
|
description: '',
|
|
|
|
deprecated: false,
|
|
|
|
required: true,
|
|
|
|
schema: { type: 'string' },
|
|
|
|
};
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2021-10-13 12:39:34 -04:00
|
|
|
* @param {string} prefix - The route prefix
|
|
|
|
* @param {string} path - The route path
|
2021-09-02 11:25:24 +02:00
|
|
|
*
|
2021-10-13 12:39:34 -04:00
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
const getPathWithPrefix = (prefix, path) => {
|
|
|
|
if (path.includes('localizations')) {
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (path.endsWith('/')) {
|
|
|
|
return prefix;
|
|
|
|
}
|
|
|
|
|
|
|
|
return prefix.concat(path);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2022-04-01 17:43:21 +02:00
|
|
|
* @description Gets all paths based on routes
|
2021-10-13 12:39:34 -04:00
|
|
|
*
|
2022-03-17 16:54:37 +01:00
|
|
|
* @param {object} apiInfo
|
|
|
|
* @property {object} apiInfo.routeInfo - The api routes object
|
|
|
|
* @property {string} apiInfo.uniqueName - Content type name | Api name + Content type name
|
2021-10-13 12:39:34 -04:00
|
|
|
*
|
|
|
|
* @returns {object}
|
2021-09-02 11:25:24 +02:00
|
|
|
*/
|
2022-04-01 17:42:15 +02:00
|
|
|
const getPaths = ({ routeInfo, uniqueName, contentTypeInfo }) => {
|
|
|
|
// Get the routes for the current content type
|
|
|
|
const contentTypeRoutes = routeInfo.routes.filter(route => {
|
|
|
|
return (
|
|
|
|
route.path.includes(contentTypeInfo.pluralName) ||
|
|
|
|
route.path.includes(contentTypeInfo.singularName)
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
const paths = contentTypeRoutes.reduce((acc, route) => {
|
2021-10-19 09:39:10 +02:00
|
|
|
// TODO: Find a more reliable way to determine list of entities vs a single entity
|
|
|
|
const isListOfEntities = route.handler.split('.').pop() === 'find';
|
|
|
|
const methodVerb = route.method.toLowerCase();
|
2021-09-02 11:25:24 +02:00
|
|
|
|
2021-10-19 09:39:10 +02:00
|
|
|
const hasPathParams = route.path.includes('/:');
|
|
|
|
const pathWithPrefix = routeInfo.prefix
|
|
|
|
? getPathWithPrefix(routeInfo.prefix, route.path)
|
|
|
|
: route.path;
|
|
|
|
const routePath = hasPathParams ? parsePathWithVariables(pathWithPrefix) : pathWithPrefix;
|
2021-09-02 11:25:24 +02:00
|
|
|
|
2022-03-17 16:54:37 +01:00
|
|
|
const { responses } = getApiResponses(uniqueName, route, isListOfEntities);
|
2021-09-02 11:25:24 +02:00
|
|
|
|
2021-10-19 09:39:10 +02:00
|
|
|
const swaggerConfig = {
|
|
|
|
responses,
|
2022-03-17 16:54:37 +01:00
|
|
|
tags: [_.upperFirst(uniqueName)],
|
2021-10-19 09:39:10 +02:00
|
|
|
parameters: [],
|
2022-02-25 12:46:31 +01:00
|
|
|
operationId: `${methodVerb}${routePath}`,
|
2021-10-19 09:39:10 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
if (isListOfEntities) {
|
|
|
|
swaggerConfig.parameters.push(...queryParams);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasPathParams) {
|
|
|
|
const pathParams = getPathParams(route.path);
|
|
|
|
swaggerConfig.parameters.push(...pathParams);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (['post', 'put'].includes(methodVerb)) {
|
2022-03-17 16:54:37 +01:00
|
|
|
const requestBody = {
|
|
|
|
required: true,
|
|
|
|
content: {
|
|
|
|
'application/json': {
|
|
|
|
schema: {
|
2022-04-05 10:57:35 +02:00
|
|
|
$ref: `#/components/schemas/${pascalCase(uniqueName)}Request`,
|
2022-03-17 16:54:37 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
2021-10-19 09:39:10 +02:00
|
|
|
|
|
|
|
swaggerConfig.requestBody = requestBody;
|
|
|
|
}
|
|
|
|
|
|
|
|
_.set(acc, `${routePath}.${methodVerb}`, swaggerConfig);
|
2021-09-02 11:25:24 +02:00
|
|
|
|
2021-10-19 09:39:10 +02:00
|
|
|
return acc;
|
|
|
|
}, {});
|
2021-09-02 11:25:24 +02:00
|
|
|
|
2022-03-17 16:54:37 +01:00
|
|
|
return paths;
|
2021-09-02 11:25:24 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2022-03-17 16:54:37 +01:00
|
|
|
* @decription Gets all open api paths object for a given content type
|
2021-09-02 11:25:24 +02:00
|
|
|
*
|
2022-03-17 16:54:37 +01:00
|
|
|
* @param {object} apiInfo
|
|
|
|
* @property {string} apiInfo.name - The name of the api
|
|
|
|
* @property {string} apiInfo.getter - api | plugin
|
|
|
|
* @property {array} apiInfo.ctNames - All contentType names on the api
|
|
|
|
* @property {string} apiInfo.uniqueName - Api name | Api name + Content type name
|
|
|
|
* @property {object} apiInfo.attributes - Attributes on content type
|
|
|
|
* @property {object} apiInfo.routeInfo - The routes for the api
|
2021-09-02 11:25:24 +02:00
|
|
|
*
|
2022-03-17 16:54:37 +01:00
|
|
|
* @returns {object} Open API paths
|
2021-09-02 11:25:24 +02:00
|
|
|
*/
|
2022-04-01 17:42:15 +02:00
|
|
|
const getAllPathsForContentType = apiInfo => {
|
2022-02-27 10:33:18 +02:00
|
|
|
let paths = {};
|
2022-03-17 16:54:37 +01:00
|
|
|
|
|
|
|
const pathsObject = getPaths(apiInfo);
|
|
|
|
|
|
|
|
paths = {
|
|
|
|
...paths,
|
|
|
|
...pathsObject,
|
|
|
|
};
|
|
|
|
|
|
|
|
return paths;
|
2021-09-02 11:25:24 +02:00
|
|
|
};
|
2022-03-17 16:54:37 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @description - Builds the Swagger paths object for each api
|
|
|
|
*
|
|
|
|
* @param {object} api - Information about the current api
|
|
|
|
* @property {string} api.name - The name of the api
|
|
|
|
* @property {string} api.getter - The getter for the api (api | plugin)
|
|
|
|
* @property {array} api.ctNames - The name of all contentTypes found on the api
|
|
|
|
*
|
|
|
|
* @returns {object}
|
|
|
|
*/
|
|
|
|
const buildApiEndpointPath = api => {
|
|
|
|
return loopContentTypeNames(api, getAllPathsForContentType);
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = buildApiEndpointPath;
|