An API providing a PATCH
endpoint should ensure two things:
1 - When the PATCH
endpoint is sent a body with an unsupported media type, the response should include an Accept-Patch
header, advertising the correct media type. This is specified in RFC5789, Section 2.2:
Unsupported patch document: Can be specified using a 415 (Unsupported Media Type) response when the client sends a patch document format that the server does not support for the resource identified by the Request-URI. Such a response SHOULD include an Accept-Patch response header as described in Section 3.1 to notify the client what patch document media types are supported.
2 - The OPTIONS
endpoint should advertise the accepted request media types through its Accept-Patch
header. This is stated in RFC5789, Section 3:
Accept-Patch SHOULD appear in the OPTIONS response for any resource that supports the use of the PATCH method. The presence of the Accept-Patch header in response to any method is an implicit indication that PATCH is allowed on the resource identified by the Request-URI. The presence of a specific patch document format in this header indicates that that specific format is allowed on the resource identified by the Request-URI.
It would be great if this would happen by default. Currently, Spring MVC doesn't add the header for either PATCH
or OPTIONS
, so I had to add this myself:
const val ACCEPT_PATCH_HEADER = "Accept-Patch"
const val APPLICATION_MERGE_PATCH_JSON_VALUE = "application/merge-patch+json"
// if used with a wrong media type, provide the Accept-Patch header with the error response
// as suggested by RFC 5789 "PATCH Method for HTTP" https://tools.ietf.org/html/rfc5789#section-2.2
@PatchMapping("/{id}")
@ResponseStatus(UNSUPPORTED_MEDIA_TYPE)
fun patchBadMediaType(response: HttpServletResponse) {
response.addHeader(ACCEPT_PATCH_HEADER, APPLICATION_MERGE_PATCH_JSON_VALUE)
}
// advertise the Accept-Patch header as additional information
// as suggested by RFC 5789 "PATCH Method for HTTP" https://tools.ietf.org/html/rfc5789#section-3
@RequestMapping("/{id}", method = [RequestMethod.OPTIONS])
fun optionsForId(response: HttpServletResponse) {
response.setHeader(ALLOW, "GET, HEAD, POST, PUT, OPTIONS, PATCH")
response.addHeader(ACCEPT_PATCH_HEADER, APPLICATION_MERGE_PATCH_JSON_VALUE)
}
Note that I had to set the Allow
header values manually, which would only be added correctly if I hadn't implemented the method myself. I might create an own issue for this.
Comment From: igorakkerman
Thanks for implementing this so quickly. Works for me with the snapshot version, I can remove my own controller methods now.