mirror of
https://github.com/strapi/strapi.git
synced 2025-12-28 07:33:17 +00:00
migrate backend to v4
This commit is contained in:
parent
41a7f31e3e
commit
3e9731a2af
@ -5,7 +5,7 @@ module.exports = {
|
||||
routes: [
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/',
|
||||
path: '/restaurants',
|
||||
handler: 'restaurant.find',
|
||||
config: {
|
||||
policies: [],
|
||||
@ -13,7 +13,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/:id',
|
||||
path: '/restaurants/:id',
|
||||
handler: 'restaurant.findOne',
|
||||
config: {
|
||||
policies: [],
|
||||
@ -21,7 +21,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
path: '/restaurants',
|
||||
handler: 'restaurant.create',
|
||||
config: {
|
||||
policies: [],
|
||||
@ -29,7 +29,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
method: 'PUT',
|
||||
path: '/:id',
|
||||
path: '/restaurants/:id',
|
||||
handler: 'restaurant.update',
|
||||
config: {
|
||||
policies: [],
|
||||
@ -37,7 +37,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
method: 'DELETE',
|
||||
path: '/:id',
|
||||
path: '/restaurants/:id',
|
||||
handler: 'restaurant.delete',
|
||||
config: {
|
||||
policies: [],
|
||||
|
||||
@ -19,7 +19,8 @@
|
||||
"koa-static": "^5.0.0",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "^2.29.1",
|
||||
"path-to-regexp": "^3.1.0",
|
||||
"path-to-regexp": "6.2.0",
|
||||
"pluralize": "8.0.0",
|
||||
"react": "^17.0.2",
|
||||
"react-copy-to-clipboard": "^5.0.3",
|
||||
"react-dom": "^17.0.2",
|
||||
|
||||
107
packages/plugins/documentation/server/bootstrap.js
vendored
107
packages/plugins/documentation/server/bootstrap.js
vendored
@ -1,10 +1,6 @@
|
||||
/* eslint-disable no-unreachable */
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const _ = require('lodash');
|
||||
|
||||
// Add permissions
|
||||
const RBAC_ACTIONS = [
|
||||
{
|
||||
@ -29,11 +25,13 @@ const RBAC_ACTIONS = [
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{strapi: import("@strapi/strapi").Strapi}} args
|
||||
*/
|
||||
module.exports = async ({ strapi }) => {
|
||||
await strapi.admin.services.permission.actionProvider.registerMany(RBAC_ACTIONS);
|
||||
|
||||
return;
|
||||
|
||||
// Check if the plugin users-permissions is installed because the documentation needs it
|
||||
if (Object.keys(strapi.plugins).indexOf('users-permissions') === -1) {
|
||||
throw new Error(
|
||||
@ -41,7 +39,11 @@ module.exports = async ({ strapi }) => {
|
||||
);
|
||||
}
|
||||
|
||||
const pluginStore = strapi.store({ type: 'plugin', name: 'documentation' });
|
||||
const pluginStore = strapi.store({
|
||||
environment: '',
|
||||
type: 'plugin',
|
||||
name: 'documentation',
|
||||
});
|
||||
|
||||
const restrictedAccess = await pluginStore.get({ key: 'config' });
|
||||
|
||||
@ -49,91 +51,8 @@ module.exports = async ({ strapi }) => {
|
||||
pluginStore.set({ key: 'config', value: { restrictedAccess: false } });
|
||||
}
|
||||
|
||||
let shouldUpdateFullDoc = false;
|
||||
const services = strapi.plugins['documentation'].services.documentation;
|
||||
// Generate plugins' documentation
|
||||
const pluginsWithDocumentationNeeded = services.getPluginsWithDocumentationNeeded();
|
||||
|
||||
pluginsWithDocumentationNeeded.forEach(plugin => {
|
||||
const isDocExisting = services.checkIfPluginDocumentationFolderExists(plugin);
|
||||
|
||||
if (!isDocExisting) {
|
||||
services.createDocumentationDirectory(services.getPluginDocumentationPath(plugin));
|
||||
// create the overrides directory
|
||||
services.createDocumentationDirectory(services.getPluginOverrideDocumentationPath(plugin));
|
||||
services.createPluginDocumentationFile(plugin);
|
||||
shouldUpdateFullDoc = true;
|
||||
} else {
|
||||
const needToUpdatePluginDoc = services.checkIfPluginDocNeedsUpdate(plugin);
|
||||
|
||||
if (needToUpdatePluginDoc) {
|
||||
services.createPluginDocumentationFile(plugin);
|
||||
shouldUpdateFullDoc = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieve all the apis from the apis directory
|
||||
const apis = services.getApis();
|
||||
// Generate APIS' documentation
|
||||
apis.forEach(api => {
|
||||
const isDocExisting = services.checkIfDocumentationFolderExists(api);
|
||||
|
||||
if (!isDocExisting) {
|
||||
// If the documentation directory doesn't exist create it
|
||||
services.createDocumentationDirectory(services.getDocumentationPath(api));
|
||||
// Create the overrides directory
|
||||
services.createDocumentationDirectory(services.getDocumentationOverridesPath(api));
|
||||
// Create the documentation files per version
|
||||
services.createDocumentationFile(api); // Then create the {api}.json documentation file
|
||||
shouldUpdateFullDoc = true;
|
||||
} else {
|
||||
const needToUpdateAPIDoc = services.checkIfAPIDocNeedsUpdate(api);
|
||||
|
||||
if (needToUpdateAPIDoc) {
|
||||
services.createDocumentationFile(api);
|
||||
shouldUpdateFullDoc = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const fullDoc = services.generateFullDoc();
|
||||
// Verify that the correct documentation folder exists in the documentation plugin
|
||||
const isMergedDocumentationExists = services.checkIfMergedDocumentationFolderExists();
|
||||
const documentationPath = services.getMergedDocumentationPath();
|
||||
|
||||
if (isMergedDocumentationExists) {
|
||||
/**
|
||||
* Retrieve all tags from the documentation and join them
|
||||
* @param {Object} documentation
|
||||
* @returns {String}
|
||||
*/
|
||||
const getDocTagsToString = documentation => {
|
||||
return _.get(documentation, 'tags', [])
|
||||
.map(tag => {
|
||||
return tag.name.toLowerCase();
|
||||
})
|
||||
.sort((a, b) => a - b)
|
||||
.join('.');
|
||||
};
|
||||
const oldDoc = require(path.resolve(documentationPath, 'full_documentation.json'));
|
||||
const oldDocTags = getDocTagsToString(oldDoc);
|
||||
const currentDocTags = getDocTagsToString(fullDoc);
|
||||
|
||||
// If the tags are different (an api has been deleted) we need to rebuild the documentation
|
||||
if (oldDocTags !== currentDocTags) {
|
||||
shouldUpdateFullDoc = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isMergedDocumentationExists || shouldUpdateFullDoc) {
|
||||
// Create the folder
|
||||
services.createDocumentationDirectory(documentationPath);
|
||||
// Write the file
|
||||
fs.writeFileSync(
|
||||
path.resolve(documentationPath, 'full_documentation.json'),
|
||||
JSON.stringify(fullDoc, null, 2),
|
||||
'utf8'
|
||||
);
|
||||
}
|
||||
await strapi
|
||||
.plugin('documentation')
|
||||
.service('documentation')
|
||||
.generateFullDoc();
|
||||
};
|
||||
|
||||
@ -21,10 +21,11 @@ module.exports = {
|
||||
path: '/documentation',
|
||||
showGeneratedFiles: true,
|
||||
generateDefaultResponse: true,
|
||||
plugins: ['email', 'upload', 'users-permissions'],
|
||||
},
|
||||
servers: [
|
||||
{
|
||||
url: 'http://localhost:1337',
|
||||
url: 'http://localhost:1337/api',
|
||||
description: 'Development server',
|
||||
},
|
||||
{
|
||||
@ -45,4 +46,13 @@ module.exports = {
|
||||
bearerAuth: [],
|
||||
},
|
||||
],
|
||||
components: {
|
||||
securitySchemes: {
|
||||
bearerAuth: {
|
||||
type: 'http',
|
||||
scheme: 'bearer',
|
||||
bearerFormat: 'JWT',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -17,14 +17,14 @@ const koaStatic = require('koa-static');
|
||||
module.exports = {
|
||||
async getInfos(ctx) {
|
||||
try {
|
||||
const service = strapi.plugins.documentation.services.documentation;
|
||||
const docVersions = service.retrieveDocumentationVersions();
|
||||
const form = await service.retrieveFrontForm();
|
||||
const docService = strapi.plugin('documentation').service('documentation');
|
||||
const docVersions = docService.getDocumentationVersions();
|
||||
const form = await docService.getFrontendForm();
|
||||
|
||||
ctx.send({
|
||||
docVersions,
|
||||
currentVersion: service.getDocumentationVersion(),
|
||||
prefix: strapi.config.get('plugin.documentation.x-strapi-config').path,
|
||||
currentVersion: docService.getDocumentationVersion(),
|
||||
prefix: strapi.plugin('documentation').config('x-strapi-config').path,
|
||||
form,
|
||||
});
|
||||
} catch (err) {
|
||||
@ -45,6 +45,7 @@ module.exports = {
|
||||
: strapi.plugins.documentation.config.info.version;
|
||||
const openAPISpecsPath = path.join(
|
||||
strapi.config.appPath,
|
||||
'src',
|
||||
'extensions',
|
||||
'documentation',
|
||||
'documentation',
|
||||
@ -66,6 +67,7 @@ module.exports = {
|
||||
try {
|
||||
const layoutPath = path.resolve(
|
||||
strapi.config.appPath,
|
||||
'src',
|
||||
'extensions',
|
||||
'documentation',
|
||||
'public',
|
||||
@ -80,6 +82,7 @@ module.exports = {
|
||||
try {
|
||||
const staticFolder = path.resolve(
|
||||
strapi.config.appPath,
|
||||
'src',
|
||||
'extensions',
|
||||
'documentation',
|
||||
'public'
|
||||
@ -119,6 +122,7 @@ module.exports = {
|
||||
try {
|
||||
const layoutPath = path.resolve(
|
||||
strapi.config.appPath,
|
||||
'src',
|
||||
'extensions',
|
||||
'documentation',
|
||||
'public',
|
||||
@ -132,6 +136,7 @@ module.exports = {
|
||||
try {
|
||||
const staticFolder = path.resolve(
|
||||
strapi.config.appPath,
|
||||
'src',
|
||||
'extensions',
|
||||
'documentation',
|
||||
'public'
|
||||
@ -176,8 +181,9 @@ module.exports = {
|
||||
},
|
||||
|
||||
async regenerateDoc(ctx) {
|
||||
const service = strapi.plugins.documentation.services.documentation;
|
||||
const documentationVersions = service.retrieveDocumentationVersions().map(el => el.version);
|
||||
const service = strapi.plugin('documentation').service('documentation');
|
||||
const documentationVersions = service.getDocumentationVersions().map(el => el.version);
|
||||
|
||||
const {
|
||||
request: {
|
||||
body: { version },
|
||||
@ -211,6 +217,7 @@ module.exports = {
|
||||
JSON.stringify(fullDoc, null, 2),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
ctx.send({ ok: true });
|
||||
} catch (err) {
|
||||
ctx.badRequest(null, admin ? 'documentation.error.regenerateDoc' : 'An error occured');
|
||||
@ -221,8 +228,8 @@ module.exports = {
|
||||
|
||||
async deleteDoc(ctx) {
|
||||
strapi.reload.isWatching = false;
|
||||
const service = strapi.plugins.documentation.services.documentation;
|
||||
const documentationVersions = service.retrieveDocumentationVersions().map(el => el.version);
|
||||
const service = strapi.plugin('documentation').service('documentation');
|
||||
const documentationVersions = service.getDocumentationVersions().map(el => el.version);
|
||||
|
||||
const {
|
||||
params: { version },
|
||||
|
||||
@ -54,6 +54,9 @@ module.exports = {
|
||||
defer: true,
|
||||
})(ctx, next);
|
||||
},
|
||||
config: {
|
||||
auth: false,
|
||||
},
|
||||
},
|
||||
]);
|
||||
},
|
||||
|
||||
@ -28,5 +28,5 @@ module.exports = async (ctx, next) => {
|
||||
}
|
||||
|
||||
// Execute the action.
|
||||
await next();
|
||||
return next();
|
||||
};
|
||||
@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const index = require('./index-policy');
|
||||
|
||||
module.exports = {
|
||||
index,
|
||||
};
|
||||
@ -6,10 +6,11 @@ module.exports = [
|
||||
path: '/',
|
||||
handler: 'documentation.index',
|
||||
config: {
|
||||
policies: [
|
||||
'plugin::documentation.index',
|
||||
{ name: 'admin::hasPermissions', config: { actions: ['plugin::documentation.read'] } },
|
||||
],
|
||||
auth: false,
|
||||
// middlewares: [restrictAccess],
|
||||
// policies: [
|
||||
// { name: 'admin::hasPermissions', options: { actions: ['plugin::documentation.read'] } },
|
||||
// ],
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -17,10 +18,11 @@ module.exports = [
|
||||
path: '/v:major(\\d+).:minor(\\d+).:patch(\\d+)',
|
||||
handler: 'documentation.index',
|
||||
config: {
|
||||
policies: [
|
||||
'plugin::documentation.index',
|
||||
{ name: 'admin::hasPermissions', config: { actions: ['plugin::documentation.read'] } },
|
||||
],
|
||||
auth: false,
|
||||
// middlewares: [restrictAccess],
|
||||
// policies: [
|
||||
// { name: 'admin::hasPermissions', options: { actions: ['plugin::documentation.read'] } },
|
||||
// ],
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,131 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const pathToRegexp = require('path-to-regexp');
|
||||
|
||||
const queryParams = require('../query-params');
|
||||
const buildApiRequests = require('./build-api-requests');
|
||||
const buildApiResponses = require('./build-api-responses');
|
||||
|
||||
/**
|
||||
* @description Parses a route with ':variable'
|
||||
*
|
||||
* @param {string} routePath - The route's path property
|
||||
* @returns '{variable}'
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @returns Swagger path params object
|
||||
*/
|
||||
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' },
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {array} routes - The routes for a given api or plugin
|
||||
* @param {object} attributes - The attributes for a given api or plugin
|
||||
* @param {string} tag - A descriptor for OpenAPI
|
||||
*
|
||||
* @returns object of OpenAPI paths for each route
|
||||
*/
|
||||
const getPaths = (routes, attributes, tag) => {
|
||||
const paths = routes.reduce(
|
||||
(acc, route) => {
|
||||
// TODO: Find a more reliable way to determine list of entities vs a single entity
|
||||
const isListOfEntities = route.handler.split('.').pop() === 'find';
|
||||
const hasPathParams = route.path.includes('/:');
|
||||
const methodVerb = route.method.toLowerCase();
|
||||
const routePath = hasPathParams ? parsePathWithVariables(route.path) : route.path;
|
||||
|
||||
const { responses } = buildApiResponses(attributes, route, isListOfEntities);
|
||||
_.set(acc.paths, `${routePath}.${methodVerb}.responses`, responses);
|
||||
_.set(acc.paths, `${routePath}.${methodVerb}.tags`, [_.upperFirst(tag)]);
|
||||
|
||||
if (isListOfEntities) {
|
||||
_.set(acc.paths, `${routePath}.${methodVerb}.parameters`, queryParams);
|
||||
}
|
||||
|
||||
if (hasPathParams) {
|
||||
const pathParams = getPathParams(route.path);
|
||||
_.set(acc.paths, `${routePath}.${methodVerb}.parameters`, pathParams);
|
||||
}
|
||||
|
||||
if (methodVerb === 'post' || methodVerb === 'put') {
|
||||
const { requestBody } = buildApiRequests(attributes, route);
|
||||
|
||||
_.set(acc.paths, `${routePath}.${methodVerb}.requestBody`, requestBody);
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{ paths: {} }
|
||||
);
|
||||
|
||||
return paths;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
module.exports = api => {
|
||||
if (!api.ctNames.length && api.getter === 'plugin') {
|
||||
// Set arbitrary attributes
|
||||
const attributes = { foo: { type: 'string' } };
|
||||
const routes = strapi.plugin(api.name).routes['admin'].routes;
|
||||
|
||||
return getPaths(routes, attributes, api.name);
|
||||
}
|
||||
|
||||
// An api could have multiple contentTypes
|
||||
for (const contentTypeName of api.ctNames) {
|
||||
// Get the attributes found on the api's contentType
|
||||
const attributes = strapi.contentType(`${api.getter}::${api.name}.${contentTypeName}`)
|
||||
.attributes;
|
||||
|
||||
// Get the routes for the current api
|
||||
const routes =
|
||||
api.getter === 'plugin'
|
||||
? strapi.plugin(api.name).routes['content-api'].routes
|
||||
: strapi.api[api.name].routes[contentTypeName].routes;
|
||||
|
||||
// Parse an identifier for OpenAPI tag if the api name and contentType name don't match
|
||||
const tag = api.name === contentTypeName ? api.name : `${api.name} - ${contentTypeName}`;
|
||||
return getPaths(routes, attributes, tag);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
const cleanSchemaAttributes = require('../clean-schema-attributes');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} attributes - The attributes found on a contentType
|
||||
* @param {object} route - The current route
|
||||
*
|
||||
* @returns The Swagger requestBody
|
||||
*/
|
||||
module.exports = (attributes, route) => {
|
||||
const requiredAttributes = Object.entries(attributes)
|
||||
.filter(([, val]) => {
|
||||
return val.required;
|
||||
})
|
||||
.map(([attr, val]) => {
|
||||
return { [attr]: val };
|
||||
});
|
||||
|
||||
const requestAttributes =
|
||||
route.method === 'POST' && requiredAttributes.length
|
||||
? Object.assign({}, ...requiredAttributes)
|
||||
: attributes;
|
||||
|
||||
return {
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
properties: {
|
||||
data: {
|
||||
type: 'object',
|
||||
properties: cleanSchemaAttributes(requestAttributes),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
const getSchemaData = require('../get-schema-data');
|
||||
const cleanSchemaAttributes = require('../clean-schema-attributes');
|
||||
const errorResponse = require('../error-response');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {boolean} isSingleEntity - Checks for a single entity
|
||||
* @returns {object} The correctly formatted meta object
|
||||
*/
|
||||
const getMeta = isListOfEntities => {
|
||||
if (isListOfEntities) {
|
||||
return {
|
||||
properties: {
|
||||
pagination: {
|
||||
properties: {
|
||||
page: { type: 'integer' },
|
||||
pageSize: { type: 'integer', minimum: 25 },
|
||||
pageCount: { type: 'integer', maximum: 1 },
|
||||
total: { type: 'integer' },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return { type: 'object' };
|
||||
};
|
||||
|
||||
/**
|
||||
* @description - Builds the Swagger response object for a given api
|
||||
*
|
||||
* @param {object} attributes - The attributes found on a contentType
|
||||
* @param {object} route - The current route
|
||||
* @param {boolean} isListOfEntities - Checks for a list of entitities
|
||||
*
|
||||
* @returns The Swagger responses
|
||||
*/
|
||||
module.exports = (attributes, route, isListOfEntities = false) => {
|
||||
let schema;
|
||||
if (route.method === 'DELETE') {
|
||||
schema = {
|
||||
type: 'integer',
|
||||
format: 'int64',
|
||||
};
|
||||
} else {
|
||||
schema = {
|
||||
properties: {
|
||||
data: getSchemaData(isListOfEntities, cleanSchemaAttributes(attributes)),
|
||||
meta: getMeta(isListOfEntities),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
responses: {
|
||||
'200': {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema,
|
||||
},
|
||||
},
|
||||
},
|
||||
'403': {
|
||||
description: 'Forbidden',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: errorResponse.Error,
|
||||
},
|
||||
},
|
||||
},
|
||||
'404': {
|
||||
description: 'Not found',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: errorResponse.Error,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const buildApiResponses = require('./build-api-responses');
|
||||
const buildApiRequests = require('./build-api-requests');
|
||||
const builApiEndpointPath = require('./build-api-endpoint-path');
|
||||
|
||||
module.exports = {
|
||||
buildApiResponses,
|
||||
buildApiRequests,
|
||||
builApiEndpointPath,
|
||||
};
|
||||
@ -0,0 +1,86 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const getSchemaData = require('./get-schema-data');
|
||||
|
||||
/**
|
||||
* @description - Converts types found on attributes to OpenAPI specific data types
|
||||
*
|
||||
* @param {object} attributes - The attributes found on a contentType
|
||||
|
||||
* @returns Attributes using OpenAPI acceptable data types
|
||||
*/
|
||||
|
||||
const cleanSchemaAttributes = attributes => {
|
||||
const attributesCopy = _.cloneDeep(attributes);
|
||||
|
||||
for (const prop in attributesCopy) {
|
||||
const attribute = attributesCopy[prop];
|
||||
if (attribute.default) {
|
||||
delete attributesCopy[prop].default;
|
||||
}
|
||||
|
||||
switch (attribute.type) {
|
||||
case 'datetime': {
|
||||
attributesCopy[prop] = { type: 'string' };
|
||||
break;
|
||||
}
|
||||
case 'decimal': {
|
||||
attributesCopy[prop] = { type: 'number', format: 'float' };
|
||||
break;
|
||||
}
|
||||
case 'integer': {
|
||||
attributesCopy[prop] = { type: 'integer' };
|
||||
break;
|
||||
}
|
||||
case 'json': {
|
||||
attributesCopy[prop] = {};
|
||||
break;
|
||||
}
|
||||
case 'uid': {
|
||||
attributesCopy[prop] = { type: 'string', format: 'uuid' };
|
||||
break;
|
||||
}
|
||||
case 'media': {
|
||||
const imageAttributes = strapi.plugin('upload').contentType('file').attributes;
|
||||
const isListOfEntities = attribute.multiple;
|
||||
|
||||
attributesCopy[prop] = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: getSchemaData(isListOfEntities, cleanSchemaAttributes(imageAttributes)),
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 'component': {
|
||||
const componentAttributes = strapi.components[attribute.component].attributes;
|
||||
const isListOfEntities = attribute.repeatable;
|
||||
|
||||
attributesCopy[prop] = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: getSchemaData(isListOfEntities, cleanSchemaAttributes(componentAttributes)),
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 'relation': {
|
||||
// TODO: Sanitize relation attributes and list them in the schema
|
||||
const isListOfEntities = attribute.relation.includes('ToMany');
|
||||
attributesCopy[prop] = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
data: getSchemaData(isListOfEntities, {}),
|
||||
},
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attributesCopy;
|
||||
};
|
||||
|
||||
module.exports = cleanSchemaAttributes;
|
||||
@ -0,0 +1,17 @@
|
||||
{
|
||||
"Error": {
|
||||
"required": [
|
||||
"code",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @description Determines the format of the data response
|
||||
*
|
||||
* @param {boolean} isListOfEntities - Checks for a multiple entities
|
||||
* @param {object} attributes - The attributes found on a contentType
|
||||
|
||||
* @returns object | array of attributes
|
||||
*/
|
||||
module.exports = (isListOfEntities, attributes) => {
|
||||
if (isListOfEntities) {
|
||||
return {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
attributes: { type: 'object', properties: attributes },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
attributes: { type: 'object', properties: attributes },
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,82 @@
|
||||
[
|
||||
{
|
||||
"name": "sort",
|
||||
"in": "query",
|
||||
"description": "Sort by attributes ascending (asc) or descending (desc)",
|
||||
"deprecated": false,
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pagination[withCount]",
|
||||
"in": "query",
|
||||
"description": "Retun page/pageSize (default: true)",
|
||||
"deprecated": false,
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pagination[page]",
|
||||
"in": "query",
|
||||
"description": "Page number (default: 0)",
|
||||
"deprecated": false,
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pagination[pageSize]",
|
||||
"in": "query",
|
||||
"description": "Page size (default: 25)",
|
||||
"deprecated": false,
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pagination[start]",
|
||||
"in": "query",
|
||||
"description": "Offset value (default: 0)",
|
||||
"deprecated": false,
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pagination[limit]",
|
||||
"in": "query",
|
||||
"description": "Number of entities to return (default: 25)",
|
||||
"deprecated": false,
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "fields",
|
||||
"in": "query",
|
||||
"description": "Fields to return (ex: title,author)",
|
||||
"deprecated": false,
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "populate",
|
||||
"in": "query",
|
||||
"description": "Relations to return",
|
||||
"deprecated": false,
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const bootstrap = require('./server/bootstrap');
|
||||
const policies = require('./server/policies');
|
||||
const services = require('./server/services');
|
||||
const routes = require('./server/routes');
|
||||
const controllers = require('./server/controllers');
|
||||
@ -15,7 +14,6 @@ module.exports = () => {
|
||||
routes,
|
||||
controllers,
|
||||
middlewares,
|
||||
policies,
|
||||
services,
|
||||
};
|
||||
};
|
||||
|
||||
15
yarn.lock
15
yarn.lock
@ -18506,6 +18506,11 @@ path-to-regexp@0.1.7:
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
||||
|
||||
path-to-regexp@6.2.0, path-to-regexp@^6.1.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38"
|
||||
integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==
|
||||
|
||||
path-to-regexp@^1.7.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
|
||||
@ -18513,16 +18518,6 @@ path-to-regexp@^1.7.0:
|
||||
dependencies:
|
||||
isarray "0.0.1"
|
||||
|
||||
path-to-regexp@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.2.0.tgz#fa7877ecbc495c601907562222453c43cc204a5f"
|
||||
integrity sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==
|
||||
|
||||
path-to-regexp@^6.1.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38"
|
||||
integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==
|
||||
|
||||
path-type@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user