diff --git a/packages/core/admin/server/controllers/__tests__/content-api.test.js b/packages/core/admin/server/controllers/__tests__/content-api.test.js index 6fce23383b..241ae3c2ae 100644 --- a/packages/core/admin/server/controllers/__tests__/content-api.test.js +++ b/packages/core/admin/server/controllers/__tests__/content-api.test.js @@ -35,4 +35,143 @@ describe('Content API permissions', () => { expect(getActionsMap).toHaveBeenCalled(); expect(send).toHaveBeenCalledWith({ data: actionsMap }); }); + + const routesMap = { + 'api::address': [ + { + method: 'GET', + path: '/api/addresses', + handler: 'api::address.address.find', + config: { + auth: false, + }, + info: { + apiName: 'address', + type: 'content-api', + }, + }, + { + method: 'GET', + path: '/api/addresses/:id', + handler: 'api::address.address.findOne', + config: { + auth: { + scope: ['api::address.address.findOne'], + }, + }, + info: { + apiName: 'address', + type: 'content-api', + }, + }, + ], + 'api::category': [ + { + method: 'GET', + path: '/api/categories', + handler: 'api::category.category.find', + config: { + auth: { + scope: ['api::category.category.find'], + }, + }, + info: { + apiName: 'category', + type: 'content-api', + }, + }, + { + method: 'GET', + path: '/api/categories/:id', + handler: 'api::category.category.findOne', + config: { + auth: { + scope: ['api::category.category.findOne'], + }, + }, + info: { + apiName: 'category', + type: 'content-api', + }, + }, + { + method: 'POST', + path: '/api/categories', + handler: 'api::category.category.create', + config: { + auth: { + scope: ['api::category.category.create'], + }, + }, + info: { + apiName: 'category', + type: 'content-api', + }, + }, + { + method: 'PUT', + path: '/api/categories/:id', + handler: 'api::category.category.update', + config: { + auth: { + scope: ['api::category.category.update'], + }, + }, + info: { + apiName: 'category', + type: 'content-api', + }, + }, + { + method: 'DELETE', + path: '/api/categories/:id', + handler: 'api::category.category.delete', + config: { + auth: { + scope: ['api::category.category.delete'], + }, + }, + info: { + apiName: 'category', + type: 'content-api', + }, + }, + { + method: 'POST', + path: '/api/categories/:id/localizations', + handler: 'category.createLocalization', + config: { + policies: [], + auth: { + scope: ['api::category.category.createLocalization'], + }, + }, + info: { + apiName: 'category', + type: 'content-api', + }, + }, + ], + }; + + test('return content api routes successfully', async () => { + const getRoutes = jest.fn().mockResolvedValue(routesMap); + const send = jest.fn(); + const ctx = createContext({}, { send }); + + global.strapi = { + admin: { + services: { + 'content-api': { + getRoutes, + }, + }, + }, + }; + + await contentApiController.getRoutes(ctx); + + expect(getRoutes).toHaveBeenCalled(); + expect(send).toHaveBeenCalledWith({ data: routesMap }); + }); }); diff --git a/packages/core/admin/server/controllers/content-api.js b/packages/core/admin/server/controllers/content-api.js index 7a988a1713..42bf2fdbf7 100644 --- a/packages/core/admin/server/controllers/content-api.js +++ b/packages/core/admin/server/controllers/content-api.js @@ -1,9 +1,19 @@ 'use strict'; +const { getService } = require('../utils'); + module.exports = { async getPermissions(ctx) { const actionsMap = await strapi.contentAPI.permissions.getActionsMap(); ctx.send({ data: actionsMap }); }, + + async getRoutes(ctx) { + const contentApiService = getService('content-api'); + + const routesMap = await contentApiService.getRoutes(); + + ctx.send({ data: routesMap }); + }, }; diff --git a/packages/core/admin/server/routes/content-api.js b/packages/core/admin/server/routes/content-api.js index cc563c1b94..8e64b6f777 100644 --- a/packages/core/admin/server/routes/content-api.js +++ b/packages/core/admin/server/routes/content-api.js @@ -9,4 +9,12 @@ module.exports = [ policies: ['admin::isAuthenticatedAdmin'], }, }, + { + method: 'GET', + path: '/content-api/routes', + handler: 'content-api.getRoutes', + config: { + policies: ['admin::isAuthenticatedAdmin'], + }, + }, ]; diff --git a/packages/core/admin/server/services/content-api.js b/packages/core/admin/server/services/content-api.js new file mode 100644 index 0000000000..2a652b6e7d --- /dev/null +++ b/packages/core/admin/server/services/content-api.js @@ -0,0 +1,65 @@ +'use strict'; + +const _ = require('lodash'); + +const transformRoutePrefixFor = (pluginName) => (route) => { + const prefix = route.config && route.config.prefix; + const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`; + + return { + ...route, + path, + }; +}; + +const getRoutes = async () => { + const routesMap = {}; + + _.forEach(strapi.api, (api, apiName) => { + const routes = _.flatMap(api.routes, (route) => { + if (_.has(route, 'routes')) { + return route.routes; + } + + return route; + }).filter((route) => route.info.type === 'content-api'); + + if (routes.length === 0) { + return; + } + + const apiPrefix = strapi.config.get('api.rest.prefix'); + routesMap[`api::${apiName}`] = routes.map((route) => ({ + ...route, + path: `${apiPrefix}${route.path}`, + })); + }); + + _.forEach(strapi.plugins, (plugin, pluginName) => { + const transformPrefix = transformRoutePrefixFor(pluginName); + + const routes = _.flatMap(plugin.routes, (route) => { + if (_.has(route, 'routes')) { + return route.routes.map(transformPrefix); + } + + return transformPrefix(route); + }).filter((route) => route.info.type === 'content-api'); + + if (routes.length === 0) { + return; + } + + const apiPrefix = strapi.config.get('api.rest.prefix'); + routesMap[`plugin::${pluginName}`] = routes.map((route) => ({ + ...route, + path: `${apiPrefix}${route.path}`, + })); + }); + + return routesMap; +}; + +module.exports = { + getRoutes, +}; diff --git a/packages/core/admin/server/services/index.js b/packages/core/admin/server/services/index.js index 22f4819ce8..2c0511a052 100644 --- a/packages/core/admin/server/services/index.js +++ b/packages/core/admin/server/services/index.js @@ -14,4 +14,5 @@ module.exports = { action: require('./action'), 'api-token': require('./api-token'), 'project-settings': require('./project-settings'), + 'content-api': require('./content-api'), };