The browser (Chrome / Firefox) doesn't send If-Match request header in PATCH request to already cached resource.
I made a test web page with 2 buttons, one for GET request the other for PATCH and the script which sends requests using Fetch API.
document.getElementById('get-btn').addEventListener('click', async () => {
await fetch("http://test.local/api/v1/test", {
method: 'GET',
headers: {
'Accept': 'application/hal+json',
'Authorization': 'Bearer XXXXX',
}
});
});
document.getElementById('patch-btn').addEventListener('click', async () => {
await fetch("http://test.local/api/v1/test", {
method: 'PATCH',
headers: {
'Accept': 'application/hal+json',
'Authorization': 'Bearer XXXXX',
'Content-Type': 'application/json'
},
body: JSON.stringify({})
});
});
The API endpoint always returns an Etag response header for GET method. The Etag value is some md5 hash (e.g. "ffsd8fsd9adsf"). Test scenario:
- First click on button that initiates the GET request - server returns 200 with an Etag response header.
- Second click on button that initiates the GET request - browser sends If-None-Match request header with an etag value - server returns 304 with an Etag response header.
- First click on button that initiates the PATCH request - browser doesn't send If-Match request header with an etag value - server returns 428 Precondition Required.
Note: Access-Control-Allow-Headers allows If-Match.
Now, my question: Is it me responsible for sending If-Match request header in PATCH request or I'm missing something that prevents browser from adding If-Match request header in same way as it automatically adds If-None-Match for GET request ?
If it's my responsibility to include If-Match header then what is an explanation for inconsistent behavior of browsers that they add If-None-Match to GET request but don't add If-Match to PATCH request ?
Your code, not the browser, is responsible for adding the
If-Matchheader. That's because whether or not to do so is a question of application logic.The PATCH standard mentions this (and the same is true for
PUTandPOST):The browser doesn't know what kind of application you have, so it would be inappropriate to automatically add the header just because it has a record of the current ETag.
By contrast, the conditional request logic behind
If-None-Matchhas nothing to do with application logic; it's just a performance enhancement. If the conditional request is successful the client already has the same resource that the server would have sent, so there's no reason to send it again. So it's safe for the browser to handle this for you.