diff --git a/bin/rerum_v1.js b/bin/rerum_v1.js index a1b953d6..c81dcaf9 100644 --- a/bin/rerum_v1.js +++ b/bin/rerum_v1.js @@ -16,7 +16,6 @@ import config from '../config/index.js' const port = config.PORT ?? 3001 app.set('port', port) - /** * Create HTTP server. */ @@ -73,3 +72,4 @@ function onListening() { : 'port ' + addr.port debug('Listening on ' + bind) } + diff --git a/controllers/bulk.js b/controllers/bulk.js index 9fb78e6d..ac6d4eb7 100644 --- a/controllers/bulk.js +++ b/controllers/bulk.js @@ -12,43 +12,60 @@ import config from '../config/index.js' import { _contextid, ObjectID, createExpressError, getAgentClaim, parseDocumentID, idNegotiation } from './utils.js' /** - * Create many objects at once with the power of MongoDB bulkWrite() operations. - * - * @see https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/ + * Sets standard JSON response headers on the Express response object. + * @param {import('express').Response} res - Express response object */ -const bulkCreate = async function (req, res, next) { +function setJsonHeaders(res) { res.set("Content-Type", "application/json; charset=utf-8") +} + + +//function to validate request body is a non-empty array +function requireNonEmptyArrayBody(req) { const documents = req.body - let err = {} if (!Array.isArray(documents)) { - err.message = "The request body must be an array of objects." - err.status = 400 - next(createExpressError(err)) - return + throw { message: "The request body must be an array of objects.", status: 400 } } if (documents.length === 0) { - err.message = "No action on an empty array." - err.status = 400 - next(createExpressError(err)) - return + throw { message: "No action on an empty array.", status: 400 } } + return documents +} + + +//check if an item is valid JSON object (not array) +function isValidJsonObject(d) { + return d !== null && typeof d === "object" && !Array.isArray(d) +} + +/** + * Create many objects at once with the power of MongoDB bulkWrite() operations. + * + * @see https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/ + */ +const bulkCreate = async function (req, res, next) { + setJsonHeaders(res) + + let documents + try { + documents = requireNonEmptyArrayBody(req) + } catch (err) { + return next(createExpressError(err)) + } + const gatekeep = documents.filter(d=> { // Each item must be valid JSON, but can't be an array. - if(Array.isArray(d) || typeof d !== "object") return d - try { - JSON.parse(JSON.stringify(d)) - } catch (err) { - return d - } + if (!isValidJsonObject(d)) return d + // Items must not have an @id, and in some cases same for id. const idcheck = _contextid(d["@context"]) ? (d.id ?? d["@id"]) : d["@id"] if(idcheck) return d }) if (gatekeep.length > 0) { - err.message = "All objects in the body of a `/bulkCreate` must be JSON and must not contain a declared identifier property." - err.status = 400 - next(createExpressError(err)) - return + return next(createExpressError({ + message: "All objects in the body of a `/bulkCreate` must be JSON and must not contain a declared identifier property.", + status: 400 + })) } // TODO: bulkWrite SLUGS? Maybe assign an id to each document and then use that to create the slug? @@ -105,40 +122,28 @@ const bulkCreate = async function (req, res, next) { * @see https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/ */ const bulkUpdate = async function (req, res, next) { - res.set("Content-Type", "application/json; charset=utf-8") - const documents = req.body - let err = {} - let encountered = [] - if (!Array.isArray(documents)) { - err.message = "The request body must be an array of objects." - err.status = 400 - next(createExpressError(err)) - return - } - if (documents.length === 0) { - err.message = "No action on an empty array." - err.status = 400 - next(createExpressError(err)) - return + setJsonHeaders(res) + + let documents + try { + documents = requireNonEmptyArrayBody(req) + } catch (err) { + return next(createExpressError(err)) } + + let encountered = [] const gatekeep = documents.filter(d => { - // Each item must be valid JSON, but can't be an array. - if(Array.isArray(d) || typeof d !== "object") return d - try { - JSON.parse(JSON.stringify(d)) - } catch (err) { - return d - } - // Items must have an @id, or in some cases an id will do + if (!isValidJsonObject(d)) return true const idcheck = _contextid(d["@context"]) ? (d.id ?? d["@id"]) : d["@id"] - if(!idcheck) return d + if (!idcheck) return true // Reject items WITHOUT an id (updates need an id) + return false }) // The empty {}s will cause this error if (gatekeep.length > 0) { - err.message = "All objects in the body of a `/bulkUpdate` must be JSON and must contain a declared identifier property." - err.status = 400 - next(createExpressError(err)) - return + return next(createExpressError({ + message: "All objects in the body of a `/bulkUpdate` must be JSON and must contain a declared identifier property.", + status: 400 + })) } // unordered bulkWrite() operations have better performance metrics. let bulkOps = [] diff --git a/package-lock.json b/package-lock.json index c5f495e3..d688c74a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "debug": "~4.4.3", "dotenv": "~17.2.3", "express": "^5.2.1", - "express-oauth2-jwt-bearer": "~1.7.1", + "express-oauth2-jwt-bearer": "^1.7.4", "express-urlrewrite": "~2.0.3", "mongodb": "^7.0.0", "morgan": "~1.10.1" @@ -2568,9 +2568,9 @@ } }, "node_modules/express-oauth2-jwt-bearer": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/express-oauth2-jwt-bearer/-/express-oauth2-jwt-bearer-1.7.1.tgz", - "integrity": "sha512-IYwLHW9bysGnASwFfXqEZ2aJzY2g4B9P36sWgeIkSqWh1SjeIc8mfoeNsBpzil/lhXNWuttPH0rWQ6norZUBIg==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/express-oauth2-jwt-bearer/-/express-oauth2-jwt-bearer-1.7.4.tgz", + "integrity": "sha512-teO/eyvU8OkJXiP4cRuoJMrp31nNvjnL47MIkso0D/21AqUGv1O+VEiLisrDA8xjkaCBTufYnV1zepCOCLK4vg==", "license": "MIT", "dependencies": { "jose": "^4.15.5" diff --git a/package.json b/package.json index 53088757..bd44127c 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "debug": "~4.4.3", "dotenv": "~17.2.3", "express": "^5.2.1", - "express-oauth2-jwt-bearer": "~1.7.1", + "express-oauth2-jwt-bearer": "^1.7.4", "express-urlrewrite": "~2.0.3", "mongodb": "^7.0.0", "morgan": "~1.10.1"