Skip to content

Commit

Permalink
[minor] support custom HTTP status code (#605)
Browse files Browse the repository at this point in the history
* Added 404 and 410 handler

* Added 404 logic to koa

* Added more redirect status codes

* Added more custom html display status codes

* Added status codes to all 3 server implementations

* Added express tests

* fix http status code dependency

* Updated tests for full coverage
  • Loading branch information
codingcircus authored and jchip committed Oct 9, 2017
1 parent 9dd2394 commit 85c00d8
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 33 deletions.
10 changes: 6 additions & 4 deletions packages/electrode-react-webapp/lib/express/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
const _ = require("lodash");
const assert = require("assert");
const ReactWebapp = require("../react-webapp");

const HTTP_REDIRECT = 302;
const HttpStatus = require("../http-status");

const handleRoute = (request, response, handler) => {
return handler({ mode: request.query.__mode || "", request })
.then(data => {
const status = data.status;

if (status === undefined) {
response.send(data);
} else if (status === HTTP_REDIRECT) {
response.redirect(data.path);
} else if (HttpStatus.redirect[status]) {
response.redirect(status, data.path);
} else if (HttpStatus.displayHtml[status]) {
response.status(status).send(data.html !== undefined ? data.html : data);
} else if (status >= 200 && status < 300) {
response.send(data.html !== undefined ? data.html : data);
} else {
Expand Down
3 changes: 2 additions & 1 deletion packages/electrode-react-webapp/lib/group-scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ module.exports = function groupScripts(data) {
update(!!x.src);

return acc;
}, { src: false, scripts: [] });
},
{ src: false, scripts: [] });

joinScripts(output);

Expand Down
8 changes: 5 additions & 3 deletions packages/electrode-react-webapp/lib/hapi/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
const _ = require("lodash");
const assert = require("assert");
const ReactWebapp = require("../react-webapp");

const HTTP_REDIRECT = 302;
const HttpStatus = require("../http-status");

const handleRoute = (request, reply, handler) => {
return handler({ mode: request.query.__mode || "", request })
.then(data => {
const status = data.status;

if (status === undefined) {
reply(data);
} else if (status === HTTP_REDIRECT) {
} else if (HttpStatus.redirect[status]) {
reply.redirect(data.path);
} else if (HttpStatus.displayHtml[status]) {
reply(data.html !== undefined ? data.html : data).code(status);
} else if (status >= 200 && status < 300) {
reply(data.html !== undefined ? data.html : data);
} else {
Expand Down
20 changes: 20 additions & 0 deletions packages/electrode-react-webapp/lib/http-status.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use strict";

const HttpStatusCodes = require("http-status-codes");

module.exports = {
// Status codes where we might want to keep custom html
displayHtml: {
[HttpStatusCodes.NOT_FOUND]: true,
[HttpStatusCodes.GONE]: true,
[HttpStatusCodes.SERVICE_UNAVAILABLE]: true
},

// Status codes where we want to redirect the user
redirect: {
[HttpStatusCodes.MOVED_PERMANENTLY]: true,
[HttpStatusCodes.MOVED_TEMPORARILY]: true,
[HttpStatusCodes.PERMANENT_REDIRECT]: true,
[HttpStatusCodes.TEMPORARY_REDIRECT]: true
}
};
8 changes: 5 additions & 3 deletions packages/electrode-react-webapp/lib/koa/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
const _ = require("lodash");
const assert = require("assert");
const ReactWebapp = require("../react-webapp");

const HTTP_REDIRECT = 302;
const HttpStatus = require("../http-status");

function handleRoute(handler) {
const request = this.request;
Expand All @@ -19,10 +18,13 @@ function handleRoute(handler) {
return handler({ mode: request.query.__mode || "", request })
.then(data => {
const status = data.status;

if (status === undefined) {
respond(200, data);
} else if (status === HTTP_REDIRECT) {
} else if (HttpStatus.redirect[status]) {
this.redirect(data.path);
} else if (HttpStatus.displayHtml[status]) {
respond(status, data.html !== undefined ? data.html : data);
} else if (status >= 200 && status < 300) {
respond(status, data.html !== undefined ? data.html : data);
} else {
Expand Down
15 changes: 14 additions & 1 deletion packages/electrode-react-webapp/lib/render-output.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const assert = require("assert");
const Promise = require("bluebird");
const HttpStatusCodes = require("http-status-codes");

class Output {
constructor() {
Expand Down Expand Up @@ -137,9 +138,21 @@ class RenderOutput {
return promise;
}

_getResolveResult() {
const { content } = this._context;
if (content && content.status !== HttpStatusCodes.OK) {
return {
status: this._context.content.status,
html: this._result
};
}

return this._result;
}

_finish() {
if (this._resolve) {
this._resolve(this._result);
this._resolve(this._getResolveResult());
}
this._resolve = this._reject = undefined;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/electrode-react-webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Hapi plugin that provides a default React web app template",
"scripts": {
"lint": "clap lint",
"test": "npm run lint && clap test",
"test": "npm run lint && clap check",
"prepublish": "if in-publish; then npm test; fi",
"format": "prettier --write --print-width 100 *.{js,jsx} `find . -type d -d 1 -exec echo '{}/**/*.{js,jsx}' \\; | egrep -v '(/node_modules/|/dist/|/coverage/)'`"
},
Expand Down Expand Up @@ -38,6 +38,7 @@
"license": "Apache-2.0",
"dependencies": {
"bluebird": "^2 || ^3",
"http-status-codes": "^1.3.0",
"in-publish": "^2.0.0",
"lodash": "^4.0.0",
"require-at": "^1.0.0"
Expand Down
85 changes: 75 additions & 10 deletions packages/electrode-react-webapp/test/spec/express.index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ describe("express electrode-react-webapp", function() {
if (req.query.render !== undefined) {
render = Boolean(+req.query.render);
}

return {
status: +req.query.status,
html,
Expand Down Expand Up @@ -139,6 +140,65 @@ describe("express electrode-react-webapp", function() {
});
});

it("should return 404 and html, if custom html is provided", () => {
const server = startServer(webappOptions());
return new Promise(resolve => {
const port = server.address().port;
return request(
`http://localhost:${port}/status?status=404&html=NotFoundHTML&render=0`
).end((err, resp) => {
expect(err).to.be.ok;
expect(resp.status).to.equal(404);
expect(resp.text).to.equal("NotFoundHTML");
server.close(() => resolve());
});
});
});

it("should return 410 and html, if custom html is provided", () => {
const server = startServer(webappOptions());
return new Promise(resolve => {
const port = server.address().port;
return request(
`http://localhost:${port}/status?status=410&html=GoneHTML&render=0`
).end((err, resp) => {
expect(err).to.be.ok;
expect(resp.status).to.equal(410);
expect(resp.text).to.equal("GoneHTML");
server.close(() => resolve());
});
});
});

it("should not fail on 404 if no html is provided", () => {
const server = startServer(webappOptions());
return new Promise(resolve => {
const port = server.address().port;
return request(
`http://localhost:${port}/status?status=404&data=test&render=0`
).end((err, resp) => {
expect(err).to.be.ok;
expect(resp.status).to.equal(404);
server.close(() => resolve());
});
});
});

it("should return 503 and html, if custom html is provided", () => {
const server = startServer(webappOptions());
return new Promise(resolve => {
const port = server.address().port;
return request(
`http://localhost:${port}/status?status=503&html=ServerErrorHTML&render=0`
).end((err, resp) => {
expect(err).to.be.ok;
expect(resp.status).to.equal(503);
expect(resp.text).to.equal("ServerErrorHTML");
server.close(() => resolve());
});
});
});

it("should return 200 and html with render false", () => {
const server = startServer(webappOptions());
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -171,10 +231,12 @@ describe("express electrode-react-webapp", function() {
const server = startServer(webappOptions());
return new Promise(resolve => {
const port = server.address().port;
return request(`http://localhost:${port}/redirect`).redirects(0).end((err, resp) => {
expect(resp.text).includes("/redirect2");
return server.close(() => resolve());
});
return request(`http://localhost:${port}/redirect`)
.redirects(0)
.end((err, resp) => {
expect(resp.text).includes("/redirect2");
return server.close(() => resolve());
});
});
});

Expand Down Expand Up @@ -235,12 +297,15 @@ describe("express electrode-react-webapp", function() {
const server = startServer(webappOptions());
return new Promise((resolve, reject) => {
const port = server.address().port;
return request.post(`http://localhost:${port}/all`).send({}).end((err, resp) => {
if (err) return reject(err);
expect(resp.text).includes("Test All");
expect(resp.text).includes("console.log('Hello all');");
return server.close(() => resolve());
});
return request
.post(`http://localhost:${port}/all`)
.send({})
.end((err, resp) => {
if (err) return reject(err);
expect(resp.text).includes("Test All");
expect(resp.text).includes("console.log('Hello all');");
return server.close(() => resolve());
});
});
});

Expand Down
51 changes: 51 additions & 0 deletions packages/electrode-react-webapp/test/spec/hapi.index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,57 @@ describe("hapi electrode-react-webapp", () => {
});
});

it("should return 404 and html, if custom html is provided", () => {
assign(paths, {
content: {
status: 404,
html: "html content"
}
});

return electrodeServer(config).then(server => {
return server
.inject({
method: "GET",
url: "/?__mode=noss"
})
.then(res => {
expect(res.statusCode).to.equal(404);
expect(res.result).to.contain("<div class=\"js-content\">html content</div>");
stopServer(server);
})
.catch(err => {
stopServer(server);
throw err;
});
});
});

it("should not fail on not handled status codes", () => {
assign(paths, {
content: {
status: 501,
message: "not implemented"
}
});

return electrodeServer(config).then(server => {
return server
.inject({
method: "GET",
url: "/?__mode=noss"
})
.then(res => {
expect(res.statusCode).to.equal(501);
stopServer(server);
})
.catch(err => {
stopServer(server);
throw err;
});
});
});

it("should handle option serverSideRendering false", () => {
configOptions.serverSideRendering = false;
return electrodeServer(config).then(server => {
Expand Down
50 changes: 40 additions & 10 deletions packages/electrode-react-webapp/test/spec/koa.index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,31 @@ describe("koa electrode-react-webapp", function() {
});
});

it("should return 404 and html, if custom html is provided", () => {
const server = startServer(webappOptions());
return new Promise(resolve => {
const port = server.address().port;
return request(`http://localhost:${port}/status?status=404&html=NotFoundHTML&render=0`).end((err, resp) => {
expect(err).to.be.ok;
expect(resp.status).to.equal(404);
expect(resp.text).to.equal("NotFoundHTML");
server.close(() => resolve());
});
});
});

it("should not fail on 404 if no html is provided", () => {
const server = startServer(webappOptions());
return new Promise(resolve => {
const port = server.address().port;
return request(`http://localhost:${port}/status?status=404&data=test&render=0`).end((err, resp) => {
expect(err).to.be.ok;
expect(resp.status).to.equal(404);
server.close(() => resolve());
});
});
});

it("should return 200 and html with render false", () => {
const server = startServer(webappOptions());
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -172,10 +197,12 @@ describe("koa electrode-react-webapp", function() {
const server = startServer(webappOptions());
return new Promise(resolve => {
const port = server.address().port;
return request(`http://localhost:${port}/redirect`).redirects(0).end((err, resp) => {
expect(resp.text).includes("/redirect2");
return server.close(() => resolve());
});
return request(`http://localhost:${port}/redirect`)
.redirects(0)
.end((err, resp) => {
expect(resp.text).includes("/redirect2");
return server.close(() => resolve());
});
});
});

Expand Down Expand Up @@ -236,12 +263,15 @@ describe("koa electrode-react-webapp", function() {
const server = startServer(webappOptions());
return new Promise((resolve, reject) => {
const port = server.address().port;
return request.post(`http://localhost:${port}/all`).send({}).end((err, resp) => {
if (err) return reject(err);
expect(resp.text).includes("Test All");
expect(resp.text).includes("console.log('Hello all');");
return server.close(() => resolve());
});
return request
.post(`http://localhost:${port}/all`)
.send({})
.end((err, resp) => {
if (err) return reject(err);
expect(resp.text).includes("Test All");
expect(resp.text).includes("console.log('Hello all');");
return server.close(() => resolve());
});
});
});

Expand Down

0 comments on commit 85c00d8

Please sign in to comment.