In March the company that installs our heating units started calling customers to ask how to get into their properties. Their engineers' job sheets had lost the access notes, the key safe locations and the second contact numbers we had sent them. About six thousand customers in all.
We had rewritten our customer sync to their field service API that month. The old version sent each changed customer in full with PUT. The new one used PATCH, which their API offers, so that a change of phone number would send only the phone number. The partner's documentation says their PATCH takes application/merge-patch+json, and we read that as a detail of the content type.
It is a whole set of rules, written down in RFC 7396. In a merge patch a member that is absent means leave this field alone, and a member set to null means remove this field. Our sync loaded only the fields that had changed into a customer object and serialised the object with our JSON library's default settings, which write every property, including the ones that are null. So a change of email address arrived as the new email and null for every other field on the customer, and the partner did exactly what the RFC asks. Each update was accepted with 200, and each one emptied out the fields we had not touched.
Our tests checked that the field we changed arrived. None of them checked what happened to the fields we did not change.
The partner restored the records from their audit history within two days, at our cost. In our client, the serializer for every merge patch request now leaves out null and absent properties, and a field we really mean to clear has to be marked explicitly, so absent, null and a value are three different states in our code, as they are in the RFC. A contract test against the partner's sandbox sets a field, patches a different one and checks that the first is still there. And a weekly job compares a sample of customers on both sides and reports any field that is empty there and filled in here.
In a merge patch, null is not the absence of a value. It is an instruction, and we had been sending it six thousand times without meaning a word of it.
– Sergey Shinder
Top comments (0)