From 8b95e14a3bf0ab060aaefa9dd8e961e71495994d Mon Sep 17 00:00:00 2001 From: Manu Artero Anguita Date: Thu, 18 Mar 2021 16:03:45 +0100 Subject: [PATCH] feat(api): list available paths at /api/v1/admin --- src/log.js | 4 +- src/server-info.js | 5 + src/server/restify-server.js | 255 ++++++++++++++++++++++------------- 3 files changed, 168 insertions(+), 96 deletions(-) create mode 100644 src/server-info.js diff --git a/src/log.js b/src/log.js index 921432e..5a371d1 100644 --- a/src/log.js +++ b/src/log.js @@ -1,8 +1,8 @@ const Logger = require('bunyan') -const { name, version } = require('../package.json') +const { serverInfo } = require('./server-info') const log = new Logger({ - name: `${name}@${version}`, + name: serverInfo(), // @ts-ignore level: process.env.LOG_LEVEL || 'info' }) diff --git a/src/server-info.js b/src/server-info.js new file mode 100644 index 0000000..267cc5b --- /dev/null +++ b/src/server-info.js @@ -0,0 +1,5 @@ +const { name, version } = require('../package.json') + +module.exports = { + serverInfo: () => `${name}@${version}` +} diff --git a/src/server/restify-server.js b/src/server/restify-server.js index 4883c76..0c79b67 100644 --- a/src/server/restify-server.js +++ b/src/server/restify-server.js @@ -1,6 +1,7 @@ const restify = require('restify') const { BadRequestError } = require('restify-errors') const { log } = require('../log') +const { serverInfo } = require('../server-info') /** * @param {import('restify').Request} req @@ -51,120 +52,186 @@ const createRestifyServer = ({ req.log.info('[<< RESPONSE]', res.toString()) }) - server.get('/', (_, res, next) => { - res.send(log.fields.name) + server.get({ name: 'server info', path: '/' }, (_, res, next) => { + res.send(serverInfo()) next() }) /** Resolves 202: Accepted */ - server.post('/api/v1/messages', async (req, res, next) => { - await processMessage(req, res) - /* do not - * `res.send(202)` - * -> headers already sent to the client - * -> [ERR_HTTP_HEADERS_SENT] err - */ - next() - }) - - server.post('/api/v1/notify', async (req, res, next) => { - const user = req.body ? req.body.user : undefined - const message = req.body ? req.body.message : undefined - if (!user || !message) { - const err = new BadRequestError("required: 'user', 'message'") - return next(err) - } - try { - const conversationKey = await notify(user, message, { - includeMention: includeMention(req) - }) - res.send(202, { conversationKey }) + server.post( + { + name: 'botframework entrypoint', + path: '/api/v1/messages' + }, + async (req, res, next) => { + await processMessage(req, res) + /* do not + * `res.send(202)` + * -> headers already sent to the client + * -> [ERR_HTTP_HEADERS_SENT] err + */ next() - } catch (err) { - next(err) } - }) + ) - server.post('/api/v1/broadcast', async (req, res, next) => { - const topic = req.body ? req.body.topic : undefined - const message = req.body ? req.body.message : undefined - if (!topic || !message) { - const err = new BadRequestError("required: 'topic', 'message'") - return next(err) - } - try { - const conversationKeys = await broadcast(topic, message, { - ensureTopic: ensureTopic(req) - }) - res.send(202, { conversationKeys }) - next() - } catch (err) { - next(err) + server.post( + { + name: 'notify', + path: '/api/v1/notify' + }, + async (req, res, next) => { + const user = req.body ? req.body.user : undefined + const message = req.body ? req.body.message : undefined + if (!user || !message) { + const err = new BadRequestError("required: 'user', 'message'") + return next(err) + } + try { + const conversationKey = await notify(user, message, { + includeMention: includeMention(req) + }) + res.send(202, { conversationKey }) + next() + } catch (err) { + next(err) + } } - }) + ) - server.get('/api/v1/admin', (_, res, next) => { - const { routes } = server.getDebugInfo() - res.send(200, routes) - }) + server.post( + { + name: 'broadcast', + path: '/api/v1/broadcast' + }, + async (req, res, next) => { + const topic = req.body ? req.body.topic : undefined + const message = req.body ? req.body.message : undefined + if (!topic || !message) { + const err = new BadRequestError("required: 'topic', 'message'") + return next(err) + } + try { + const conversationKeys = await broadcast(topic, message, { + ensureTopic: ensureTopic(req) + }) + res.send(202, { conversationKeys }) + next() + } catch (err) { + next(err) + } + } + ) - server.get('/api/v1/admin/users', async (_, res, next) => { - const users = await getUsers() - res.send(200, users) - next() - }) + server.get( + { + name: 'admin root', + path: '/api/v1/admin' + }, + (_, res, next) => { + const { routes } = server.getDebugInfo() + // @ts-ignore + const response = routes.map(({ name, method, path }) => ({ + name, + method, + path + })) + res.send(200, response) + } + ) - server.get('/api/v1/admin/topics', async (_, res, next) => { - const topics = await getTopics() - res.send(200, topics) - next() - }) + server.get( + { + name: 'admin: user index', + path: '/api/v1/admin/users' + }, + async (_, res, next) => { + const users = await getUsers() + res.send(200, users) + next() + } + ) - server.post('/api/v1/admin/topics', async (req, res, next) => { - const topic = req.body ? req.body.name : undefined - if (!topic) { - const err = new BadRequestError("required: 'name'") - return next(err) + server.get( + { + name: 'admin: topic index', + path: '/api/v1/admin/topics' + }, + async (_, res, next) => { + const topics = await getTopics() + res.send(200, topics) + next() } - const topics = await createTopic(topic) - res.send(200, topics) - next() - }) + ) - server.del('/api/v1/topics/:topic', async (req, res, next) => { - const topic = req.body ? req.body.name : undefined - try { - const topics = await removeTopic(topic) + server.post( + { + name: 'admin: topic creation', + path: '/api/v1/admin/topics' + }, + async (req, res, next) => { + const topic = req.body ? req.body.name : undefined + if (!topic) { + const err = new BadRequestError("required: 'name'") + return next(err) + } + const topics = await createTopic(topic) res.send(200, topics) next() - } catch (err) { - next(err) } - }) + ) - server.put('/api/v1/topics/:topic/subscribers', async (req, res, next) => { - const user = req.body ? req.body.user : undefined - if (!user) { - const err = new BadRequestError("required: 'user'") - return next(err) + server.del( + { + name: 'admin: topic delete', + path: '/api/v1/admin/topics/:topic' + }, + async (req, res, next) => { + const topic = req.body ? req.body.name : undefined + try { + const topics = await removeTopic(topic) + res.send(200, topics) + next() + } catch (err) { + next(err) + } } - const topic = req.params.topic - const subscribers = await forceSubscription(user, topic) - res.send(200, { subscribers }) - next() - }) + ) + + server.put( + { + name: 'admin: subscribe to topic', + path: '/api/v1/admin/topics/:topic/subscribers' + }, + async (req, res, next) => { + const user = req.body ? req.body.user : undefined + if (!user) { + const err = new BadRequestError("required: 'user'") + return next(err) + } + const topic = req.params.topic + const subscribers = await forceSubscription(user, topic) + res.send(200, { subscribers }) + next() + } + ) - // server.del('/api/v1/topics/:topic', async (req, res, next) => { - // const user = req.body ? req.body.user : undefined - // if (!user) { - // const err = new BadRequestError("required: 'user'") - // return next(err) - // } - // const topic = req.params.topic - // const subscribers = await cancelSubscription(user, topic) - // res.send(200, { subscribers }) - // next() - // }) + server.del( + { + name: 'admin: unsubscribe from topic', + path: '/api/v1/admin/topics/:topic/subscribers' + }, + async (req, res, next) => { + const user = req.body ? req.body.user : undefined + if (!user) { + const err = new BadRequestError("required: 'user'") + return next(err) + } + const topic = req.params.topic + const subscribers = await cancelSubscription(user, topic) + res.send(200, { subscribers }) + next() + } + ) return { /**