",
10 | "private": true,
11 | "scripts": {
12 | "start": "node server.js",
13 | "start:dev": "nodemon server.js",
14 | "test": "lab -v -c -L",
15 | "security": "nsp check",
16 | "release": "npm run security && standard-version --tag-prefix",
17 | "release:patch": "npm run security && standard-version --tag-prefix --release-as patch",
18 | "release:minor": "npm run security && standard-version --tag-prefix --release-as minor",
19 | "release:major": "npm run security && standard-version --tag-prefix --release-as major",
20 | "coverage": "lab -v -c -r html -o ./test/artifacts/coverage.html && open ./test/artifacts/coverage.html",
21 | "coveralls": "lab -r lcov | ./node_modules/.bin/coveralls"
22 | },
23 | "eslintConfig": {
24 | "extends": "eslint-config-hapi"
25 | },
26 | "engines": {
27 | "node": ">=6.0.0"
28 | },
29 | "dependencies": {
30 | "boom": "^5.2.0",
31 | "confidence": "^3.0.2",
32 | "dotenv": "^5.0.0",
33 | "glue": "^4.2.1",
34 | "good": "^7.3.0",
35 | "good-console": "^7.1.0",
36 | "good-squeeze": "^5.0.2",
37 | "handlebars": "^4.0.10",
38 | "hapi": "^16.6.2",
39 | "inert": "^4.2.1",
40 | "require-dir": "^1.0.0",
41 | "vision": "^4.1.1",
42 | "visionary": "^6.0.2"
43 | },
44 | "devDependencies": {
45 | "code": "^4.1.0",
46 | "coveralls": "^3.0.0",
47 | "eslint": "^4.18.0",
48 | "eslint-config-hapi": "^11.1.0",
49 | "eslint-plugin-hapi": "^4.0.0",
50 | "lab": "^14.3.2",
51 | "nodemon": "^1.15.0",
52 | "nsp": "^3.2.1",
53 | "standard-version": "^4.3.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/generators/app/templates/response-files/gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/micromata/generator-http-fake-backend/daa7b3eb0a209c4ec132122a336d42060f328737/generators/app/templates/response-files/gitkeep
--------------------------------------------------------------------------------
/generators/app/templates/server.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Composer = require('./index');
4 | const Config = require('./config');
5 |
6 | Composer((err, server) => {
7 |
8 | if (err) {
9 | throw err;
10 | }
11 |
12 | server.start(() => {
13 |
14 | server.log('info', 'NODE_ENV: ' + Config.get('/env'));
15 | server.log('info', 'Server running at: ' + server.info.uri);
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/generators/app/templates/server/api/setup/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Config = require('../../../config');
4 | const UnsupportedMethods = require('./unsupportedMethods');
5 | const SupportedMethod = require('./supportedMethod');
6 |
7 | module.exports = function (settings) {
8 |
9 | const exportEndpoint = {};
10 | const path = Config.get('/apiUrlPrefix') + '/' + settings.name;
11 | const urls = settings.urls;
12 |
13 | exportEndpoint.register = function (server, options, next) {
14 |
15 | const routes = [];
16 |
17 | const createRoutes = function (url) {
18 |
19 | const params = url.params || '';
20 |
21 | url.requests.forEach((proposedRequest) => {
22 |
23 | const supportedMethod = SupportedMethod(server, proposedRequest, settings, params, path);
24 | routes.push(supportedMethod);
25 | });
26 |
27 | const unsupportedMethods = UnsupportedMethods(settings, params, path);
28 | routes.push(unsupportedMethods);
29 | };
30 |
31 | urls.forEach(createRoutes);
32 | server.route(routes);
33 | next();
34 | };
35 |
36 | exportEndpoint.register.attributes = {
37 | name: settings.name,
38 | path,
39 | urls
40 | };
41 |
42 | return exportEndpoint;
43 | };
44 |
--------------------------------------------------------------------------------
/generators/app/templates/server/api/setup/lib/getContentDisposition.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (filePath) {
4 |
5 | const fileName = /\/([^\/]+\.\S+)$/g.exec(filePath);
6 | return 'attachment; filename=' + fileName[1];
7 | };
8 |
--------------------------------------------------------------------------------
/generators/app/templates/server/api/setup/lib/getCustomResponseHeader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (env) {
4 |
5 | return {
6 | name: env.CUSTOM_HEADER_NAME || 'X-Powered-By',
7 | value: env.CUSTOM_HEADER_VALUE || 'https://hapijs.com'
8 | };
9 | };
10 |
--------------------------------------------------------------------------------
/generators/app/templates/server/api/setup/supportedMethod.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Boom = require('boom');
4 | const Fs = require('fs');
5 | const Path = require('path');
6 |
7 | const GetContentDisposition = require('./lib/getContentDisposition');
8 | const CustomResponseHeader = require('./lib/getCustomResponseHeader')(process.env);
9 |
10 | module.exports = function (server, proposedRequest, settings, params, path) {
11 |
12 | const method = proposedRequest.method || 'GET';
13 | const sendFile = proposedRequest.sendFile | false;
14 | const isFile = typeof proposedRequest.response === 'string';
15 | const mimeType = proposedRequest.mimeType || (sendFile ? 'application/octet-stream' : 'application/json');
16 |
17 | return {
18 | method,
19 | path: path + params,
20 | handler: function (request, reply) {
21 |
22 | let response;
23 |
24 | if (proposedRequest.statusCode && !proposedRequest.response) {
25 | response = Boom.create(proposedRequest.statusCode);
26 | }
27 | else if (settings.statusCode && !proposedRequest.statusCode) {
28 | response = Boom.create(settings.statusCode);
29 | }
30 | else {
31 | server.log('info', 'Received payload:' + JSON.stringify(request.payload));
32 |
33 | if (typeof proposedRequest.response === 'string') {
34 | const filePath = Path.normalize(Path.join(__dirname, '../../../', proposedRequest.response));
35 | response = Fs.readFileSync(filePath);
36 | }
37 | else {
38 | response = proposedRequest.response;
39 | }
40 |
41 | }
42 |
43 | if (response.isBoom === true) {
44 | response.output.headers[CustomResponseHeader.name] = CustomResponseHeader.value;
45 | return reply(response);
46 | }
47 |
48 | if (sendFile && isFile) {
49 | return reply(response).code(proposedRequest.statusCode || 200).type(mimeType)
50 | .header('Content-Disposition', GetContentDisposition(proposedRequest.response))
51 | .header(CustomResponseHeader.name, CustomResponseHeader.value);
52 | }
53 | return reply(response).code(proposedRequest.statusCode || 200).type(mimeType)
54 | .header(CustomResponseHeader.name, CustomResponseHeader.value);
55 | }
56 | };
57 | };
58 |
--------------------------------------------------------------------------------
/generators/app/templates/server/api/setup/unsupportedMethods.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Boom = require('boom');
4 | const CustomResponseHeader = require('./lib/getCustomResponseHeader')(process.env);
5 |
6 | module.exports = function (settings, params, path) {
7 |
8 | return {
9 | method: '*',
10 | path: path + params,
11 | handler: function (request, reply) {
12 |
13 | let response;
14 |
15 | if (settings.statusCode) {
16 | response = Boom.create(settings.statusCode);
17 | }
18 | else {
19 | response = Boom.methodNotAllowed();
20 | }
21 |
22 | response.output.headers[CustomResponseHeader.name] = CustomResponseHeader.value;
23 | return reply(response);
24 | }
25 | };
26 | };
27 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const RequireDir = require('require-dir');
4 | const apiDir = RequireDir('../api');
5 |
6 |
7 | const getEndpoints = function (request, reply) {
8 |
9 | const endpoints = [];
10 |
11 | Object.keys(apiDir).forEach((key) => {
12 |
13 | endpoints.push(apiDir[key].register.attributes);
14 | });
15 |
16 | return reply(endpoints);
17 | };
18 |
19 | exports.register = function (server, options, next) {
20 |
21 | server.route({
22 | method: 'GET',
23 | path: '/',
24 | config: {
25 | pre: [{
26 | method: getEndpoints,
27 | assign: 'getEndpoints'
28 | }],
29 | handler: function (request, reply) {
30 |
31 | return reply.view('index', {
32 | title: 'endpoints / routes',
33 | endpoints: request.pre.getEndpoints
34 | });
35 | }
36 | }
37 | });
38 |
39 | next();
40 | };
41 |
42 |
43 | exports.register.attributes = {
44 | name: 'index',
45 | dependencies: 'visionary'
46 | };
47 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/public.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.register = function (server, options, next) {
4 |
5 | server.route({
6 | method: 'GET',
7 | path: '/assets/{param*}',
8 | handler: {
9 | directory: {
10 | path: './server/web/public/assets',
11 | listing: true
12 | }
13 | }
14 | });
15 |
16 | next();
17 | };
18 |
19 |
20 | exports.register.attributes = {
21 | name: 'public'
22 | };
23 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/public/assets/css/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
3 | }
4 | h1 { font-weight: normal; }
5 |
6 | a:visited { color: inherit; }
7 |
8 | footer {
9 | border-top: 1px solid #dedede;
10 | padding-top: 1em;
11 | }
12 |
13 | .hidden {
14 | display: none;
15 | }
16 |
17 | .endpoints ul { padding-left: 0.6em; }
18 | .endpoints li { list-style-type: none; }
19 | .endpoints li:before {
20 | content: "–";
21 | margin-right: 0.5em;
22 | }
23 | .endpoints .method {
24 | display: inline-block;
25 | font-family: "Courier New", Courier, monospace;
26 | }
27 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/views/helpers/json.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Returns the given object as string representation.
5 | */
6 |
7 | module.exports = function (object) {
8 |
9 | return JSON.stringify(object);
10 | };
11 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/views/helpers/methods.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Returns the method(s) or the default method when no method is defined.
5 | */
6 |
7 | module.exports = function (requests) {
8 |
9 | const methods = [];
10 | requests.forEach((response) => {
11 |
12 | methods.push(response.method || 'GET');
13 | });
14 | return methods.join(',');
15 | };
16 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/views/helpers/removeCurlyBraces.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Returns the given params without curly braces.
5 | */
6 |
7 | module.exports = function (params) {
8 |
9 | if (typeof params === 'string') {
10 | params = params.replace(/({|})/g, '');
11 | }
12 | else {
13 | params = '';
14 | }
15 |
16 | return params;
17 | };
18 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/views/index.hbs:
--------------------------------------------------------------------------------
1 | {{> header}}
2 |
3 | Endpoints / Routes
4 |
5 | {{{json endpoints}}}
6 |
7 | {{#if endpoints}}
8 |
20 | {{else}}
21 | No endpoints configured yet …
22 | {{/if}}
23 |
24 | {{> footer}}
25 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/views/layout/layout.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | http-fake-backend{{#if title}} - {{title}}{{/if}}
7 |
8 |
9 |
10 | {{{content}}}
11 |
12 |
13 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/views/partials/footer.hbs:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/generators/app/templates/server/web/views/partials/header.hbs:
--------------------------------------------------------------------------------
1 |
2 | http-fake-backend
3 |
4 |
--------------------------------------------------------------------------------
/generators/app/templates/test/config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Lab = require('lab');
4 | const Code = require('code');
5 | const Config = require('../config');
6 |
7 |
8 | const lab = exports.lab = Lab.script();
9 |
10 |
11 | lab.experiment('Config', () => {
12 |
13 | lab.test('it gets config data', (done) => {
14 |
15 | Code.expect(Config.get('/')).to.be.an.object();
16 | done();
17 | });
18 |
19 |
20 | lab.test('it gets config meta data', (done) => {
21 |
22 | Code.expect(Config.meta('/')).to.match(/general project wide config/i);
23 | done();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/generators/app/templates/test/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Lab = require('lab');
4 | const Code = require('code');
5 | const Composer = require('../index');
6 |
7 |
8 | const lab = exports.lab = Lab.script();
9 |
10 |
11 | lab.experiment('App', () => {
12 |
13 | lab.test('it composes a server', (done) => {
14 |
15 | Composer((err, composedServer) => {
16 |
17 | Code.expect(composedServer).to.be.an.object();
18 | done(err);
19 | });
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/generators/app/templates/test/manifest.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Lab = require('lab');
4 | const Code = require('code');
5 | const Manifest = require('../manifest');
6 |
7 |
8 | const lab = exports.lab = Lab.script();
9 |
10 |
11 | lab.experiment('Manifest', () => {
12 |
13 | lab.test('it gets manifest data', (done) => {
14 |
15 | Code.expect(Manifest.get('/')).to.be.an.object();
16 | done();
17 | });
18 |
19 |
20 | lab.test('it gets manifest meta data', (done) => {
21 |
22 | Code.expect(Manifest.meta('/')).to.match(/hapi server config used by glue to compose the server/i);
23 | done();
24 | });
25 |
26 | lab.test('it gets the correct custom response header', (done) => {
27 |
28 | Code.expect(Manifest.get('/').server.connections.routes.cors.additionalExposedHeaders).to.equal(['X-Powered-By']);
29 | done();
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/generators/app/templates/test/server/api/customResponseHeader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Lab = require('lab');
4 | const Code = require('code');
5 | const Config = require('../../../config');
6 | const Hapi = require('hapi');
7 | const SetupEndpoint = require('../../../server/api/setup/');
8 | const GetCustomResponseHeader = require('../../../server/api/setup/lib/getCustomResponseHeader');
9 |
10 | const apiUrlPrefix = Config.get('/apiUrlPrefix');
11 |
12 | const Endpoint = SetupEndpoint({
13 | name: 'customResponseHeader',
14 | urls: [
15 | {
16 | params: '/regularResponse',
17 | requests: [
18 | { response: '/test/server/api/fixtures/response.json' }
19 | ]
20 | },
21 | {
22 | params: '/fileResponse',
23 | requests: [{
24 | response: '/test/server/api/fixtures/example.pdf',
25 | sendFile: true,
26 | mimeType: 'application/pdf'
27 | }]
28 | },
29 | {
30 | params: '/boomError',
31 | requests: [{ statusCode: 402 }]
32 | }
33 | ]
34 | });
35 |
36 | const lab = exports.lab = Lab.script();
37 | let request;
38 | let server;
39 |
40 | lab.beforeEach((done) => {
41 |
42 | const plugins = [Endpoint];
43 | server = new Hapi.Server();
44 | server.connection({ port: Config.get('/port/web') });
45 | server.register(plugins, (err) => {
46 |
47 | if (err) {
48 | return done(err);
49 | }
50 |
51 | done();
52 | });
53 | });
54 |
55 |
56 | lab.experiment('Custom response header', () => {
57 |
58 | lab.beforeEach((done) => {
59 |
60 |
61 | done();
62 | });
63 |
64 | lab.test('should be read from .env file', (done) => {
65 |
66 | const env = Object.assign({}, process.env);
67 |
68 | env.CUSTOM_HEADER_NAME = 'Authorization';
69 | env.CUSTOM_HEADER_VALUE = 'Bearer eyJhbGciOiJIUzUxMiJ9';
70 |
71 | Code.expect(GetCustomResponseHeader(env)).to.equal({
72 | name: 'Authorization',
73 | value: 'Bearer eyJhbGciOiJIUzUxMiJ9'
74 | });
75 |
76 | done();
77 | });
78 |
79 | lab.test('should have a fallback if not defined in .env file', (done) => {
80 |
81 |
82 | Code.expect(GetCustomResponseHeader(process.env)).to.equal({
83 | name: 'X-Powered-By',
84 | value: 'https://hapijs.com'
85 | });
86 |
87 | done();
88 | });
89 |
90 | lab.test('regular responses should have the defined response header', (done) => {
91 |
92 | request = {
93 | method: 'GET',
94 | url: apiUrlPrefix + '/customResponseHeader/regularResponse'
95 | };
96 |
97 | server.inject(request, (response) => {
98 |
99 | Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');
100 |
101 | done();
102 | });
103 | });
104 |
105 | lab.test('file responses should have the defined response header', (done) => {
106 |
107 | request = {
108 | method: 'GET',
109 | url: apiUrlPrefix + '/customResponseHeader/fileResponse'
110 | };
111 |
112 | server.inject(request, (response) => {
113 |
114 | Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');
115 |
116 | done();
117 | });
118 | });
119 |
120 | lab.test('boom errors should have the defined response header', (done) => {
121 |
122 | request = {
123 | method: 'GET',
124 | url: apiUrlPrefix + '/customResponseHeader/boomError'
125 | };
126 |
127 | server.inject(request, (response) => {
128 |
129 | Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');
130 |
131 | done();
132 | });
133 | });
134 |
135 | lab.test('unallowed methods of regular responses should have the defined response header', (done) => {
136 |
137 | request = {
138 | method: 'POST',
139 | url: apiUrlPrefix + '/customResponseHeader/regularResponse'
140 | };
141 |
142 | server.inject(request, (response) => {
143 |
144 | Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');
145 |
146 | done();
147 | });
148 | });
149 |
150 | lab.test('unallowed methods of boom errors should have the defined response header', (done) => {
151 |
152 | request = {
153 | method: 'POST',
154 | url: apiUrlPrefix + '/customResponseHeader/boomError'
155 | };
156 |
157 | server.inject(request, (response) => {
158 |
159 | Code.expect(response.headers['x-powered-by']).to.equal('https://hapijs.com');
160 |
161 | done();
162 | });
163 | });
164 |
165 | });
166 |
--------------------------------------------------------------------------------
/generators/app/templates/test/server/api/endpoint.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Lab = require('lab');
4 | const Code = require('code');
5 | const Config = require('../../../config');
6 | const Hapi = require('hapi');
7 | const SetupEndpoint = require('../../../server/api/setup/');
8 |
9 | const apiUrlPrefix = Config.get('/apiUrlPrefix');
10 |
11 | const Endpoint = SetupEndpoint({
12 | name: 'endpoint',
13 | urls: [
14 | {
15 | requests: [
16 | { response: '/test/server/api/fixtures/response.json' }
17 | ]
18 | },
19 | {
20 | params: '/object',
21 | requests: [{
22 | response: {
23 | javascript: 'object'
24 | }
25 | }]
26 | },
27 | {
28 | params: '/read',
29 | requests: [{
30 | method: 'GET',
31 | response: '/test/server/api/fixtures/response.json'
32 | }]
33 | },
34 | {
35 | params: '/update/{id}',
36 | requests: [{
37 | method: 'PUT',
38 | response: '/test/server/api/fixtures/response.json'
39 | }, {
40 | method: 'PATCH',
41 | response: {
42 | success: true
43 | }
44 | }]
45 | },
46 | {
47 | params: '/delete/{id}',
48 | requests: [{
49 | method: 'DELETE',
50 | response: '/test/server/api/fixtures/response.json'
51 | }]
52 | },
53 | {
54 | params: '/multipleMethods',
55 | requests: [{
56 | method: ['PUT', 'PATCH'],
57 | response: {
58 | success: true
59 | }
60 | }]
61 | }
62 | ]
63 | });
64 |
65 | const lab = exports.lab = Lab.script();
66 | let request;
67 | let server;
68 |
69 | lab.beforeEach((done) => {
70 |
71 | const plugins = [Endpoint];
72 | server = new Hapi.Server();
73 | server.connection({ port: Config.get('/port/web') });
74 | server.register(plugins, (err) => {
75 |
76 | if (err) {
77 | return done(err);
78 | }
79 |
80 | done();
81 | });
82 | });
83 |
84 |
85 | lab.experiment('Setup endpoints', () => {
86 |
87 | lab.beforeEach((done) => {
88 |
89 |
90 | done();
91 | });
92 |
93 |
94 | lab.test('returns 404 for unknown route', (done) => {
95 |
96 | request = {
97 | method: 'POST',
98 | url: apiUrlPrefix + '/baz'
99 | };
100 |
101 | server.inject(request, (response) => {
102 |
103 | Code.expect(response.statusCode).to.equal(404);
104 |
105 | done();
106 | });
107 | });
108 |
109 | lab.test('returns 405: Method Not Allowed for undefined methods', (done) => {
110 |
111 | request = {
112 | method: 'POST',
113 | url: apiUrlPrefix + '/endpoint/read'
114 | };
115 |
116 | server.inject(request, (response) => {
117 |
118 | Code.expect(response.statusCode).to.equal(405);
119 | Code.expect(response.result).to.equal({
120 | statusCode: 405,
121 | error: 'Method Not Allowed',
122 | message: 'Method Not Allowed'
123 | });
124 |
125 | done();
126 | });
127 | });
128 |
129 | lab.test('params and method are optional', (done) => {
130 |
131 | request = {
132 | method: 'GET',
133 | url: apiUrlPrefix + '/endpoint'
134 | };
135 |
136 | server.inject(request, (response) => {
137 |
138 | Code.expect(response.statusCode).to.equal(200);
139 | Code.expect(JSON.parse(response.result)).to.equal({ response: '🐷' });
140 |
141 | done();
142 | });
143 | });
144 |
145 | lab.test('returns correct json from JavaScript object', (done) => {
146 |
147 | request = {
148 | method: 'GET',
149 | url: apiUrlPrefix + '/endpoint/object'
150 | };
151 |
152 | server.inject(request, (response) => {
153 |
154 | Code.expect(response.statusCode).to.equal(200);
155 | Code.expect(response.result).to.equal({ javascript: 'object' });
156 |
157 | done();
158 | });
159 | });
160 |
161 | lab.test('returns correct json from JSON template', (done) => {
162 |
163 | request = {
164 | method: 'GET',
165 | url: apiUrlPrefix + '/endpoint/read'
166 | };
167 |
168 | server.inject(request, (response) => {
169 |
170 | Code.expect(response.statusCode).to.equal(200);
171 | Code.expect(JSON.parse(response.result)).to.equal({ response: '🐷' });
172 |
173 | done();
174 | });
175 | });
176 |
177 | lab.test('PUT returns correct json', (done) => {
178 |
179 | request = {
180 | method: 'PUT',
181 | url: apiUrlPrefix + '/endpoint/update/foo'
182 | };
183 |
184 | server.inject(request, (response) => {
185 |
186 | Code.expect(response.statusCode).to.equal(200);
187 | Code.expect(JSON.parse(response.result)).to.equal({ response: '🐷' });
188 |
189 | done();
190 | });
191 | });
192 |
193 | lab.test('PATCH on same route returns different json', (done) => {
194 |
195 | request = {
196 | method: 'PATCH',
197 | url: apiUrlPrefix + '/endpoint/update/foo'
198 | };
199 |
200 | server.inject(request, (response) => {
201 |
202 | Code.expect(response.statusCode).to.equal(200);
203 | Code.expect(response.result).to.equal({ success: true });
204 |
205 | done();
206 | });
207 | });
208 |
209 | lab.test('DELETE returns correct json', (done) => {
210 |
211 | request = {
212 | method: 'DELETE',
213 | url: apiUrlPrefix + '/endpoint/delete/foo'
214 | };
215 |
216 | server.inject(request, (response) => {
217 |
218 | Code.expect(response.statusCode).to.equal(200);
219 | Code.expect(JSON.parse(response.result)).to.equal({ response: '🐷' });
220 |
221 | done();
222 | });
223 | });
224 |
225 | lab.test('correct json for multiple Methods', (done) => {
226 |
227 | const putRequest = {
228 | method: 'PUT',
229 | url: apiUrlPrefix + '/endpoint/multipleMethods'
230 | };
231 |
232 | const patchRequest = {
233 | method: 'PATCH',
234 | url: apiUrlPrefix + '/endpoint/multipleMethods'
235 | };
236 |
237 | const postRequest = {
238 | method: 'POST',
239 | url: apiUrlPrefix + '/endpoint/multipleMethods'
240 | };
241 |
242 | server.inject(putRequest, (response) => {
243 |
244 | Code.expect(response.statusCode).to.equal(200);
245 | Code.expect(response.result).to.equal({ success: true });
246 | });
247 |
248 | server.inject(patchRequest, (response) => {
249 |
250 | Code.expect(response.statusCode).to.equal(200);
251 | Code.expect(response.result).to.equal({ success: true });
252 | });
253 |
254 | server.inject(postRequest, (response) => {
255 |
256 | Code.expect(response.statusCode).to.equal(405);
257 | Code.expect(response.result).to.equal({
258 | statusCode: 405,
259 | error: 'Method Not Allowed',
260 | message: 'Method Not Allowed'
261 | });
262 |
263 | done();
264 | });
265 |
266 |
267 | });
268 |
269 | });
270 |
--------------------------------------------------------------------------------
/generators/app/templates/test/server/api/fakeStatusCode.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Lab = require('lab');
4 | const Code = require('code');
5 | const Config = require('../../../config');
6 | const Hapi = require('hapi');
7 | const SetupEndpoint = require('../../../server/api/setup/');
8 |
9 | const apiUrlPrefix = Config.get('/apiUrlPrefix');
10 |
11 | const EndpointLevel = SetupEndpoint({
12 | name: 'endpoint',
13 | urls: [{
14 | requests: [
15 | { response: '/test/server/api/fixtures/response.json' }
16 | ]
17 | }],
18 | statusCode: 401
19 | });
20 |
21 | const RequestLevel = SetupEndpoint({
22 | name: 'request',
23 | urls: [
24 | {
25 | params: '/boomError',
26 | requests: [{ statusCode: 402 }]
27 | },
28 | {
29 | params: '/customError',
30 | requests: [
31 | {
32 | response: { error: true },
33 | statusCode: 406
34 | }
35 | ]
36 | }
37 | ]
38 | });
39 |
40 | const RequestLevelBeatsEndpointLevel = SetupEndpoint({
41 | name: 'requestBeatsEndpoint',
42 | urls: [
43 | {
44 | params: '/boomError',
45 | requests: [{ statusCode: 402 }]
46 | },
47 | {
48 | params: '/customError',
49 | requests: [
50 | {
51 | response: { error: true },
52 | statusCode: 406
53 | }
54 | ]
55 | }
56 | ],
57 | statusCode: 401
58 | });
59 |
60 | const lab = exports.lab = Lab.script();
61 | let request;
62 | let server;
63 |
64 | lab.beforeEach((done) => {
65 |
66 | const plugins = [
67 | EndpointLevel,
68 | RequestLevel,
69 | RequestLevelBeatsEndpointLevel
70 | ];
71 | server = new Hapi.Server();
72 | server.connection({ port: Config.get('/port/web') });
73 | server.register(plugins, (err) => {
74 |
75 | if (err) {
76 | return done(err);
77 | }
78 |
79 | done();
80 | });
81 | });
82 |
83 |
84 | lab.experiment('Fake status codes', () => {
85 |
86 | lab.experiment('on endpoint level', () => {
87 |
88 | lab.beforeEach((done) => {
89 |
90 | done();
91 | });
92 |
93 | lab.test('returns correct error provided by boom', (done) => {
94 |
95 | request = {
96 | method: 'GET',
97 | url: apiUrlPrefix + '/endpoint'
98 | };
99 |
100 | server.inject(request, (response) => {
101 |
102 | Code.expect(response.statusCode).to.equal(401);
103 |
104 | done();
105 | });
106 | });
107 |
108 | lab.test('undefined method returns correct error provided by boom', (done) => {
109 |
110 | request = {
111 | method: 'PUT',
112 | url: apiUrlPrefix + '/endpoint'
113 | };
114 |
115 | server.inject(request, (response) => {
116 |
117 | Code.expect(response.statusCode).to.equal(401);
118 |
119 | done();
120 | });
121 | });
122 | });
123 |
124 | lab.experiment('on request level', () => {
125 |
126 | lab.test('returns correct error provided by boom', (done) => {
127 |
128 | request = {
129 | method: 'GET',
130 | url: apiUrlPrefix + '/request/boomError'
131 | };
132 |
133 | server.inject(request, (response) => {
134 |
135 | Code.expect(response.statusCode).to.equal(402);
136 |
137 | done();
138 | });
139 | });
140 |
141 | lab.test('returns correct faked status code with regular response', (done) => {
142 |
143 | request = {
144 | method: 'GET',
145 | url: apiUrlPrefix + '/request/customError'
146 | };
147 |
148 | server.inject(request, (response) => {
149 |
150 | Code.expect(response.statusCode).to.equal(406);
151 | Code.expect(response.result).to.equal({ error: true });
152 |
153 | done();
154 | });
155 | });
156 | });
157 |
158 | lab.experiment('request level beats endpoint level', () => {
159 |
160 | lab.test('returns correct error provided by boom', (done) => {
161 |
162 | request = {
163 | method: 'GET',
164 | url: apiUrlPrefix + '/requestBeatsEndpoint/boomError'
165 | };
166 |
167 | server.inject(request, (response) => {
168 |
169 | Code.expect(response.statusCode).to.equal(402);
170 |
171 | done();
172 | });
173 | });
174 |
175 | lab.test('returns correct faked status code with regular response', (done) => {
176 |
177 | request = {
178 | method: 'GET',
179 | url: apiUrlPrefix + '/requestBeatsEndpoint/customError'
180 | };
181 |
182 | server.inject(request, (response) => {
183 |
184 | Code.expect(response.statusCode).to.equal(406);
185 | Code.expect(response.result).to.equal({ error: true });
186 |
187 | done();
188 | });
189 | });
190 | });
191 | });
192 |
--------------------------------------------------------------------------------
/generators/app/templates/test/server/api/fileTypes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Lab = require('lab');
4 | const Code = require('code');
5 | const Config = require('../../../config');
6 | const Hapi = require('hapi');
7 | const Fs = require('fs');
8 | const Path = require('path');
9 | const SetupEndpoint = require('../../../server/api/setup/');
10 |
11 | const apiUrlPrefix = Config.get('/apiUrlPrefix');
12 |
13 | const Endpoint = SetupEndpoint({
14 | name: 'fileTypes',
15 | urls: [{
16 | params: '/json',
17 | requests: [{
18 | response: '/test/server/api/fixtures/response.json'
19 | }]
20 | }, {
21 | params: '/json/download',
22 | requests: [{
23 | response: '/test/server/api/fixtures/response.json',
24 | sendFile: true
25 | }]
26 | }, {
27 | params: '/text',
28 | requests: [{
29 | response: '/test/server/api/fixtures/response.txt',
30 | mimeType: 'text/plain'
31 | }]
32 | }, {
33 | params: '/html',
34 | requests: [{
35 | response: '/test/server/api/fixtures/response.html',
36 | statusCode: 201,
37 | mimeType: 'text/html'
38 | }]
39 | }, {
40 | params: '/pdf',
41 | requests: [{
42 | response: '/response-files/example.pdf',
43 | sendFile: true
44 | }]
45 | }, {
46 | params: '/pdf/tweaked',
47 | requests: [{
48 | response: '/response-files/example.pdf',
49 | sendFile: true,
50 | statusCode: 201,
51 | mimeType: 'application/pdf'
52 | }]
53 | }]
54 | });
55 |
56 | const lab = exports.lab = Lab.script();
57 | let request;
58 | let server;
59 |
60 | lab.beforeEach((done) => {
61 |
62 | const plugins = [Endpoint];
63 | server = new Hapi.Server();
64 | server.connection({ port: Config.get('/port/web') });
65 | server.register(plugins, (err) => {
66 |
67 | if (err) {
68 | return done(err);
69 | }
70 |
71 | done();
72 | });
73 | });
74 |
75 |
76 | lab.experiment('Different file types', () => {
77 |
78 | lab.beforeEach((done) => {
79 |
80 |
81 | done();
82 | });
83 |
84 |
85 | lab.experiment('send file contents ', () => {
86 |
87 | lab.test('content-type header defaults to `application/json`', (done) => {
88 |
89 | request = {
90 | method: 'GET',
91 | url: apiUrlPrefix + '/fileTypes/json'
92 | };
93 |
94 | server.inject(request, (response) => {
95 |
96 | Code.expect(response.headers['content-type']).to.equal('application/json; charset=utf-8');
97 | Code.expect(JSON.parse(response.result)).to.equal({ response: '🐷' });
98 |
99 | done();
100 | });
101 | });
102 |
103 | lab.test('return text files with the defined content-type header`', (done) => {
104 |
105 | request = {
106 | method: 'GET',
107 | url: apiUrlPrefix + '/fileTypes/text'
108 | };
109 |
110 | server.inject(request, (response) => {
111 |
112 | Code.expect(response.headers['content-type']).to.equal('text/plain; charset=utf-8');
113 | Code.expect(response.result).to.equal('This is just a plain old text file ✅\n');
114 |
115 | done();
116 | });
117 | });
118 |
119 | lab.test('return with the defined content-type header and custom status code`', (done) => {
120 |
121 | request = {
122 | method: 'GET',
123 | url: apiUrlPrefix + '/fileTypes/html'
124 | };
125 |
126 | server.inject(request, (response) => {
127 |
128 | Code.expect(response.headers['content-type']).to.equal('text/html; charset=utf-8');
129 | Code.expect(response.result).to.equal('GitHub 💖\n');
130 | Code.expect(response.statusCode).to.equal(201);
131 |
132 | done();
133 | });
134 | });
135 |
136 | });
137 |
138 |
139 |
140 | lab.experiment('send files ', () => {
141 |
142 | lab.test('ascii files have correctly encoded content', (done) => {
143 |
144 | request = {
145 | method: 'GET',
146 | url: apiUrlPrefix + '/fileTypes/json/download'
147 | };
148 |
149 | server.inject(request, (response) => {
150 |
151 | Code.expect(JSON.parse(response.result)).to.equal({ response: '🐷' });
152 |
153 | done();
154 | });
155 | });
156 |
157 | lab.test('binary files have correctly encoded content', (done) => {
158 |
159 | request = {
160 | method: 'GET',
161 | url: apiUrlPrefix + '/fileTypes/pdf'
162 | };
163 |
164 | const fixtureContent = Fs.readFileSync(Path.normalize(Path.join(__dirname, '/fixtures/example.pdf'))).toString();
165 |
166 | server.inject(request, (response) => {
167 |
168 | Code.expect(response.result).to.equal(fixtureContent);
169 |
170 | done();
171 | });
172 | });
173 |
174 | lab.test('send files with the default content-type and the correct name`', (done) => {
175 |
176 | request = {
177 | method: 'GET',
178 | url: apiUrlPrefix + '/fileTypes/pdf'
179 | };
180 |
181 | server.inject(request, (response) => {
182 |
183 | Code.expect(response.headers['content-type']).to.equal('application/octet-stream');
184 | Code.expect(response.headers['content-disposition']).to.equal('attachment; filename=example.pdf');
185 | Code.expect(response.statusCode).to.equal(200);
186 |
187 | done();
188 | });
189 | });
190 |
191 | lab.test('send files with a defined content-type and a custom status code`', (done) => {
192 |
193 | request = {
194 | method: 'GET',
195 | url: apiUrlPrefix + '/fileTypes/pdf/tweaked'
196 | };
197 |
198 | server.inject(request, (response) => {
199 |
200 | Code.expect(response.headers['content-type']).to.equal('application/pdf');
201 | Code.expect(response.headers['content-disposition']).to.equal('attachment; filename=example.pdf');
202 | Code.expect(response.statusCode).to.equal(201);
203 |
204 | done();
205 | });
206 | });
207 |
208 | });
209 |
210 |
211 | });
212 |
--------------------------------------------------------------------------------
/generators/app/templates/test/server/api/fixtures/example.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/micromata/generator-http-fake-backend/daa7b3eb0a209c4ec132122a336d42060f328737/generators/app/templates/test/server/api/fixtures/example.pdf
--------------------------------------------------------------------------------
/generators/app/templates/test/server/api/fixtures/response.html:
--------------------------------------------------------------------------------
1 | GitHub 💖
2 |
--------------------------------------------------------------------------------
/generators/app/templates/test/server/api/fixtures/response.json:
--------------------------------------------------------------------------------
1 | {
2 | "response": "🐷"
3 | }
4 |
--------------------------------------------------------------------------------
/generators/app/templates/test/server/api/fixtures/response.txt:
--------------------------------------------------------------------------------
1 | This is just a plain old text file ✅
2 |
--------------------------------------------------------------------------------
/generators/app/templates/test/server/web/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Lab = require('lab');
4 | const Code = require('code');
5 | const Config = require('../../../config');
6 | const Hapi = require('hapi');
7 | const Vision = require('vision');
8 | const Inert = require('inert');
9 | const HomePlugin = require('../../../server/web/index');
10 |
11 |
12 | const lab = exports.lab = Lab.script();
13 | let request;
14 | let server;
15 |
16 |
17 | lab.beforeEach((done) => {
18 |
19 | const plugins = [Vision, Inert, HomePlugin];
20 | server = new Hapi.Server();
21 | server.connection({ port: Config.get('/port/web') });
22 | server.register(plugins, (err) => {
23 |
24 | if (err) {
25 | return done(err);
26 | }
27 |
28 | server.views({
29 | engines: { hbs: require('handlebars') },
30 | layout: true,
31 | path: './server/web/views',
32 | partialsPath: './server/web/views/partials',
33 | layoutPath: './server/web/views/layout',
34 | helpersPath: './server/web/views/helpers',
35 | isCached: false
36 | });
37 |
38 | done();
39 | });
40 | });
41 |
42 |
43 | lab.experiment('Home Page View', () => {
44 |
45 | lab.beforeEach((done) => {
46 |
47 | request = {
48 | method: 'GET',
49 | url: '/'
50 | };
51 |
52 | done();
53 | });
54 |
55 |
56 | lab.test('home page renders properly', (done) => {
57 |
58 | server.inject(request, (response) => {
59 |
60 | Code.expect(response.result).to.match(/http-fake-backend - endpoints \/ routes<\/title>/i);
61 | Code.expect(response.statusCode).to.equal(200);
62 |
63 | done();
64 | });
65 | });
66 |
67 | lab.test('endpoints are delivered to the view', (done) => {
68 |
69 | server.inject(request, (response) => {
70 |
71 | const endpointsInView = response.result.match(/(.+)<\/code>/)[1];
72 | const endpointsInController = JSON.stringify(response.request.preResponses.getEndpoints.source);
73 |
74 | Code.expect(endpointsInController).to.equal(endpointsInView);
75 |
76 | done();
77 | });
78 | });
79 | });
80 |
--------------------------------------------------------------------------------
/generators/endpoint/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const Generator = require('yeoman-generator');
3 | const chalk = require('chalk');
4 | const yosay = require('yosay');
5 | const superb = require('superb');
6 | const titleCase = require('title-case');
7 | const helper = require('./promptingHelpers');
8 |
9 | module.exports = class extends Generator {
10 | prompting() {
11 | const done = this.async();
12 |
13 | // Have Yeoman greet the user.
14 | this.log(yosay(`${titleCase(superb())}, let’s create an endpoint …`));
15 |
16 | this.endpoint = {
17 | name: null,
18 | urls: []
19 | };
20 |
21 | const prompts = [
22 | {
23 | type: 'input',
24 | name: 'endpointName',
25 | message: 'What should be the name of the endpoint?',
26 | when: () => {
27 | return !this.endpoint.urls.length;
28 | },
29 | validate: helper.validateEndpoint
30 | },
31 | {
32 | type: 'input',
33 | name: 'params',
34 | message: 'Please enter URL path params (optional)',
35 | validate: helper.validateParams
36 | }, {
37 | type: 'list',
38 | name: 'method',
39 | message: 'What should be the accepted method for this request?',
40 | choices: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']
41 | }, {
42 | type: 'list',
43 | name: 'responseType',
44 | message: 'What would you like to return?',
45 | choices: [
46 | 'The content of a file',
47 | 'A JavaScript object literal as JSON',
48 | 'A file via Content-Disposition: attachment',
49 | 'An error object'
50 | ],
51 | filter: helper.filterResponseType
52 | }, {
53 | type: 'list',
54 | name: 'contentType',
55 | message: 'Which content type should it have?',
56 | choices: [
57 | 'application/json',
58 | 'text/plain',
59 | 'text/html'
60 | ],
61 | filter: helper.filterContentType,
62 | when(answers) {
63 | return answers.responseType === 'fileContent';
64 | }
65 | }, {
66 | type: 'input',
67 | name: 'response',
68 | message: 'Please enter the name of the JSON file',
69 | default: 'your-filename.json',
70 | when(answers) {
71 | return answers.contentType === 'json';
72 | },
73 | validate: helper.validateJson
74 | }, {
75 | type: 'input',
76 | name: 'response',
77 | message: 'Please enter the name of the text file',
78 | default: 'your-filename.txt',
79 | when(answers) {
80 | return answers.contentType === 'txt';
81 | },
82 | validate: helper.validateText
83 | }, {
84 | type: 'input',
85 | name: 'response',
86 | message: 'Please enter the name of the HTML file',
87 | default: 'your-filename.html',
88 | when(answers) {
89 | return answers.contentType === 'html';
90 | },
91 | validate: helper.validateHtml
92 | }, {
93 | type: 'input',
94 | name: 'response',
95 | message: 'Please enter a JavaScript object literal or array',
96 | default: '{ status: \'ok\' }',
97 | when(answers) {
98 | return answers.responseType === 'objectLiteral';
99 | },
100 | validate: helper.validateJsObject
101 | }, {
102 | type: 'input',
103 | name: 'response',
104 | message: 'Please enter the name of the file',
105 | when(answers) {
106 | return answers.responseType === 'fileAttachment';
107 | },
108 | validate: helper.validateFile
109 | }, {
110 | type: 'input',
111 | name: 'statusCode',
112 | message: 'Please enter a valid HTTP error status code',
113 | default: '400',
114 | when(answers) {
115 | return answers.responseType === 'error';
116 | },
117 | validate: helper.validateErrorStatusCode
118 | }, {
119 | type: 'input',
120 | name: 'statusCode',
121 | message: 'Please enter a valid HTTP status code',
122 | default: '200',
123 | when(answers) {
124 | return answers.responseType !== 'error';
125 | },
126 | validate: helper.validateStatusCode
127 | }, {
128 | type: 'confirm',
129 | name: 'anotherUrl',
130 | message: 'Should this endpoint have additional path params (just hit enter for YES)?',
131 | default: true
132 | }
133 | ];
134 |
135 | prompting(this);
136 |
137 | function prompting(that) {
138 | that.prompt(prompts).then(props => {
139 | that.props = props;
140 |
141 | if (!that.endpoint.name) {
142 | that.endpoint.name = that.props.endpointName;
143 | }
144 |
145 | that.endpoint.urls.push({
146 | params: that.props.params,
147 | requests: [{
148 | method: that.props.method,
149 | responseType: that.props.responseType,
150 | contentType: that.props.contentType,
151 | response: that.props.response,
152 | statusCode: that.props.statusCode
153 | }]
154 | });
155 |
156 | if (props.anotherUrl) {
157 | prompting(that);
158 | } else {
159 | done();
160 | }
161 | });
162 | }
163 | }
164 |
165 | writing() {
166 | this.fs.copyTpl(
167 | this.templatePath('_endpoint.js'),
168 | this.destinationPath('server/api/' + this.endpoint.name + '.js'), {
169 | endpoint: this.endpoint
170 | }
171 | );
172 |
173 | this.endpoint.urls.forEach(url => {
174 | if (url.requests[0].responseType === 'fileContent') {
175 | this.fs.copy(
176 | this.templatePath(`response.${url.requests[0].contentType}`),
177 | this.destinationPath('response-files/' + url.requests[0].response)
178 | );
179 | }
180 | });
181 | }
182 |
183 | end() {
184 | this.log(yosay(`
185 | That’s it. Feel free to fire up the server with ${chalk.green('npm run start:dev')}
186 | `));
187 | }
188 | };
189 |
--------------------------------------------------------------------------------
/generators/endpoint/promptingHelpers.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const helper = {};
3 |
4 | helper.filterResponseType = function (value) {
5 | let responseType;
6 | switch (value) {
7 | case 'The content of a file':
8 | responseType = 'fileContent';
9 | break;
10 | case 'A file via Content-Disposition: attachment':
11 | responseType = 'fileAttachment';
12 | break;
13 | case 'A JavaScript object literal as JSON':
14 | responseType = 'objectLiteral';
15 | break;
16 | case 'An error object':
17 | responseType = 'error';
18 | break;
19 | // No Default
20 | }
21 | return responseType;
22 | };
23 |
24 | helper.filterContentType = function (value) {
25 | let contentType;
26 | switch (value) {
27 | case 'application/json':
28 | contentType = 'json';
29 | break;
30 | case 'text/plain':
31 | contentType = 'txt';
32 | break;
33 | case 'text/html':
34 | contentType = 'html';
35 | break;
36 | // No Default
37 | }
38 | return contentType;
39 | };
40 |
41 | helper.validateJsObject = function (value) {
42 | let returnvalue = chalk.red('Your input doesn’t look like an object or array at all.');
43 | const isArray = value.match(/^\[/) && value.match(/]$/);
44 | const isObject = value.match(/^{/) && value.match(/\}$/);
45 | if (isArray || isObject) {
46 | returnvalue = true;
47 | }
48 | return returnvalue;
49 | };
50 |
51 | helper.validateJson = function (value) {
52 | let returnvalue = chalk.red('Please enter valid filename (*.json)');
53 | const fileExt = value.match(/\w\.json$/);
54 | const validChars = value.match(/[^a-zA-Z0-9(),!.~$&'\-_*+;=:@]+/g);
55 | if (fileExt && !validChars) {
56 | returnvalue = true;
57 | }
58 | return returnvalue;
59 | };
60 |
61 | helper.validateText = function (value) {
62 | let returnvalue = chalk.red('Please enter valid filename (*.txt)');
63 | const fileExt = value.match(/\w\.txt$/);
64 | const validChars = value.match(/[^a-zA-Z0-9(),!.~$&'\-_*+;=:@]+/g);
65 | if (fileExt && !validChars) {
66 | returnvalue = true;
67 | }
68 | return returnvalue;
69 | };
70 |
71 | helper.validateHtml = function (value) {
72 | let returnvalue = chalk.red('Please enter valid filename (*.html)');
73 | const fileExt = value.match(/\w\.html$/);
74 | const validChars = value.match(/[^a-zA-Z0-9(),!.~$&'\-_*+;=:@]+/g);
75 | if (fileExt && !validChars) {
76 | returnvalue = true;
77 | }
78 | return returnvalue;
79 | };
80 |
81 | helper.validateFile = function (value) {
82 | let returnvalue = chalk.red('Please enter valid filename');
83 | const fileExt = value.match(/\w\.\w{2,4}$/);
84 | const validChars = value.match(/[^a-zA-Z0-9(),!.~$&'\-_*+;=:@]+/g);
85 | if (fileExt && !validChars) {
86 | returnvalue = true;
87 | }
88 | return returnvalue;
89 | };
90 |
91 | helper.validateEndpoint = function (value) {
92 | let returnvalue = chalk.red('Please enter a valid name. This will be a part of the url.');
93 | const validChars = value.match(/[^a-zA-Z0-9(),!.~$&'\-_*+;=:@]+/g);
94 | if (!validChars && value) {
95 | returnvalue = true;
96 | }
97 | return returnvalue;
98 | };
99 |
100 | helper.validateParams = function (value) {
101 | let returnvalue = chalk.red('Please enter valid path parameters with a leading `/`. See http://hapijs.com/api#path-parameters');
102 | const validChars = value.match(/[^a-zA-Z0-9()/,!.~$&'\-_*+;=:@{}]+/g);
103 | const leadingSlash = value.match(/^\//);
104 | if ((!validChars && leadingSlash) || value === '') {
105 | returnvalue = true;
106 | }
107 | return returnvalue;
108 | };
109 |
110 | helper.validateErrorStatusCode = function (value) {
111 | let returnvalue = chalk.red('Please enter valid 4xx or 5xx status code supported by https://github.com/hapijs/boom');
112 | const validStatusCodes = [
113 | 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 410, 411, 412, 413, 414, 415, 416, 417, 422, 423, 428, 429, 451, 500, 501, 502, 503, 504
114 | ];
115 |
116 | if (validStatusCodes.indexOf(Number(value)) !== -1) {
117 | returnvalue = true;
118 | }
119 | return returnvalue;
120 | };
121 |
122 | helper.validateStatusCode = function (value) {
123 | let returnvalue = chalk.red('Please enter a number which reprents a valid HTTP status code');
124 | const validStatusCode = value.match(/^[1-5][0-9][0-9]/);
125 |
126 | if (validStatusCode && value.length === 3) {
127 | returnvalue = true;
128 | }
129 | return returnvalue;
130 | };
131 |
132 | module.exports = helper;
133 |
--------------------------------------------------------------------------------
/generators/endpoint/templates/_endpoint.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const SetupEndpoint = require('./setup/');
4 |
5 | module.exports = SetupEndpoint({
6 | name: '<%= endpoint.name %>',
7 | urls: [<% endpoint.urls.forEach(function(url, index){ %>
8 | {<% if (url.params){ %>
9 | params: '<%= url.params %>',<% } %>
10 | requests: [{
11 | method: '<%= url.requests[0].method %>',<% if (url.requests[0].responseType === 'fileContent'){ %>
12 | response: '/response-files/<%= url.requests[0].response %>'<% if (url.requests[0].contentType === 'txt'){ %>,
13 | mimeType: 'text/plain'<% } else if (url.requests[0].contentType === 'html'){ %>,
14 | mimeType: 'text/html'<% } %><% } else if (url.requests[0].responseType === 'objectLiteral'){ %>
15 | response: <%- url.requests[0].response %><% } else if (url.requests[0].responseType === 'fileAttachment'){ %>
16 | response: '/response-files/<%= url.requests[0].response %>',
17 | sendFile: true<% } %><% if (url.requests[0].statusCode !== '200' && url.requests[0].responseType !== 'error'){ %>,<% } %><% if (url.requests[0].statusCode !== '200'){ %>
18 | statusCode: <%- url.requests[0].statusCode %><% } %>
19 | }]
20 | }<% if (index + 1 !== endpoint.urls.length) { %>,<% } %><% }) %>
21 | ]
22 | });
23 |
--------------------------------------------------------------------------------
/generators/endpoint/templates/response.html:
--------------------------------------------------------------------------------
1 | GitHub
2 |
--------------------------------------------------------------------------------
/generators/endpoint/templates/response.json:
--------------------------------------------------------------------------------
1 | { "success": true }
2 |
--------------------------------------------------------------------------------
/generators/endpoint/templates/response.txt:
--------------------------------------------------------------------------------
1 | Success
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "generator-http-fake-backend",
3 | "version": "4.1.0",
4 | "description": "Build a fake backend by providing the content of JSON files or JavaScript objects through configurable routes.",
5 | "homepage": "https://github.com/micromata/generator-http-fake-backend",
6 | "author": {
7 | "name": "Michael Kühnel",
8 | "email": "m.kuehnel@micromata.de",
9 | "url": "http://micromata.de"
10 | },
11 | "engines": {
12 | "node": ">=6.0.0"
13 | },
14 | "files": [
15 | "generators"
16 | ],
17 | "main": "generators/index.js",
18 | "scripts": {
19 | "test": "jest",
20 | "test:watch": "jest --watch",
21 | "security": "nsp check",
22 | "prepublishOnly": "npm run security",
23 | "lint": "eslint . --fix",
24 | "pretest": "npm run lint",
25 | "coveralls": "cat ./coverage/lcov.info | coveralls",
26 | "release": "npm run security && standard-version --tag-prefix",
27 | "release:patch": "npm run security && standard-version --tag-prefix --release-as patch",
28 | "release:minor": "npm run security && standard-version --tag-prefix --release-as minor",
29 | "release:major": "npm run security && standard-version --tag-prefix --release-as major"
30 | },
31 | "keywords": [
32 | "fake",
33 | "api",
34 | "http",
35 | "backend",
36 | "yeoman-generator",
37 | "micromata",
38 | "server",
39 | "rest",
40 | "restful",
41 | "data",
42 | "mocks",
43 | "mocking",
44 | "mock"
45 | ],
46 | "dependencies": {
47 | "chalk": "2.3.1",
48 | "command-exists": "^1.2.2",
49 | "nsp": "^3.2.1",
50 | "superb": "2.0.0",
51 | "title-case": "^2.1.1",
52 | "yeoman-generator": "^2.0.2",
53 | "yosay": "^2.0.1"
54 | },
55 | "devDependencies": {
56 | "codeclimate-test-reporter": "^0.5.0",
57 | "coveralls": "^3.0.0",
58 | "eslint": "^4.18.0",
59 | "eslint-config-xo-space": "^0.18.0",
60 | "jest": "^22.3.0",
61 | "jest-cli": "^22.3.0",
62 | "standard-version": "^4.3.0",
63 | "yeoman-assert": "^3.1.0",
64 | "yeoman-test": "1.7.0"
65 | },
66 | "eslintConfig": {
67 | "extends": "xo-space/esnext",
68 | "env": {
69 | "jest": true
70 | }
71 | },
72 | "jest": {
73 | "testEnvironment": "node",
74 | "testPathIgnorePatterns": [
75 | "/generators/app/templates"
76 | ],
77 | "collectCoverage": true,
78 | "coverageDirectory": "coverage",
79 | "collectCoverageFrom": [
80 | "generators/app/**/*.js",
81 | "!generators/app/templates/**/*.js"
82 | ],
83 | "coverageReporters": [
84 | "lcov",
85 | "html",
86 | "text",
87 | "text-summary"
88 | ]
89 | },
90 | "repository": "micromata/generator-http-fake-backend",
91 | "license": "MIT"
92 | }
93 |
--------------------------------------------------------------------------------