diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml index 73555fe7ac..b827cb127c 100644 --- a/public/openapi/write.yaml +++ b/public/openapi/write.yaml @@ -23,11 +23,25 @@ info: servers: - url: /api/v3 tags: + - name: utilities + description: Utility calls to test Write API functionality - name: users - description: 'Account related calls (create, modify, delete, etc.)' + description: Account related calls (create, modify, delete, etc.) + - name: groups + description: Calls related to user groups - name: categories description: Administrative calls to manage categories + - name: topics + description: Topic-based calls (create, modify, delete, etc.) + - name: posts + description: Individual post-related calls (create, modify, delete, etc.) + - name: admin + description: Administrative calls + - name: files + description: File upload routes paths: + /ping: + $ref: 'write/ping.yaml' /users/: $ref: 'write/users.yaml' /users/{uid}: diff --git a/src/routes/write/index.js b/src/routes/write/index.js index 539668d508..6cf266acdb 100644 --- a/src/routes/write/index.js +++ b/src/routes/write/index.js @@ -48,6 +48,7 @@ Write.reload = async (params) => { router.post('/api/v3/ping', middleware.authenticate, function (req, res) { helpers.formatApiResponse(200, res, { uid: req.user.uid, + received: req.body, }); }); diff --git a/test/api.js b/test/api.js index 9a1f6292f5..fefcdb92e6 100644 --- a/test/api.js +++ b/test/api.js @@ -172,31 +172,46 @@ describe('API', async () => { it('should grab all mounted routes and ensure a schema exists', async () => { const webserver = require('../src/webserver'); const buildPaths = function (stack, prefix) { - const paths = stack.reduce((memo, cur) => { - if (cur.route && cur.route.path && typeof cur.route.path === 'string' && cur.route.path.startsWith('/api/')) { - memo.push({ - method: Object.keys(cur.route.methods)[0], - path: (prefix || '') + cur.route.path, - }); - } else if (cur.name === 'router') { - const prefix = cur.regexp.toString().replace('/^', '').replace('\\/?(?=\\/|$)/i', '').replace(/\\\//g, '/'); - memo = memo.concat(buildPaths(cur.handle.stack, prefix)); + const paths = stack.map((dispatch) => { + if (dispatch.route && dispatch.route.path && typeof dispatch.route.path === 'string') { + if (!prefix && !dispatch.route.path.startsWith('/api/')) { + return null; + } + return { + method: Object.keys(dispatch.route.methods)[0], + path: (prefix || '') + dispatch.route.path, + }; + } else if (dispatch.name === 'router') { + const prefix = dispatch.regexp.toString().replace('/^', '').replace('\\/?(?=\\/|$)/i', '').replace(/\\\//g, '/'); + return buildPaths(dispatch.handle.stack, prefix); } - return memo; - }, []); - return paths; + // Drop any that aren't actual routes (middlewares, error handlers, etc.) + return null; + }); + + return paths.flat(); }; - const paths = buildPaths(webserver.app._router.stack).map(function normalize(pathObj) { + + let paths = buildPaths(webserver.app._router.stack).filter(Boolean).map(function normalize(pathObj) { pathObj.path = pathObj.path.replace(/\/:([^\\/]+)/g, '/{$1}'); return pathObj; }); + const exclusionPrefixes = ['/api/admin/plugins']; + paths = paths.filter(function filterExclusions(path) { + return !exclusionPrefixes.some(prefix => path.path.startsWith(prefix)); + }); + // For each express path, query for existence in read and write api schemas paths.forEach((pathObj) => { describe(`${pathObj.method.toUpperCase()} ${pathObj.path}`, () => { it('should be defined in schema docs', () => { - const schema = pathObj.path.startsWith('/api/v3') ? writeApi : readApi; + let schema = readApi; + if (pathObj.path.startsWith('/api/v3')) { + schema = writeApi; + pathObj.path = pathObj.path.replace('/api/v3', ''); + } const normalizedPath = pathObj.path.replace(/\/:([^\\/]+)/g, '/{$1}').replace(/\?/g, ''); assert(schema.paths.hasOwnProperty(normalizedPath)); });