UNPKG

stubby

Version:

a lightweight server for stubbing external systems and endpoints

216 lines (164 loc) 5.39 kB
'use strict'; const contract = require('../models/contract'); const Portal = require('./portal').Portal; const ns = require('node-static'); const path = require('path'); const status = new ns.Server(path.resolve(__dirname, '../../webroot')); function Admin (endpoints) { Portal.call(this); this.server = this.server.bind(this); this.endpoints = endpoints; this.contract = contract; this.name = '[admin]'; } Admin.prototype = Object.create(Portal.prototype); Admin.prototype.constructor = Admin; Admin.prototype.urlPattern = /^\/([1-9][0-9]*)?$/; Admin.prototype.goPong = function (response) { this.writeHead(response, 200, { 'Content-Type': 'text/plain' }); response.end('pong'); }; Admin.prototype.goPUT = function (request, response) { const id = this.getId(request.url); let data = ''; const self = this; if (!id) { return this.notSupported(response); } request.on('data', function (chunk) { data += chunk; }); request.on('end', function () { self.processPUT(id, data, response); }); }; Admin.prototype.goPOST = function (request, response) { const id = this.getId(request.url); let data = ''; const self = this; if (id) { return this.notSupported(response); } request.on('data', function (chunk) { data += chunk; }); request.on('end', function () { self.processPOST(data, response, request); }); }; Admin.prototype.goDELETE = function (request, response) { const id = this.getId(request.url); const self = this; function callback (err) { if (err) { self.notFound(response); } else { self.noContent(response); } } if (id) { this.endpoints.delete(id, callback); } else if (request.url === '/') { this.endpoints.deleteAll(callback); } else { this.notSupported(response); } }; Admin.prototype.goGET = function (request, response) { let callback; const id = this.getId(request.url); const self = this; if (id) { callback = function (err, endpoint) { if (err) { self.notFound(response); } else { self.ok(response, endpoint); } }; return this.endpoints.retrieve(id, callback); } callback = function (_, data) { if (data.length === 0) { self.noContent(response); } else { self.ok(response, data); } }; return this.endpoints.gather(callback); }; Admin.prototype.processPUT = function (id, data, response) { const self = this; try { data = JSON.parse(data); } catch (e) { return this.badRequest(response); } const errors = this.contract(data); if (errors) { return this.badRequest(response, errors); } function callback (err) { if (err) { self.notFound(response); } else { self.noContent(response); } } this.endpoints.update(id, data, callback); }; Admin.prototype.processPOST = function (data, response, request) { const self = this; try { data = JSON.parse(data); } catch (e) { return this.badRequest(response); } const errors = this.contract(data); if (errors) { return this.badRequest(response, errors); } function callback (_, endpoint) { self.created(response, request, endpoint.id); } this.endpoints.create(data, callback); }; Admin.prototype.ok = function (response, result) { this.writeHead(response, 200, { 'Content-Type': 'application/json' }); if (result != null) { return response.end(JSON.stringify(result)); } return response.end(); }; Admin.prototype.created = function (response, request, id) { this.writeHead(response, 201, { Location: request.headers.host + '/' + id }); response.end(); }; Admin.prototype.noContent = function (response) { response.statusCode = 204; response.end(); }; Admin.prototype.badRequest = function (response, errors) { this.writeHead(response, 400, { 'Content-Type': 'application/json' }); response.end(JSON.stringify(errors)); }; Admin.prototype.notSupported = function (response) { response.statusCode = 405; response.end(); }; Admin.prototype.notFound = function (response) { this.writeHead(response, 404, { 'Content-Type': 'text/plain' }); response.end(); }; Admin.prototype.saveError = function (response) { this.writeHead(response, 422, { 'Content-Type': 'text/plain' }); response.end(); }; Admin.prototype.serverError = function (response) { this.writeHead(response, 500, { 'Content-Type': 'text/plain' }); response.end(); }; Admin.prototype.urlValid = function (url) { return url.match(this.urlPattern) != null; }; Admin.prototype.getId = function (url) { return url.replace(this.urlPattern, '$1'); }; Admin.prototype.server = function (request, response) { const self = this; this.received(request, response); response.on('finish', function () { self.responded(response.statusCode, request.url); }); if (request.url === '/ping') { return this.goPong(response); } if (/^\/(status|js|css)(\/.*)?$/.test(request.url)) { return status.serve(request, response); } if (this.urlValid(request.url)) { switch (request.method.toUpperCase()) { case 'PUT': return this.goPUT(request, response); case 'POST': return this.goPOST(request, response); case 'DELETE': return this.goDELETE(request, response); case 'GET': return this.goGET(request, response); default: return this.notSupported(response); } } else { return this.notFound(response); } }; module.exports.Admin = Admin;