Resolve plugin from package or path like plugins and allow same resolve at route level

This commit is contained in:
Alexandre Bodin 2021-09-29 14:23:45 +02:00
parent 010294813d
commit cd2cdaae76
8 changed files with 131 additions and 68 deletions

View File

@ -23,5 +23,8 @@ module.exports = [
foo: 'bar',
},
},
'api::address.address-middleware',
{
resolve: './src/custom/middleware.js',
config: {},
},
];

View File

@ -1,3 +1,6 @@
module.exports = options => {
return (ctx, next) => next();
return (ctx, next) => {
ctx.set('X-Strapi-Test', 'Address Middleware');
return next();
};
};

View File

@ -7,6 +7,7 @@ module.exports = {
path: '/addresses',
handler: 'address.find',
config: {
middlewares: ['api::address.address-middleware'],
policies: ['address'],
},
},

View File

@ -0,0 +1,5 @@
'use strict';
module.exports = () => {
return (ctx, next) => next();
};

View File

@ -3,7 +3,7 @@
const { toLower, castArray, trim, prop } = require('lodash/fp');
const compose = require('koa-compose');
const { resolveMiddlewares } = require('./middleware');
const { resolveRouteMiddlewares } = require('./middleware');
const { resolvePolicies } = require('./policy');
const getMethod = route => trim(toLower(route.method));
@ -58,7 +58,7 @@ module.exports = strapi => {
const method = getMethod(route);
const path = getPath(route);
const middlewares = resolveMiddlewares(route);
const middlewares = resolveRouteMiddlewares(route, strapi);
const policies = resolvePolicies(route);
const action = getAction(route, strapi);

View File

@ -8,7 +8,7 @@ const { createRouteManager } = require('./routing');
const { createAdminAPI } = require('./admin-api');
const { createContentAPI } = require('./content-api');
const registerAllRoutes = require('./register-routes');
const registerMiddlewares = require('./register-middlewares');
const registerApplicationMiddlewares = require('./register-middlewares');
const healthCheck = async ctx => {
ctx.set('strapi', 'You are so French!');
@ -98,7 +98,7 @@ const createServer = strapi => {
},
async initMiddlewares() {
await registerMiddlewares(strapi);
await registerApplicationMiddlewares(strapi);
return this;
},

View File

@ -1,9 +1,115 @@
'use strict';
const { propOr } = require('lodash/fp');
const path = require('path');
const { propOr, isArray } = require('lodash/fp');
const resolveMiddlewares = propOr([], 'config.middlewares');
const getMiddlewareConfig = propOr([], 'config.middlewares');
const resolveRouteMiddlewares = (route, strapi) => {
const middlewaresConfig = getMiddlewareConfig(route);
if (!isArray(middlewaresConfig)) {
throw new Error('Route middlewares config must be an array');
}
const middlewares = resolveMiddlewares(middlewaresConfig, strapi);
return middlewares.map(({ handler }) => handler);
};
/**
* Initialize every configured middlewares
* @param {MiddlewaresConfig} config
* @param {Strapi} strapi
* @returns {Middlewares}
*/
const resolveMiddlewares = (config, strapi) => {
const middlewares = [];
for (const item of config) {
if (typeof item === 'function') {
middlewares.push({
name: null,
handler: item,
});
continue;
}
if (typeof item === 'string') {
const middlewareFactory = strapi.middleware(item);
if (!middlewareFactory) {
throw new Error(`Middleware ${item} not found.`);
}
middlewares.push({
name: item,
handler: middlewareFactory(null, { strapi }),
});
continue;
}
if (typeof item === 'object' && item !== null) {
const { name, resolve, config = {} } = item;
if (name) {
const middlewareFactory = strapi.middleware(name);
middlewares.push({
name,
handler: middlewareFactory(config, { strapi }),
});
continue;
}
if (resolve) {
middlewares.push({
name: resolve,
handler: resolveCustomMiddleware(resolve, strapi)(config, { strapi }),
});
continue;
}
throw new Error('Invalid middleware configuration. Missing name or resolve properties.');
}
throw new Error(
'Middleware config must either be a string or an object {name?: string, resolve?: string, config: any}.'
);
}
return middlewares;
};
/**
* Resolve middleware from package name or path
* @param {string} resolve
* @param {Strapi} strapi
*/
const resolveCustomMiddleware = (resolve, strapi) => {
let modulePath;
try {
modulePath = require.resolve(resolve);
} catch (error) {
if (error.code === 'MODULE_NOT_FOUND') {
modulePath = path.resolve(strapi.dirs.root, resolve);
} else {
throw error;
}
}
try {
return require(modulePath);
} catch (err) {
throw new Error(`Could not load middleware "${modulePath}".`);
}
};
module.exports = {
resolveRouteMiddlewares,
resolveMiddlewares,
};

View File

@ -1,6 +1,7 @@
'use strict';
const { yup } = require('@strapi/utils');
const { resolveMiddlewares } = require('./middleware');
/**
* @typedef {import('../../').Strapi} Strapi
@ -53,12 +54,12 @@ const middlewareConfigSchema = yup.array().of(
* Register middlewares in router
* @param {Strapi} strapi
*/
module.exports = async strapi => {
const registerApplicationMiddlewares = async strapi => {
const middlewareConfig = strapi.config.get('middlewares', defaultConfig);
await validateMiddlewareConfig();
await validateMiddlewareConfig(middlewareConfig);
const middlewares = await initMiddlewares(middlewareConfig, strapi);
const middlewares = await resolveMiddlewares(middlewareConfig, strapi);
checkRequiredMiddlewares(middlewares);
@ -101,60 +102,4 @@ const checkRequiredMiddlewares = middlewares => {
return;
};
/**
* Initialize every configured middlewares
* @param {MiddlewaresConfig} config
* @param {Strapi} strapi
* @returns {Middlewares}
*/
const initMiddlewares = async (config, strapi) => {
const middlewares = [];
for (const item of config) {
if (typeof item === 'string') {
const middlewareFactory = strapi.middleware(item);
if (!middlewareFactory) {
throw new Error(`Middleware ${item} not found.`);
}
middlewares.push({
name: item,
handler: await middlewareFactory(null, { strapi }),
});
continue;
}
if (typeof item === 'object' && item !== null) {
const { name, resolve, config = {} } = item;
if (name) {
const middlewareFactory = strapi.middleware(name);
middlewares.push({
name,
handler: await middlewareFactory(config, { strapi }),
});
continue;
}
if (resolve) {
middlewares.push({
name: resolve,
handler: await require(resolve)(config, { strapi }),
});
continue;
}
throw new Error('Invalid middleware configuration. Missing name or resolve properties.');
}
throw new Error(
'Middleware config must either be a string or an object {name?: string, resolve?: string, config: any}.'
);
}
return middlewares;
};
module.exports = registerApplicationMiddlewares;