diff --git a/packages/plugins/documentation/server/services/helpers/build-api-endpoint-path.js b/packages/plugins/documentation/server/services/helpers/build-api-endpoint-path.js index 1cad6bd7f7..32b9b2eb64 100644 --- a/packages/plugins/documentation/server/services/helpers/build-api-endpoint-path.js +++ b/packages/plugins/documentation/server/services/helpers/build-api-endpoint-path.js @@ -7,7 +7,7 @@ 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 { hasFindMethod } = require('./utils/routes'); +const { hasFindMethod, isLocalizedPath } = require('./utils/routes'); /** * @description Parses a route with ':variable' @@ -93,12 +93,17 @@ const getPaths = ({ routeInfo, uniqueName, contentTypeInfo }) => { const paths = contentTypeRoutes.reduce((acc, route) => { // TODO: Find a more reliable way to determine list of entities vs a single entity const isListOfEntities = hasFindMethod(route.handler); - const isLocalizationPath = route.path.includes('localizations'); + const isLocalizationPath = isLocalizedPath(route.path); const methodVerb = route.method.toLowerCase(); const hasPathParams = route.path.includes('/:'); const pathWithPrefix = getPathWithPrefix(routeInfo.prefix, route); const routePath = hasPathParams ? parsePathWithVariables(pathWithPrefix) : pathWithPrefix; - const { responses } = getApiResponses(uniqueName, route, isListOfEntities); + const { responses } = getApiResponses({ + uniqueName, + route, + isListOfEntities, + isLocalizationPath, + }); const swaggerConfig = { responses, diff --git a/packages/plugins/documentation/server/services/helpers/build-component-schema.js b/packages/plugins/documentation/server/services/helpers/build-component-schema.js index b9508f5b8b..36e66b9618 100644 --- a/packages/plugins/documentation/server/services/helpers/build-component-schema.js +++ b/packages/plugins/documentation/server/services/helpers/build-component-schema.js @@ -1,9 +1,10 @@ 'use strict'; +const _ = require('lodash'); const cleanSchemaAttributes = require('./utils/clean-schema-attributes'); const loopContentTypeNames = require('./utils/loop-content-type-names'); const pascalCase = require('./utils/pascal-case'); -const { hasFindMethod } = require('./utils/routes'); +const { hasFindMethod, isLocalizedPath } = require('./utils/routes'); /** * @decription Get all open api schema objects for a given content type @@ -20,13 +21,24 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => { let schemas = {}; // Get all the route methods const routeMethods = routeInfo.routes.map((route) => route.method); + // Check for localized paths const hasLocalizationPath = routeInfo.routes.filter((route) => - route.path.includes('localizations') + isLocalizedPath(route.path) ).length; - // When the route methods contain any post or put requests if (routeMethods.includes('POST') || routeMethods.includes('PUT')) { - const requiredAttributes = Object.entries(attributes) + const attributesToOmit = [ + 'createdAt', + 'updatedAt', + 'publishedAt', + 'publishedBy', + 'updatedBy', + 'createdBy', + 'localizations', + ]; + const attributesForRequest = _.omit(attributes, attributesToOmit); + + const requiredAttributes = Object.entries(attributesForRequest) .filter(([, attribute]) => attribute.required) .map(([attributeName, attribute]) => { return { [attributeName]: attribute }; @@ -35,19 +47,14 @@ const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => { const requestAttributes = routeMethods.includes('POST') && requiredAttributes.length ? Object.assign({}, ...requiredAttributes) - : attributes; + : attributesForRequest; if (hasLocalizationPath) { - const localizationsRequestAttributes = { - ...requestAttributes, - locale: { type: 'string' }, - }; - schemas = { ...schemas, [`${pascalCase(uniqueName)}LocalizationRequest`]: { type: 'object', - properties: cleanSchemaAttributes(localizationsRequestAttributes, { isRequest: true }), + properties: cleanSchemaAttributes(requestAttributes, { isRequest: true }), }, }; } diff --git a/packages/plugins/documentation/server/services/helpers/utils/clean-schema-attributes.js b/packages/plugins/documentation/server/services/helpers/utils/clean-schema-attributes.js index 62edc138e1..4fb7fa4a76 100644 --- a/packages/plugins/documentation/server/services/helpers/utils/clean-schema-attributes.js +++ b/packages/plugins/documentation/server/services/helpers/utils/clean-schema-attributes.js @@ -113,7 +113,7 @@ const cleanSchemaAttributes = (attributes, { typeMap = new Map(), isRequest = fa break; } case 'dynamiczone': { - const components = attribute.components.map(component => { + const components = attribute.components.map((component) => { const componentAttributes = strapi.components[component].attributes; return { type: 'object', @@ -169,6 +169,14 @@ const cleanSchemaAttributes = (attributes, { typeMap = new Map(), isRequest = fa break; } + if (prop === 'localizations') { + attributesCopy[prop] = { + type: 'array', + items: { type: 'object', properties: {} }, + }; + break; + } + if (!attribute.target || typeMap.has(attribute.target)) { attributesCopy[prop] = { type: 'object', diff --git a/packages/plugins/documentation/server/services/helpers/utils/get-api-responses.js b/packages/plugins/documentation/server/services/helpers/utils/get-api-responses.js index 4977b72b4b..0b8847fded 100644 --- a/packages/plugins/documentation/server/services/helpers/utils/get-api-responses.js +++ b/packages/plugins/documentation/server/services/helpers/utils/get-api-responses.js @@ -11,7 +11,12 @@ const pascalCase = require('./pascal-case'); * * @returns The Swagger responses */ -const getApiResponse = (name, route, isListOfEntities = false) => { +const getApiResponse = ({ + uniqueName, + route, + isListOfEntities = false, + isLocalizationPath = false, +}) => { const getSchema = () => { if (route.method === 'DELETE') { return { @@ -20,18 +25,22 @@ const getApiResponse = (name, route, isListOfEntities = false) => { }; } - if (isListOfEntities) { - return { $ref: `#/components/schemas/${pascalCase(name)}ListResponse` }; + if (isLocalizationPath) { + return { $ref: `#/components/schemas/${pascalCase(uniqueName)}LocalizationResponse` }; } - return { $ref: `#/components/schemas/${pascalCase(name)}Response` }; + if (isListOfEntities) { + return { $ref: `#/components/schemas/${pascalCase(uniqueName)}ListResponse` }; + } + + return { $ref: `#/components/schemas/${pascalCase(uniqueName)}Response` }; }; const schema = getSchema(); return { responses: { - '200': { + 200: { description: 'OK', content: { 'application/json': { @@ -39,7 +48,7 @@ const getApiResponse = (name, route, isListOfEntities = false) => { }, }, }, - '400': { + 400: { description: 'Bad Request', content: { 'application/json': { @@ -49,7 +58,7 @@ const getApiResponse = (name, route, isListOfEntities = false) => { }, }, }, - '401': { + 401: { description: 'Unauthorized', content: { 'application/json': { @@ -59,7 +68,7 @@ const getApiResponse = (name, route, isListOfEntities = false) => { }, }, }, - '403': { + 403: { description: 'Forbidden', content: { 'application/json': { @@ -69,7 +78,7 @@ const getApiResponse = (name, route, isListOfEntities = false) => { }, }, }, - '404': { + 404: { description: 'Not Found', content: { 'application/json': { @@ -79,7 +88,7 @@ const getApiResponse = (name, route, isListOfEntities = false) => { }, }, }, - '500': { + 500: { description: 'Internal Server Error', content: { 'application/json': {