diff --git a/README.md b/README.md index 7e1bd30..19302b7 100644 --- a/README.md +++ b/README.md @@ -486,10 +486,16 @@ The `sendStatus` method sets the status code and returns its string representati ```javascript res.sendStatus(200); // equivalent to res.status(200).send('OK') -res.sendStatus(304); // equivalent to res.status(304).send('Not Modified') res.sendStatus(403); // equivalent to res.status(403).send('Forbidden') ``` +Status codes that [must not carry content](https://datatracker.ietf.org/doc/html/rfc9110#name-overview-of-status-codes) per RFC 9110 — `1xx`, `204`, `205`, and `304` — are sent with an empty body instead: + +```javascript +res.sendStatus(204); // equivalent to res.status(204).send('') +res.sendStatus(304); // equivalent to res.status(304).send('') +``` + **NOTE:** If an unsupported status code is provided, it will return 'Unknown' as the body. ### header(key, value [,append]) diff --git a/__tests__/responses.unit.js b/__tests__/responses.unit.js index b535b6b..6469d4d 100644 --- a/__tests__/responses.unit.js +++ b/__tests__/responses.unit.js @@ -73,6 +73,10 @@ api.get('/testSendStatus', function(req,res) { res.sendStatus(200) }) +api.get('/testSendStatus204', function(req,res) { + res.sendStatus(204) +}) + api.get('/testSendStatus403', function(req,res) { res.sendStatus(403) }) @@ -180,6 +184,12 @@ describe('Response Tests:', function() { expect(result).toEqual({ multiValueHeaders: { 'content-type': ['application/json'] }, statusCode: 200, body: 'OK', isBase64Encoded: false }) }) // end it + it('sendStatus 204', async function() { + let _event = Object.assign({},event,{ path: '/testSendStatus204'}) + let result = await new Promise(r => api.run(_event,{},(e,res) => { r(res) })) + expect(result).toEqual({ multiValueHeaders: { 'content-type': ['application/json'] }, statusCode: 204, body: '', isBase64Encoded: false }) + }) // end it + it('sendStatus 403', async function() { let _event = Object.assign({},event,{ path: '/testSendStatus403'}) let result = await new Promise(r => api.run(_event,{},(e,res) => { r(res) })) diff --git a/__tests__/utils.unit.js b/__tests__/utils.unit.js index 888d4ab..b6998ee 100644 --- a/__tests__/utils.unit.js +++ b/__tests__/utils.unit.js @@ -232,6 +232,28 @@ describe("Utility Function Tests:", function () { }); // end it }); // end encodeBody tests + describe("statusBodyLookup:", function () { + test.each([ + [100, ""], + [101, ""], + [200, "OK"], + ["200", "OK"], + [204, ""], + ["204", ""], + [205, ""], + ["205", ""], + [304, ""], + ["304", ""], + [404, "Not Found"], + [502, "Bad Gateway"], + [999, "Unknown"], + ["not a number", "Unknown"] + ])("%s", (status, expected) => { + expect(utils.statusBodyLookup(status)).toBe(expected); + }); // end it + }); // end statusBodyLookup tests + + describe("extractRoutes:", function () { it("Sample routes", function () { // Create an api instance diff --git a/src/lib/response.js b/src/lib/response.js index fe1e26b..b59ce38 100644 --- a/src/lib/response.js +++ b/src/lib/response.js @@ -415,7 +415,7 @@ class RESPONSE { // Convenience method for sending status codes sendStatus(status) { - this.status(status).send(UTILS.statusLookup(status)); + this.status(status).send(UTILS.statusBodyLookup(status)); } // Convenience method for setting CORS headers diff --git a/src/lib/utils.js b/src/lib/utils.js index 23a0e68..22a02dc 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -114,6 +114,18 @@ export const statusLookup = (status) => { return status in statusCodes ? statusCodes[status] : 'Unknown'; }; +export const statusBodyLookup = (status) => { + const code = typeof status === 'string' ? Number(status) : status; + + // The following status codes must not have a response body + // according to rfc 9110 + if ((100 <= code && code < 200) || [204, 205, 304].includes(code)) { + return ''; + } + + return statusLookup(code); +}; + // Parses routes into readable array const extractRoutes = (routes, table = []) => { // Loop through all routes