From 2d89e44f4c3ffe79c41e191436dc5235885d0f03 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 16:36:26 -0500 Subject: [PATCH 01/14] This just makes me happy --- app.js | 19 +++---------------- error-messenger.js | 26 ++++++++++++++++++++++++++ routes/create.js | 12 ++++++++++-- routes/delete.js | 21 ++++++++++++++++++--- routes/overwrite.js | 29 +++++++++++++++++------------ routes/query.js | 12 ++++++++++-- routes/update.js | 12 ++++++++++-- 7 files changed, 94 insertions(+), 37 deletions(-) create mode 100644 error-messenger.js diff --git a/app.js b/app.js index 75e67b4..685e356 100644 --- a/app.js +++ b/app.js @@ -1,5 +1,4 @@ #!/usr/bin/env node -import createError from "http-errors" import express from "express" import path from "path" import { fileURLToPath } from "url" @@ -12,6 +11,7 @@ import createRouter from "./routes/create.js" import updateRouter from "./routes/update.js" import deleteRouter from "./routes/delete.js" import overwriteRouter from "./routes/overwrite.js" +import { messenger } from './error-messenger.js' import cors from "cors" let app = express() @@ -68,20 +68,7 @@ app.use('/app/update', updateRouter) app.use('/app/delete', deleteRouter) app.use('/app/overwrite', overwriteRouter) -// catch 404 and forward to error handler -app.use(function(req, res, next) { - next(createError(404)) -}) - -// error handler -app.use(function(err, req, res, next) { - // set locals, only providing error in development - res.locals.message = err.message - res.locals.error = req.app.get('env') === 'development' ? err : {} - - // render the error page - res.status(err.status || 500) - res.send(err.message) -}) +// RERUM error response handler, and app 404s +app.use(messenger) export default app diff --git a/error-messenger.js b/error-messenger.js new file mode 100644 index 0000000..1878c32 --- /dev/null +++ b/error-messenger.js @@ -0,0 +1,26 @@ +/** + * Errors from RERUM are a response code with a text body (except those handled specifically upstream) + * We want to send the same error and message through. It is assumed to be RESTful and useful. + * This will also handle app level 404 errors. + * + * @param rerum_error_res An Express Response object from a request to RERUM that encountered an error. Explanatory text is in .text(). + */ +export async function messenger(rerum_error_res, req, res, next) { + if (res.headersSent) { + return + } + let error = {} + let rerum_err_text + try{ + rerum_err_text = await rerum_error_res.text() + } + catch(err) { + rerum_err_text = undefined + } + if(rerum_err_text) error.message = rerum_err_text + else { error.message = rerum_error_res.statusMessage ?? rerum_error_res.message ?? `An unhandled error occured, perhaps with RERUM.` } + error.status = rerum_error_res.statusCode ?? rerum_error_res.status ?? 500 + console.error(error) + res.set("Content-Type", "text/plain; charset=utf-8") + res.status(error.status).send(error.message) +} diff --git a/routes/create.js b/routes/create.js index 6a2c7f2..33c3359 100644 --- a/routes/create.js +++ b/routes/create.js @@ -18,8 +18,16 @@ router.post('/', checkAccessToken, async (req, res, next) => { } } const createURL = `${process.env.RERUM_API_ADDR}create` - const result = await fetch(createURL, createOptions).then(res=>res.json()) - .catch(err=>next(err)) + let errorState = false + const result = await fetch(createURL, createOptions).then(res=>{ + if(res.ok) return res.json() + errorState = true + return res + }) + .catch(err => { + throw err + }) + if (errorState) return next(result) res.setHeader("Location", result["@id"] ?? result.id) res.status(201) res.json(result) diff --git a/routes/delete.js b/routes/delete.js index ea941ef..3ce5851 100644 --- a/routes/delete.js +++ b/routes/delete.js @@ -23,7 +23,15 @@ router.delete('/', checkAccessToken, async (req, res, next) => { } } const deleteURL = `${process.env.RERUM_API_ADDR}delete` - const result = await fetch(deleteURL, deleteOptions).then(res => res.text()) + let errorState = false + const result = await fetch(deleteURL, deleteOptions).then(res=>{ + if(!res.ok) errorState = true + return res.text() + }) + .catch(err => { + throw err + }) + if (errorState) return next(results) res.status(204) res.send(result) } @@ -44,8 +52,15 @@ router.delete('/:id', async (req, res, next) => { 'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`, } } - const result = await fetch(deleteURL, deleteOptions).then(res => res.text()) - .catch(err=>next(err)) + let errorState = false + const result = await fetch(deleteURL, deleteOptions).then(res => { + if(!res.ok) errorState = true + return res + }) + .catch(err => { + throw err + }) + if (errorState) return next(results) res.status(204) res.send(result) } diff --git a/routes/overwrite.js b/routes/overwrite.js index 8c66600..29092ea 100644 --- a/routes/overwrite.js +++ b/routes/overwrite.js @@ -37,29 +37,34 @@ router.put('/', checkAccessToken, async (req, res, next) => { } const overwriteURL = `${process.env.RERUM_API_ADDR}overwrite` + let errorState = false const response = await fetch(overwriteURL, overwriteOptions) - .then(resp=>{ - if (!resp.ok) throw resp - return resp - }) - .catch(async err => { - // Handle 409 conflict error for version mismatch - if (err.status === 409) { - const currentVersion = await err.json() - return res.status(409).json(currentVersion) + .then(async rerum_res=>{ + if(rerum_res.ok) return rerum_res.json() + errorState = true + if(rerum_res.headers.get("Content-Type").includes("json")) { + if (rerum_res.status === 409) { + const currentVersion = await rerum_res.json() + return res.status(409).json(currentVersion) + } } - throw new Error(`Error in overwrite request: ${err.status} ${err.statusText}`) + return rerum_res + }) + .catch(err => { + throw err }) - if(res.headersSent) return + if (errorState) return next(response) const result = await response.json() const location = result?.["@id"] ?? result?.id if (location) { res.setHeader("Location", location) } - res.status(response.status ?? 200) + res.status(200) res.json(result) } catch (err) { + console.log("O-CAUGHT") + console.log(err) next(err) } }) diff --git a/routes/query.js b/routes/query.js index a147cc3..9b0fc50 100644 --- a/routes/query.js +++ b/routes/query.js @@ -25,8 +25,16 @@ router.post('/', async (req, res, next) => { } } const queryURL = `${process.env.RERUM_API_ADDR}query?limit=${lim}&skip=${skip}` - const results = await fetch(queryURL, queryOptions).then(res=>res.json()) - .catch(err=>next(err)) + let errorState = false + const results = await fetch(queryURL, queryOptions).then(res=>{ + if(res.ok) return res.json() + errorState = true + return res + }) + .catch(err => { + throw err + }) + if (errorState) return next(results) res.status(200) res.send(results) } diff --git a/routes/update.js b/routes/update.js index 391b3ce..748a6ca 100644 --- a/routes/update.js +++ b/routes/update.js @@ -23,8 +23,16 @@ router.put('/', checkAccessToken, async (req, res, next) => { } } const updateURL = `${process.env.RERUM_API_ADDR}update` - const result = await fetch(updateURL, updateOptions).then(res=>res.json()) - .catch(err=>next(err)) + let errorState = false + const result = await fetch(updateURL, updateOptions).then(res=>{ + if(res.ok) return res.json() + errorState = true + return res + }) + .catch(err => { + throw err + }) + if (errorState) return next(result) res.setHeader("Location", result["@id"] ?? result.id) res.status(200) res.send(result) From 8a8254f501dfd1e000a31841095272e652df6c15 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 16:38:45 -0500 Subject: [PATCH 02/14] polish and document --- routes/overwrite.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/routes/overwrite.js b/routes/overwrite.js index 29092ea..ff926f1 100644 --- a/routes/overwrite.js +++ b/routes/overwrite.js @@ -63,8 +63,6 @@ router.put('/', checkAccessToken, async (req, res, next) => { res.json(result) } catch (err) { - console.log("O-CAUGHT") - console.log(err) next(err) } }) From 3d5661179e806e654170561a1a6a313a84894998 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 16:46:35 -0500 Subject: [PATCH 03/14] polish and document --- error-messenger.js | 3 +++ routes/create.js | 9 +++++---- routes/delete.js | 13 +++++++------ routes/overwrite.js | 8 +++++--- routes/query.js | 7 ++++--- routes/update.js | 7 ++++--- 6 files changed, 28 insertions(+), 19 deletions(-) diff --git a/error-messenger.js b/error-messenger.js index 1878c32..5b84ca1 100644 --- a/error-messenger.js +++ b/error-messenger.js @@ -4,6 +4,9 @@ * This will also handle app level 404 errors. * * @param rerum_error_res An Express Response object from a request to RERUM that encountered an error. Explanatory text is in .text(). + * @param req The Express Request object from the request into TinyNode + * @param res The Express Response object to send out of TinyNode + * @param next The Express next() operator, unused here but required to support the middleware chain. */ export async function messenger(rerum_error_res, req, res, next) { if (res.headersSent) { diff --git a/routes/create.js b/routes/create.js index 33c3359..e149e64 100644 --- a/routes/create.js +++ b/routes/create.js @@ -18,16 +18,17 @@ router.post('/', checkAccessToken, async (req, res, next) => { } } const createURL = `${process.env.RERUM_API_ADDR}create` - let errorState = false + let errored = false const result = await fetch(createURL, createOptions).then(res=>{ - if(res.ok) return res.json() - errorState = true + if (res.ok) return res.json() + errored = true return res }) .catch(err => { throw err }) - if (errorState) return next(result) + // Send RERUM error responses to to error-messenger.js + if (errored) return next(result) res.setHeader("Location", result["@id"] ?? result.id) res.status(201) res.json(result) diff --git a/routes/delete.js b/routes/delete.js index 3ce5851..dd35ea6 100644 --- a/routes/delete.js +++ b/routes/delete.js @@ -23,15 +23,15 @@ router.delete('/', checkAccessToken, async (req, res, next) => { } } const deleteURL = `${process.env.RERUM_API_ADDR}delete` - let errorState = false + let errored = false const result = await fetch(deleteURL, deleteOptions).then(res=>{ - if(!res.ok) errorState = true + if(!res.ok) errored = true return res.text() }) .catch(err => { throw err }) - if (errorState) return next(results) + if (errored) return next(results) res.status(204) res.send(result) } @@ -52,15 +52,16 @@ router.delete('/:id', async (req, res, next) => { 'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`, } } - let errorState = false + let errored = false const result = await fetch(deleteURL, deleteOptions).then(res => { - if(!res.ok) errorState = true + if(!res.ok) errored = true return res }) .catch(err => { throw err }) - if (errorState) return next(results) + // Send RERUM error responses to to error-messenger.js + if (errored) return next(results) res.status(204) res.send(result) } diff --git a/routes/overwrite.js b/routes/overwrite.js index ff926f1..585c430 100644 --- a/routes/overwrite.js +++ b/routes/overwrite.js @@ -37,12 +37,13 @@ router.put('/', checkAccessToken, async (req, res, next) => { } const overwriteURL = `${process.env.RERUM_API_ADDR}overwrite` - let errorState = false + let errored = false const response = await fetch(overwriteURL, overwriteOptions) .then(async rerum_res=>{ if(rerum_res.ok) return rerum_res.json() - errorState = true + errored = true if(rerum_res.headers.get("Content-Type").includes("json")) { + // Special handling. This does not go through to error-messenger.js if (rerum_res.status === 409) { const currentVersion = await rerum_res.json() return res.status(409).json(currentVersion) @@ -53,7 +54,8 @@ router.put('/', checkAccessToken, async (req, res, next) => { .catch(err => { throw err }) - if (errorState) return next(response) + // Send RERUM error responses to to error-messenger.js + if (errored) return next(response) const result = await response.json() const location = result?.["@id"] ?? result?.id if (location) { diff --git a/routes/query.js b/routes/query.js index 9b0fc50..c343619 100644 --- a/routes/query.js +++ b/routes/query.js @@ -25,16 +25,17 @@ router.post('/', async (req, res, next) => { } } const queryURL = `${process.env.RERUM_API_ADDR}query?limit=${lim}&skip=${skip}` - let errorState = false + let errored = false const results = await fetch(queryURL, queryOptions).then(res=>{ if(res.ok) return res.json() - errorState = true + errored = true return res }) .catch(err => { throw err }) - if (errorState) return next(results) + // Send RERUM error responses to to error-messenger.js + if (errored) return next(results) res.status(200) res.send(results) } diff --git a/routes/update.js b/routes/update.js index 748a6ca..3819bd5 100644 --- a/routes/update.js +++ b/routes/update.js @@ -23,16 +23,17 @@ router.put('/', checkAccessToken, async (req, res, next) => { } } const updateURL = `${process.env.RERUM_API_ADDR}update` - let errorState = false + let errored = false const result = await fetch(updateURL, updateOptions).then(res=>{ if(res.ok) return res.json() - errorState = true + errored = true return res }) .catch(err => { throw err }) - if (errorState) return next(result) + // Send RERUM error responses to to error-messenger.js + if (errored) return next(result) res.setHeader("Location", result["@id"] ?? result.id) res.status(200) res.send(result) From 4e35b8093400aaca3024380c23f30466375b301f Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 17:03:02 -0500 Subject: [PATCH 04/14] future thing --- app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app.js b/app.js index 685e356..50a4547 100644 --- a/app.js +++ b/app.js @@ -18,6 +18,7 @@ let app = express() app.use(logger('dev')) app.use(express.json()) +app.use(express.text()) if(process.env.OPEN_API_CORS !== "false") { // This enables CORS for all requests. We may want to update this in the future and only apply to some routes. app.use( From 3eaf3453bc5d96ad6e3ba03c11e16192e646bb3e Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 17:31:43 -0500 Subject: [PATCH 05/14] changes and tests --- routes/__tests__/create.test.js | 4 +++- routes/__tests__/delete.test.js | 3 ++- routes/__tests__/overwrite.test.js | 4 ++-- routes/__tests__/query.test.js | 9 +++++++-- routes/__tests__/update.test.js | 4 +++- routes/overwrite.js | 2 +- 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/routes/__tests__/create.test.js b/routes/__tests__/create.test.js index 9b21d83..e928820 100644 --- a/routes/__tests__/create.test.js +++ b/routes/__tests__/create.test.js @@ -20,7 +20,9 @@ beforeEach(() => { */ global.fetch = jest.fn(() => Promise.resolve({ - json: () => Promise.resolve({ "@id": rerum_uri, "test": "item", "__rerum": { "stuff": "here" } }) + json: () => Promise.resolve({ "@id": rerum_uri, "test": "item", "__rerum": { "stuff": "here" } }), + ok: true, + text: () => Promise.resolve("Descriptive Error Here") }) ) }) diff --git a/routes/__tests__/delete.test.js b/routes/__tests__/delete.test.js index eeb6e11..f92d6b1 100644 --- a/routes/__tests__/delete.test.js +++ b/routes/__tests__/delete.test.js @@ -19,7 +19,8 @@ beforeEach(() => { */ global.fetch = jest.fn(() => Promise.resolve({ - text: () => Promise.resolve("") + text: () => Promise.resolve(""), + ok: true }) ) }) diff --git a/routes/__tests__/overwrite.test.js b/routes/__tests__/overwrite.test.js index 225c280..6ee5ae4 100644 --- a/routes/__tests__/overwrite.test.js +++ b/routes/__tests__/overwrite.test.js @@ -16,9 +16,9 @@ const rerum_tiny_test_obj_id = `${process.env.RERUM_ID_PATTERN}tiny_tester` beforeEach(() => { global.fetch = jest.fn(() => Promise.resolve({ - status: 200, + json: () => Promise.resolve({ "@id": rerum_tiny_test_obj_id, "testing": "item", "__rerum": { "stuff": "here" } }), ok: true, - json: () => Promise.resolve({ "@id": rerum_tiny_test_obj_id, "testing": "item", "__rerum": { "stuff": "here" } }) + text: () => Promise.resolve("Descriptive Error Here") }) ) }) diff --git a/routes/__tests__/query.test.js b/routes/__tests__/query.test.js index c7caed8..87bbb26 100644 --- a/routes/__tests__/query.test.js +++ b/routes/__tests__/query.test.js @@ -19,7 +19,9 @@ beforeEach(() => { */ global.fetch = jest.fn(() => Promise.resolve({ - json: () => Promise.resolve([{ "@id": rerum_uri, "test": "item", "__rerum": { "stuff": "here" } }]) + json: () => Promise.resolve([{ "@id": rerum_uri, "test": "item", "__rerum": { "stuff": "here" } }]), + ok: true, + text: () => Promise.resolve("Descriptive Error Here") }) ) }) @@ -36,7 +38,7 @@ beforeEach(() => { * * Note: /app/query uses the same logic and would be a redundant test. */ -describe("Check that the request/response behavior of the TinyNode query route functions. Mock the connection to RERUM. __mock_functions", () => { +describe("Check that the request/response behavior of the TinyNode query route functions. Mock the connection to RERUM. __mock_functions_q", () => { it("'/query' route request and response behavior is functioning.", async () => { const response = await request(routeTester) .post("/query") @@ -44,6 +46,9 @@ describe("Check that the request/response behavior of the TinyNode query route f .set("Content-Type", "application/json") .then(resp => resp) .catch(err => err) + console.log(response.statusCode) + console.log(response.status) + console.log(response.body) expect(response.statusCode).toBe(200) expect(response.body[0].test).toBe("item") }) diff --git a/routes/__tests__/update.test.js b/routes/__tests__/update.test.js index 3385609..1ddc3fc 100644 --- a/routes/__tests__/update.test.js +++ b/routes/__tests__/update.test.js @@ -21,7 +21,9 @@ beforeEach(() => { */ global.fetch = jest.fn(() => Promise.resolve({ - json: () => Promise.resolve({ "@id": rerum_uri_updated, "testing": "item", "__rerum": { "stuff": "here" } }) + json: () => Promise.resolve({ "@id": rerum_uri_updated, "testing": "item", "__rerum": { "stuff": "here" } }), + ok: true, + text: () => Promise.resolve("Descriptive Error Here") }) ) }) diff --git a/routes/overwrite.js b/routes/overwrite.js index 585c430..50ee479 100644 --- a/routes/overwrite.js +++ b/routes/overwrite.js @@ -56,7 +56,7 @@ router.put('/', checkAccessToken, async (req, res, next) => { }) // Send RERUM error responses to to error-messenger.js if (errored) return next(response) - const result = await response.json() + const result = response const location = result?.["@id"] ?? result?.id if (location) { res.setHeader("Location", location) From 2565f70ce62af78dac0bd9b3e8410378598b0c72 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 17:36:14 -0500 Subject: [PATCH 06/14] changes and tests --- routes/__tests__/query.test.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/routes/__tests__/query.test.js b/routes/__tests__/query.test.js index 87bbb26..3b62cd4 100644 --- a/routes/__tests__/query.test.js +++ b/routes/__tests__/query.test.js @@ -38,7 +38,7 @@ beforeEach(() => { * * Note: /app/query uses the same logic and would be a redundant test. */ -describe("Check that the request/response behavior of the TinyNode query route functions. Mock the connection to RERUM. __mock_functions_q", () => { +describe("Check that the request/response behavior of the TinyNode query route functions. Mock the connection to RERUM. __mock_functions", () => { it("'/query' route request and response behavior is functioning.", async () => { const response = await request(routeTester) .post("/query") @@ -46,9 +46,6 @@ describe("Check that the request/response behavior of the TinyNode query route f .set("Content-Type", "application/json") .then(resp => resp) .catch(err => err) - console.log(response.statusCode) - console.log(response.status) - console.log(response.body) expect(response.statusCode).toBe(200) expect(response.body[0].test).toBe("item") }) From d33245d009986d2187c01c497d19d1fdaeec1985 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 17:43:17 -0500 Subject: [PATCH 07/14] polish --- error-messenger.js | 10 ++++++---- routes/delete.js | 2 +- routes/overwrite.js | 4 ++-- routes/query.js | 2 +- routes/update.js | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/error-messenger.js b/error-messenger.js index 5b84ca1..9968d32 100644 --- a/error-messenger.js +++ b/error-messenger.js @@ -14,14 +14,16 @@ export async function messenger(rerum_error_res, req, res, next) { } let error = {} let rerum_err_text - try{ + try { rerum_err_text = await rerum_error_res.text() } - catch(err) { + catch (err) { rerum_err_text = undefined } - if(rerum_err_text) error.message = rerum_err_text - else { error.message = rerum_error_res.statusMessage ?? rerum_error_res.message ?? `An unhandled error occured, perhaps with RERUM.` } + if (rerum_err_text) error.message = rerum_err_text + else { + error.message = rerum_error_res.statusMessage ?? rerum_error_res.message ?? `An unhandled error occured, perhaps with RERUM.` + } error.status = rerum_error_res.statusCode ?? rerum_error_res.status ?? 500 console.error(error) res.set("Content-Type", "text/plain; charset=utf-8") diff --git a/routes/delete.js b/routes/delete.js index dd35ea6..adcd6f4 100644 --- a/routes/delete.js +++ b/routes/delete.js @@ -25,7 +25,7 @@ router.delete('/', checkAccessToken, async (req, res, next) => { const deleteURL = `${process.env.RERUM_API_ADDR}delete` let errored = false const result = await fetch(deleteURL, deleteOptions).then(res=>{ - if(!res.ok) errored = true + if (!res.ok) errored = true return res.text() }) .catch(err => { diff --git a/routes/overwrite.js b/routes/overwrite.js index 50ee479..15e43cf 100644 --- a/routes/overwrite.js +++ b/routes/overwrite.js @@ -40,9 +40,9 @@ router.put('/', checkAccessToken, async (req, res, next) => { let errored = false const response = await fetch(overwriteURL, overwriteOptions) .then(async rerum_res=>{ - if(rerum_res.ok) return rerum_res.json() + if (rerum_res.ok) return rerum_res.json() errored = true - if(rerum_res.headers.get("Content-Type").includes("json")) { + if (rerum_res.headers.get("Content-Type").includes("json")) { // Special handling. This does not go through to error-messenger.js if (rerum_res.status === 409) { const currentVersion = await rerum_res.json() diff --git a/routes/query.js b/routes/query.js index c343619..071e49c 100644 --- a/routes/query.js +++ b/routes/query.js @@ -27,7 +27,7 @@ router.post('/', async (req, res, next) => { const queryURL = `${process.env.RERUM_API_ADDR}query?limit=${lim}&skip=${skip}` let errored = false const results = await fetch(queryURL, queryOptions).then(res=>{ - if(res.ok) return res.json() + if (res.ok) return res.json() errored = true return res }) diff --git a/routes/update.js b/routes/update.js index 3819bd5..038e7c2 100644 --- a/routes/update.js +++ b/routes/update.js @@ -25,7 +25,7 @@ router.put('/', checkAccessToken, async (req, res, next) => { const updateURL = `${process.env.RERUM_API_ADDR}update` let errored = false const result = await fetch(updateURL, updateOptions).then(res=>{ - if(res.ok) return res.json() + if (res.ok) return res.json() errored = true return res }) From 95ef3f504268c61f6a4d76b158b37205074625dd Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 17:46:54 -0500 Subject: [PATCH 08/14] polish --- error-messenger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/error-messenger.js b/error-messenger.js index 9968d32..b7fcab8 100644 --- a/error-messenger.js +++ b/error-messenger.js @@ -3,7 +3,7 @@ * We want to send the same error and message through. It is assumed to be RESTful and useful. * This will also handle app level 404 errors. * - * @param rerum_error_res An Express Response object from a request to RERUM that encountered an error. Explanatory text is in .text(). + * @param rerum_error_res A Fetch API Response object from a fetch() to RERUM that encountered an error. Explanatory text is in .text(). * @param req The Express Request object from the request into TinyNode * @param res The Express Response object to send out of TinyNode * @param next The Express next() operator, unused here but required to support the middleware chain. From 892f353906cbb1f21e3f14ccb4a4c3931db5fde0 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 17:53:31 -0500 Subject: [PATCH 09/14] polish --- app.js | 2 +- error-messenger.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 50a4547..5063775 100644 --- a/app.js +++ b/app.js @@ -69,7 +69,7 @@ app.use('/app/update', updateRouter) app.use('/app/delete', deleteRouter) app.use('/app/overwrite', overwriteRouter) -// RERUM error response handler, and app 404s +// RERUM error response handler, as well as unhandled generic app error handler app.use(messenger) export default app diff --git a/error-messenger.js b/error-messenger.js index b7fcab8..84ef076 100644 --- a/error-messenger.js +++ b/error-messenger.js @@ -1,7 +1,7 @@ /** * Errors from RERUM are a response code with a text body (except those handled specifically upstream) * We want to send the same error and message through. It is assumed to be RESTful and useful. - * This will also handle app level 404 errors. + * This will also handle generic (500) app level errors, as well as app level 404 errors. * * @param rerum_error_res A Fetch API Response object from a fetch() to RERUM that encountered an error. Explanatory text is in .text(). * @param req The Express Request object from the request into TinyNode @@ -22,6 +22,7 @@ export async function messenger(rerum_error_res, req, res, next) { } if (rerum_err_text) error.message = rerum_err_text else { + // Perhaps this is a more generic 500 from the app and there is no good rerum_error_res error.message = rerum_error_res.statusMessage ?? rerum_error_res.message ?? `An unhandled error occured, perhaps with RERUM.` } error.status = rerum_error_res.statusCode ?? rerum_error_res.status ?? 500 From 6e59876a9fcac2b8234d5c9b10054b85fd273c88 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 17:56:17 -0500 Subject: [PATCH 10/14] polish --- error-messenger.js | 2 +- routes/create.js | 2 +- routes/delete.js | 2 +- routes/overwrite.js | 2 +- routes/query.js | 2 +- routes/update.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/error-messenger.js b/error-messenger.js index 84ef076..083b4b8 100644 --- a/error-messenger.js +++ b/error-messenger.js @@ -1,6 +1,6 @@ /** * Errors from RERUM are a response code with a text body (except those handled specifically upstream) - * We want to send the same error and message through. It is assumed to be RESTful and useful. + * We want to send the same error code and message through. It is assumed to be RESTful and useful. * This will also handle generic (500) app level errors, as well as app level 404 errors. * * @param rerum_error_res A Fetch API Response object from a fetch() to RERUM that encountered an error. Explanatory text is in .text(). diff --git a/routes/create.js b/routes/create.js index e149e64..23056f4 100644 --- a/routes/create.js +++ b/routes/create.js @@ -27,7 +27,7 @@ router.post('/', checkAccessToken, async (req, res, next) => { .catch(err => { throw err }) - // Send RERUM error responses to to error-messenger.js + // Send RERUM error responses to error-messenger.js if (errored) return next(result) res.setHeader("Location", result["@id"] ?? result.id) res.status(201) diff --git a/routes/delete.js b/routes/delete.js index adcd6f4..7f2f780 100644 --- a/routes/delete.js +++ b/routes/delete.js @@ -60,7 +60,7 @@ router.delete('/:id', async (req, res, next) => { .catch(err => { throw err }) - // Send RERUM error responses to to error-messenger.js + // Send RERUM error responses to error-messenger.js if (errored) return next(results) res.status(204) res.send(result) diff --git a/routes/overwrite.js b/routes/overwrite.js index 15e43cf..b2bb6dd 100644 --- a/routes/overwrite.js +++ b/routes/overwrite.js @@ -54,7 +54,7 @@ router.put('/', checkAccessToken, async (req, res, next) => { .catch(err => { throw err }) - // Send RERUM error responses to to error-messenger.js + // Send RERUM error responses to error-messenger.js if (errored) return next(response) const result = response const location = result?.["@id"] ?? result?.id diff --git a/routes/query.js b/routes/query.js index 071e49c..4b06a82 100644 --- a/routes/query.js +++ b/routes/query.js @@ -34,7 +34,7 @@ router.post('/', async (req, res, next) => { .catch(err => { throw err }) - // Send RERUM error responses to to error-messenger.js + // Send RERUM error responses to error-messenger.js if (errored) return next(results) res.status(200) res.send(results) diff --git a/routes/update.js b/routes/update.js index 038e7c2..b5ca5d5 100644 --- a/routes/update.js +++ b/routes/update.js @@ -32,7 +32,7 @@ router.put('/', checkAccessToken, async (req, res, next) => { .catch(err => { throw err }) - // Send RERUM error responses to to error-messenger.js + // Send RERUM error responses to error-messenger.js if (errored) return next(result) res.setHeader("Location", result["@id"] ?? result.id) res.status(200) From 575b17a55f5bd19541ba318c37cb53f3e879f70c Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Tue, 8 Jul 2025 17:58:26 -0500 Subject: [PATCH 11/14] polish --- error-messenger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/error-messenger.js b/error-messenger.js index 083b4b8..74236b0 100644 --- a/error-messenger.js +++ b/error-messenger.js @@ -3,7 +3,7 @@ * We want to send the same error code and message through. It is assumed to be RESTful and useful. * This will also handle generic (500) app level errors, as well as app level 404 errors. * - * @param rerum_error_res A Fetch API Response object from a fetch() to RERUM that encountered an error. Explanatory text is in .text(). + * @param rerum_error_res A Fetch API Response object from a fetch() to RERUM that encountered an error. Explanatory text is in .text(). In some cases it is a unhandled generic (500) app level Error. * @param req The Express Request object from the request into TinyNode * @param res The Express Response object to send out of TinyNode * @param next The Express next() operator, unused here but required to support the middleware chain. From 983eaed9cb5a7a6726f8ffcdcf4b8e9d5a4d0c90 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Wed, 9 Jul 2025 08:32:02 -0500 Subject: [PATCH 12/14] polish --- error-messenger.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/error-messenger.js b/error-messenger.js index 74236b0..acaa354 100644 --- a/error-messenger.js +++ b/error-messenger.js @@ -15,15 +15,17 @@ export async function messenger(rerum_error_res, req, res, next) { let error = {} let rerum_err_text try { + // Unless already handled upstream the rerum_error_res is an error Response with details as a textual body. rerum_err_text = await rerum_error_res.text() } catch (err) { + // It is some 500 rerum_err_text = undefined } if (rerum_err_text) error.message = rerum_err_text else { - // Perhaps this is a more generic 500 from the app and there is no good rerum_error_res - error.message = rerum_error_res.statusMessage ?? rerum_error_res.message ?? `An unhandled error occured, perhaps with RERUM.` + // Perhaps this is a more generic 500 from the app, perhaps involving RERUM, and there is no good rerum_error_res + error.message = rerum_error_res.statusMessage ?? rerum_error_res.message ?? `A server error has occured` } error.status = rerum_error_res.statusCode ?? rerum_error_res.status ?? 500 console.error(error) From dec5ed5311d4bedf2e6719cf728c96879b5b8082 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Wed, 9 Jul 2025 08:35:31 -0500 Subject: [PATCH 13/14] polish --- routes/delete.js | 1 + 1 file changed, 1 insertion(+) diff --git a/routes/delete.js b/routes/delete.js index 7f2f780..a3e80a1 100644 --- a/routes/delete.js +++ b/routes/delete.js @@ -31,6 +31,7 @@ router.delete('/', checkAccessToken, async (req, res, next) => { .catch(err => { throw err }) + // Send RERUM error responses to error-messenger.js if (errored) return next(results) res.status(204) res.send(result) From 92e8d1e82cc7d16a82605fc805fbe46041d61562 Mon Sep 17 00:00:00 2001 From: Bryan Haberberger Date: Wed, 9 Jul 2025 10:14:55 -0500 Subject: [PATCH 14/14] setMessage is undefined --- public/scripts/api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/api.js b/public/scripts/api.js index b16b25b..ce165f0 100644 --- a/public/scripts/api.js +++ b/public/scripts/api.js @@ -126,7 +126,7 @@ function create(form) { JSON.parse(obj) } catch (error) { console.error("You did not provide valid JSON") - setMessage("You did not provide valid JSON") + _customEvent("rerum-error", "You did not provide valid JSON", {}, error) document.getElementById("obj-viewer").style.display = "none" return false }