We are building a backoffice web application where people are making changes to an array of nested objects. Because of totally non relevant business reasons there are things that users cannot change but can still send in. It is assumed that some people might not use the frontend but directly call the backend, so we cannot just "omit" values that cannot change from the requests the frontend will send.
To give you an example let's say you have an admin page for users home appliances: you can change the name
of the appliance ("Eric's fridge" to "Kitchen fridge") but you are not allowed to change the serialNumber
of it.
In the cases when a change is about to happen on those "special paths" we want to drop the it and return useful error messages, e.g. "Changing serialNumber
of User[3].device[4]
is not allowed".
To go further in the question we use the following technologies:
node.js
for the backendjoi
for validating requests
Also I assume that for update operations like these you have to query the object about to change.
The bird's eye view is this:
- The request hits backend
- Validation by
JOI
happens - A request is sent to DB to fetch the existing objects
- The new and old values are compared and checked if values differ only on specific paths
- The request is either committed and
200
sent back or dropped and400 Bad Request
with relevant error message is sent back.
Looking at the documentation I could not find anything on this, but it seems to be fairly common to have existing solutions out there, so it might be that I have missed some obvious ones (I fairly infrequently work on backend).
The expected answers should tell if there are existing libraries for this case to avoid reinventing the wheel and also should point me how much custom logic should be written for this.
Where would you put the comparison logic?
Can it be added to the JOI
validation? If so should the custom validator query the DB?
Or should it happen after JOI
validation as a separate non-JOI
custom step?
In this case I am curious what is considered a best practice? Stuffing everything to work in the validator library or can it be a custom "secondary" step?
The scalable solution for us would be to have a configurable list of paths that cannot change.
To give you some pseudo-code:
const listOfPathsThatCannotChange = [
'user[*].device[*].serialNumber',
'user[*].id',
'user[*].auditInfo[*].supportAgentEmail',
'...'
];
const comparisonResults = compare({
a: request,
b: objectStoredInDb,
bannedPaths: listOfPathsThatCannotChange
});
if (comparisonResults.length > 0) {
send(400, comparisonResults);
return;
}
send(200);
Thanks for reading/commenting/answering!
serialNumber
element, then everyone just has to conform to that, regardless of if they are using the regular frontend or not.