232 lines
6.8 KiB
JavaScript
Raw Normal View History

2022-03-17 16:54:37 +01:00
'use strict';
2022-08-08 15:50:34 +02:00
2022-05-05 12:32:22 +02:00
const _ = require('lodash');
2022-03-17 16:54:37 +01:00
const cleanSchemaAttributes = require('./utils/clean-schema-attributes');
const loopContentTypeNames = require('./utils/loop-content-type-names');
const pascalCase = require('./utils/pascal-case');
2022-05-05 12:32:22 +02:00
const { hasFindMethod, isLocalizedPath } = require('./utils/routes');
2022-03-17 16:54:37 +01:00
/**
2022-04-05 10:57:35 +02:00
* @decription Get all open api schema objects for a given content type
2022-03-17 16:54:37 +01:00
*
* @param {object} apiInfo
* @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
*
* @returns {object} Open API schemas
*/
2022-04-01 18:10:59 +02:00
const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
2022-03-17 16:54:37 +01:00
// Store response and request schemas in an object
let schemas = {};
2023-03-14 11:10:55 +01:00
let strapiComponentSchemas = {};
2022-06-30 13:09:24 +02:00
// adds a ComponentSchema to the Schemas so it can be used as Ref
2023-03-09 11:38:01 +05:30
const didAddStrapiComponentsToSchemas = (schemaName, schema) => {
if (!Object.keys(schema) || !Object.keys(schema.properties)) return false;
// Add the Strapi components to the schema
2023-03-14 11:10:55 +01:00
strapiComponentSchemas = {
...strapiComponentSchemas,
2022-06-30 13:01:19 +02:00
[schemaName]: schema,
};
2023-03-09 11:38:01 +05:30
return true;
2022-06-30 13:01:19 +02:00
};
2022-03-17 16:54:37 +01:00
// Get all the route methods
2022-08-08 23:33:39 +02:00
const routeMethods = routeInfo.routes.map((route) => route.method);
2022-05-05 12:32:22 +02:00
// Check for localized paths
2022-08-08 23:33:39 +02:00
const hasLocalizationPath = routeInfo.routes.filter((route) =>
isLocalizedPath(route.path)
).length;
2023-03-09 11:38:01 +05:30
// Build the request schemas when the route has POST or PUT methods
2022-03-17 16:54:37 +01:00
if (routeMethods.includes('POST') || routeMethods.includes('PUT')) {
2022-05-05 12:32:22 +02:00
const attributesToOmit = [
'createdAt',
'updatedAt',
'publishedAt',
'publishedBy',
'updatedBy',
'createdBy',
'localizations',
];
const attributesForRequest = _.omit(attributes, attributesToOmit);
// Get a list of required attribute names
const requiredAttributes = Object.entries(attributesForRequest).reduce((acc, attribute) => {
const [attributeKey, attributeValue] = attribute;
2022-03-17 16:54:37 +01:00
if (attributeValue.required) {
acc.push(attributeKey);
}
return acc;
}, []);
2023-03-13 15:00:05 +01:00
2023-03-09 11:38:01 +05:30
// Build localization requests schemas
2022-04-29 10:05:29 +02:00
if (hasLocalizationPath) {
schemas = {
...schemas,
[`${pascalCase(uniqueName)}LocalizationRequest`]: {
required: [...requiredAttributes, 'locale'],
2022-04-29 10:05:29 +02:00
type: 'object',
2022-08-23 15:51:04 +02:00
properties: cleanSchemaAttributes(attributesForRequest, {
isRequest: true,
2023-03-09 11:38:01 +05:30
didAddStrapiComponentsToSchemas,
2022-08-23 15:51:04 +02:00
}),
2022-04-29 10:05:29 +02:00
},
};
}
2022-04-05 10:57:35 +02:00
// Build the request schema
2022-03-17 16:54:37 +01:00
schemas = {
...schemas,
2022-04-05 10:57:35 +02:00
[`${pascalCase(uniqueName)}Request`]: {
2022-03-17 16:54:37 +01:00
type: 'object',
required: ['data'],
2022-03-17 16:54:37 +01:00
properties: {
data: {
2023-03-14 11:10:55 +01:00
...(requiredAttributes.length && { required: requiredAttributes }),
2022-03-17 16:54:37 +01:00
type: 'object',
2022-08-23 15:51:04 +02:00
properties: cleanSchemaAttributes(attributesForRequest, {
isRequest: true,
2023-03-09 11:38:01 +05:30
didAddStrapiComponentsToSchemas,
2022-08-23 15:51:04 +02:00
}),
2022-03-17 16:54:37 +01:00
},
},
},
};
}
2023-03-13 15:00:05 +01:00
2023-03-09 11:38:01 +05:30
// Build the localization response schema
2022-05-02 11:09:43 +02:00
if (hasLocalizationPath) {
schemas = {
...schemas,
[`${pascalCase(uniqueName)}LocalizationResponse`]: {
type: 'object',
properties: {
2022-08-31 10:37:08 +00:00
id: { type: 'number' },
2023-03-09 11:38:01 +05:30
...cleanSchemaAttributes(attributes, {
didAddStrapiComponentsToSchemas,
}),
},
},
[`${pascalCase(uniqueName)}ResponseDataObjectLocalized`]: {
type: 'object',
properties: {
id: { type: 'number' },
attributes: {
type: 'object',
properties: cleanSchemaAttributes(attributes, {
didAddStrapiComponentsToSchemas,
}),
},
2022-05-02 11:09:43 +02:00
},
},
};
}
2023-03-13 15:00:05 +01:00
2022-04-05 10:57:35 +02:00
// Check for routes that need to return a list
2022-08-08 23:33:39 +02:00
const hasListOfEntities = routeInfo.routes.filter((route) => hasFindMethod(route.handler)).length;
2022-04-05 10:57:35 +02:00
if (hasListOfEntities) {
2023-03-09 11:38:01 +05:30
// Buld the localized list response schema
if (hasLocalizationPath) {
schemas = {
...schemas,
[`${pascalCase(uniqueName)}ListResponseDataItemLocalized`]: {
type: 'object',
properties: {
id: { type: 'number' },
attributes: {
type: 'object',
properties: cleanSchemaAttributes(attributes, {
didAddStrapiComponentsToSchemas,
}),
},
},
},
};
}
2022-04-05 10:57:35 +02:00
// Build the list response schema
schemas = {
...schemas,
2022-06-30 13:01:19 +02:00
[`${pascalCase(uniqueName)}ListResponseDataItem`]: {
type: 'object',
properties: {
2022-09-06 05:35:56 +00:00
id: { type: 'number' },
2022-06-30 13:01:19 +02:00
attributes: {
type: 'object',
properties: cleanSchemaAttributes(attributes, {
2023-03-09 11:38:01 +05:30
didAddStrapiComponentsToSchemas,
2022-06-30 13:01:19 +02:00
componentSchemaRefName: `#/components/schemas/${pascalCase(
uniqueName
)}ListResponseDataItemLocalized`,
}),
},
},
2022-06-30 13:01:19 +02:00
},
2022-04-05 10:57:35 +02:00
[`${pascalCase(uniqueName)}ListResponse`]: {
properties: {
data: {
type: 'array',
items: {
2022-06-30 13:01:19 +02:00
$ref: `#/components/schemas/${pascalCase(uniqueName)}ListResponseDataItem`,
2022-04-05 10:57:35 +02:00
},
},
meta: {
type: 'object',
properties: {
pagination: {
properties: {
page: { type: 'integer' },
pageSize: { type: 'integer', minimum: 25 },
pageCount: { type: 'integer', maximum: 1 },
total: { type: 'integer' },
},
},
},
},
},
},
};
}
// Build the response schema
2022-03-17 16:54:37 +01:00
schemas = {
...schemas,
[`${pascalCase(uniqueName)}ResponseDataObject`]: {
type: 'object',
2022-04-05 10:57:35 +02:00
properties: {
2022-09-06 05:35:56 +00:00
id: { type: 'number' },
2022-06-30 13:01:19 +02:00
attributes: {
2022-04-05 10:57:35 +02:00
type: 'object',
2022-06-30 13:01:19 +02:00
properties: cleanSchemaAttributes(attributes, {
2023-03-09 11:38:01 +05:30
didAddStrapiComponentsToSchemas,
2022-06-30 13:01:19 +02:00
componentSchemaRefName: `#/components/schemas/${pascalCase(
uniqueName
)}ResponseDataObjectLocalized`,
}),
2022-04-05 10:57:35 +02:00
},
2022-06-30 13:01:19 +02:00
},
},
[`${pascalCase(uniqueName)}Response`]: {
properties: {
data: {
2022-06-30 13:01:19 +02:00
$ref: `#/components/schemas/${pascalCase(uniqueName)}ResponseDataObject`,
2022-04-05 10:57:35 +02:00
},
meta: { type: 'object' },
},
},
2022-03-17 16:54:37 +01:00
};
2023-03-13 15:00:05 +01:00
2023-03-14 11:10:55 +01:00
return { ...schemas, ...strapiComponentSchemas };
2022-03-17 16:54:37 +01:00
};
2022-08-08 23:33:39 +02:00
const buildComponentSchema = (api) => {
2022-04-06 17:10:27 +02:00
// 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
2022-03-17 16:54:37 +01:00
return loopContentTypeNames(api, getAllSchemasForContentType);
};
module.exports = buildComponentSchema;