One input per field in the ID that is optional. This field is marked as being the ID.
Inputs for other fields on the body. All fields that are not nullable and can’t be populated by the system on create should be required.
Pseudo-Code
functionupsertObjectById(obj){
// If the object's ID is split across more than one field, we should check
// that either all ID fields are populated or that none are. Otherwise we
// should throw an exception.
const objectToUpdate = GetObjectById(obj.id); // Usually GET verb
if(objectToUpdate == null) {
const createdObject = CreateObject(obj); // Usually POST verb
EmitData(createdObject);
} else {
const updatedObject = UpdateObject(obj, id); // Usually POST/PATCH verb
EmitData(updatedObject);
}
}
Output Data
The object post creation/update as reported by the system
Gotcha’s to lookout for
Updates should be partial updates
Make sure to Url Encode IDs appearing in HTTP urls
Iteration 2: Update Object By Unique Criteria
Additional Config Fields
Upsert Criteria: Drop down with all sets of unique constraints for the object in question
Input Metadata Changes
The fields that are part of the upsert criteria are marked as being part of the criteria. If the criteria is something other than the ID, they should be marked as required.
(There is a hypothetical edge case here where the system auto-populates the unique criteria)
Upsert Object
Iteration 1: Upsert Object By ID
function upsertObjectById(obj) {
// If the object's ID is split across more than one field, we should check
// that either all ID fields are populated or that none are. Otherwise we
// should throw an exception.
const objectToUpdate = GetObjectById(obj.id); // Usually GET verb
if(objectToUpdate == null) {
const createdObject = CreateObject(obj); // Usually POST verb
EmitData(createdObject);
} else {
const updatedObject = UpdateObject(obj, id); // Usually POST/PATCH verb
EmitData(updatedObject);
}
}
Iteration 2: Update Object By Unique Criteria
function upsertObjectByUniqueCriteria(obj, uniqueCriteria) {
// Ensure unique criteria are all populated (unless ID)
// If criteira is th the object's ID and it is split across more than one field, we should check
// that either all ID fields are populated or that none are. Otherwise we
// should throw an exception.
const objectsToUpdate = GetObjectsByCritieria(uniqueCriteria); // Usually GET verb
if(objectsToUpdate.length == 0) {
const createdObject = CreateObject(obj); // Usually POST verb
EmitData(createdObject);
} else if (objectsToUpdate.length == 1) {
const updatedObject = UpdateObject(obj, objectsToUpdate[0].id); // Usually POST/PATCH verb
EmitData(updatedObject);
} else {
throw new Error(`More than one matching object found.`);