REST API - Handling an empty body in PATCH - rest

I am currently contributing to a REST API written in Go and I was facing an existential question.
How are we supposed to handle an empty body in a PATCH? Knowing that a PATCH is used to update an existing data, are we supposed to return an error code (4XX) or an ok status (2XX)?
For example, if I have the following route: /user/:id
And a user has the following structure:
type User struct {
Name string
Email string
}
So if we PATCH a specific user, we will either have a body containing the name or the email.
What should we do if it is empty?
The RFC5789 was not a real help (2.2 for error handling)
https://datatracker.ietf.org/doc/rfc5789/?include_text=1

How are we supposed to handle an empty body in a PATCH?
That depends: what's wrong with an empty patch body?
If an empty patch body is an error, then your response should communicate the nature of the error to the client.
If the empty patch body is not an error, then apply the empty patch. That's probably a no-op, in which case, success! So you return a response that explains that applying empty patches is trivial, and here's where they can go to see the updated implementation. Alternatively, you can 204 as shown in the example. I don't see things explicitly spelled out, but I think you can draw upon the pattern described in RFC 7231 section 6.3.1.
Some examples that might help.
Suppose the client were using JSON Patch as the media type for the request. Now, a "JSON Patch document is a JSON [RFC4627] document that represents an array of objects". An empty request body is not a valid JSON document, and certainly isn't a valid array of objects, so that's a malformed patch document, and as described in section 2.2 you should be thinking about sending a 400 response.
Suppose the client were to send a json patch with an empty array of operations
[]
Semantically, that's a no-op -- except that a response indicating that the patch was successfully applied will invalidate cached values. So you could certainly report success (200) with not doing anything. You may be able to prevent the cached entries from being invalidated by returning an error (I think the Patch spec isn't quite describing the semantics correctly, but I don't see an errata filed).
A similar argument applies for application/merge-patch+json.
You may also want to consider the errata for RFC 5789
If a server receives a PATCH request with a media type whose specification does not define semantics specific to PATCH, the server SHOULD reject the request by returning the 415 Unsupported Media Type status code, unless a more specific error status code takes priority.
In particular, servers SHOULD NOT assume PATCH semantics for generic media types that don't define them, such as "application/xml" or "application/json".

The MDN used 204 No Content in an example here:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH#response

Related

HTTP response code for REST GET - subresource not found (but not referenced by identifier)

I'm building a REST API and have a dilemma around the returning response code to a GET operation.
I've found many examples and answers online but not for my particular scenario.
Here is what I have found and understand so far:
if returning an empty list (say /library/authors/{authorId}/books) an empty list with a response code 200 will suffice
if requesting a specific resource with an id ( say /library/authors/{authorId}/books/{bookId} ) the response will be empty with a 404
That summarizes most of my use cases and I am fine with it.
However, what happens if I access a sub-resource without an id?
For example, for arguments sake, let's say the author can have many books, but only one auto-biography. He either has one or he doesn't. I don't expect the user to pass in the auto-biography id because the system can figure out on its own if one exists, the endpoint is something like this:
GET /library/authors/{authorId}/auto-biography
If the author exists but he has no autobiography (it is NULL), would the http response code be:
204 (empty content)
404 (resource does not exist)
Thank you in advance!
Working through the semantics
GET /library/authors/1/auto-biography
/library/authors/1/auto-biography is an identifier. The resource itself is some concept like "the auto biography of author 1"; notice that we can talk about the resource even though it may not actually exist yet.
A resource can map to the empty set, which allows references to be made to a concept before any realization of that concept exists
The thing that appears in the body of the HTTP response isn't the resource, but a representation of the resource.
So now look at the status codes
404
The 404 (Not Found) status code indicates that the origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
204
The 204 (No Content) status code indicates that the server has successfully fulfilled the request and that there is no additional content to send in the response payload body.
A loose analogy: suppose you try to get the contents of a file. 404 is semantically aligned with FileNotFound; 204 indicates the file is zero bytes long.
404 would normally be accompanied by "a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition." It indicates that the client tried to use a link that shouldn't have been available.
204, on the other hand, doesn't have anything -- the representation is zero bytes long, how could there be data. It's a special case of a 200 response, advising the client (and intermediary components) that the response body is intentionally left blank.

Response to a PATCH request

Suppose I have an endpoint /api/todos and I make a PATCH request to change one of the todos. Does it ever make sense for my PATCH request to have in the response body the list of all of the todos?
Is there any specification that I can read about this?
I have talked to some developers and the general consensus is that the PATCH method should only return the changed entry. I agree with this point but am looking for documentation detailing this.
The RFC is here.
But it doesn't really specify anything. Here's an example from it:
Successful PATCH response to existing text file:
HTTP/1.1 204 No Content
Content-Location: /file.txt
ETag: "e0023aa4f"
The 204 response code is used because the response does not carry a
message body (which a response with the 200 code would have). Note
that other success codes could be used as well.
So you can implement it however you wish. Responding with just the changed entry would be more inline with how other methods (PUT, DELETE, etc.) are usually handled, so I would do it that way.
So when you want to provide a RESTfull api /api/todos represents a ressource where every todo has an separate id. Here you would patch e.g. to `/api/todos/4' to update the todo with the id 4.
The usual behaviour here would be to responde with either a 204 Status Code or with the updated object to save another request to get the updated todo.
If your todo's aren't separate objects with id's they are propably a list of items and should be returned all at once.
I like to use the Google API AIPs for most of my api development.
https://google.aip.dev/134
Small excerpt from AIP 134 which is about updates and PATCH.
The response message must be the resource itself.
The response should include the fully-populated resource, and must include any fields that were sent and included in the update mask unless they are input only (see AIP-203).

REST: correct response status according RFC 2616 HTTP/1.1 spec?

I have skimmed over the HTTP/1.1 protocol spec at RFC-2616 and I am trying to understand which status code should be returned when a particular REST method is invoked. As far as I have studied the protocol (links), I tried to parse REST methods to the correct status code:
GET
to return 200 (ok) in case at least one resource is found.
should I return 204 (not found) if nothing is found (i.e. empty list is returned)?
PUT
to return 200 (ok) or 204 (not found) based if the resource is modified or not
moreover to return 501 (unimplemented) if the request is malformed or not understood.
POST
the same like PUT method with the difference the 201 (created) is returned if the new reource has been added to the orign
based on common recommendation, POST sould be used for creating a new reource, PUT for modifying an existing one. If I decide follow this recommendation, what should I return in case of attempt to modify an existing resource ex. POST api/v1/person/1?
PATCH
the same like PUT method with the difference it doesn't replace the whole resource like PUT does, but itmodifies a resource partially
there is no word about PATCH REST method in W3 protocol RFC-2616, should it be treated the same like PUT?
DELETE
to return 200 (ok) if the resource was deleted and [204 (not found)] in case there is no resource existing to remove (id not found). Does it copy the GET responses principe in case of REST implementation?
Is my "table" correct (especially the statements with the quotation marks ?? Is right that only GET should return the request itself in the body and the rest of methods just an URI link to an amended resource (new added, modified..) included in the header?
Is my understanding correct and does exist another source describing REST methods officially which is recommended (or are we "obligated") to follow? I am quite confused of wide range of sources giving me a bit different answers to each method as well of this really verbose RFC-2616 protocol.
The best would be the existence of a table describing briefly and clearly all these 5 methods with possibilites of status returned, body content and headers.
From RFC 7230
This HTTP/1.1 specification obsoletes RFC 2616
So any attempt to work out patterns for status codes should start from there
Is my "table" correct
Not really; take a look at Kropat's (unofficial) flow charts in Stop Making it Hard.

What status code should we return if the POST succeeds but does not result in creating anything new?

We have an endpoint which when you post create a new version of resource and returns a 201 and the location of the newly created resource. It determines the new version number based on a comparison of the current version and the version being posted (using a semver like ruleset).
If the version you post is identical to the existing version then no version number is updated. What should we return in this case?
We could just return a 201 even though we have not technically created anything.
I don't want to return a 409 as its not really a conflict, like when you post something with the same id. If you posted the same thing when the existing version was slightly different then you would happily get a 201.
We could just return a 200, but then that would seem weird, and increases the response codes that the users have to deal with
Does the idempotency of the 201 response matter?
Any better suggestions?
How about 303 - See Other? Seems to fit. I draw your attention to this sentence
from the spec at https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource.
That sounds like what you want to do to me. Here's the rest of it.
10.3.4 303 See Other
The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. The new URI is not a substitute reference for the originally requested resource. The 303 response MUST NOT be cached, but the response to the second (redirected) request might be cacheable.
The different URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).
Note: Many pre-HTTP/1.1 user agents do not understand the 303
status. When interoperability with such clients is a concern, the
302 status code may be used instead, since most user agents react
to a 302 response as described here for 303
I am a bit puzzled by the other answers as some get it almost right. So, let's clear up things a bit. If all requests are indeed performed with the POST method, in the context of ReSTfulness, they are supposed to modify state on the target server. Otherwise, the meaning of POST is a bit relaxed as you can see in RFC 7231, sec. 4.3.3.
Since the intent of the requests is to create a new version of a resource, they have failed if a version with the given presentation already exists. This would disqualify any 2xx-class response codes. From section 6.3:
The 2xx (Successful) class of status code indicates that the client's request was successfully received, understood, and accepted.
If you absolutely wanted to, you could go for 202/Accepted, which "is intentionally noncommittal." This is a bit of a stretch, though, as this status code is intended for queued processing. I would advise against it.
The 204/No Content code suggested by others is a bit of a poor choice. It were absolutely correct if you POSTed to the resource you were updating, though.
As the result is neither informational (1xx) nor a fault by the server (5xx). Let us have a look at the 3xx class first. From section 6.4:
The 3xx (Redirection) class of status code indicates that further action needs to be taken by the user agent in order to fulfill the request.
One of the most prominent one here would be 304/Not Modified. While sounding like a perfect fit, this code is unfortunately not applicable here. It can only be returned in response to conditional GET or HEAD requests.
302/Found may sound like the next best fit. However, this code is intended for temporary redirects, which is in all likelyhood not what you want.
As has been suggested here, 303/See Other is indeed a good choice:
The 303 (See Other) status code indicates that the server is redirecting the user agent to a different resource [...] which is intended to provide an indirect response to the original request.
[...]
This status code is applicable to any HTTP method. It is primarily used to allow the output of a POST action to redirect the user agent to a selected resource
All other 3xx codes are dealing with various forms of redirects that hardly relate to the situation here.
A final look, 4xx-class of status codes. From RFC 7231, sec. 6.5:
The 4xx (Client Error) class of status code indicates that the client seems to have erred. Except when responding to a HEAD request, the server SHOULD send a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition. These status codes are applicable to any request method.
Very few of these are actually deeling with the request body. Two of those who do would stand out here: One is 400/Bad Request, which is by design overly broad. It is - if you will - a catch-all solution. However, this would imply that the request body is malformed (as in syntactically incorrect) in some way, which is probably not the case.
More interesting is 409/Conflict. From the RFC (emphasis mine):
The 409 (Conflict) status code indicates that the request could not be completed due to a conflict with the current state of the target resource.
The wording of the definition places this code close to the PUT method, but is not exclusive. To reiterate the definition of the 4xx codes:
These status codes are applicable to any request method.
422/Unprocessable Entity is a contender, but it implies a semantic error, which really isn't the case here.
Ultimately (drumroll) the final piece of the puzzle could be found in section 4.3.3:
If the result of processing a POST would be equivalent to a representation of an existing resource, an origin server MAY redirect the user agent to that resource by sending a 303 (See Other) response with the existing resource's identifier in the Location field.
Note the "MAY." So you can really choose between 303 and 409. I feel 409 were the better fit, as clearly an earlier request introduced a state that is incompatible with the current one. OTOH, 303 may be the politer way to go and is closer to the standard. Either way, as a consumer of your API, I would really like to know if my requests failed. And be it by not having any effect whatsoever.
If nothing has been created by the operation, 201 is not suitable for that:
6.3.2. 201 Created
The 201 (Created) status code indicates that the request has been fulfilled and has resulted in one or more new resources being created. [...]
See below some options you could consider if the operation succeeds:
6.3.1. 200 OK
The 200 (OK) status code indicates that the request has succeeded. The payload sent in a 200 response depends on the request method. For the methods defined by this specification, the intended meaning of the payload can be summarized as:
[...]
POST: a representation of the status of, or results obtained from, the action;
[...]
Aside from responses to CONNECT, a 200 response always has a payload, though an origin server MAY generate a payload body of zero length. If no payload is desired, an origin server ought to send 204 (No Content) instead. [...]
6.3.5. 204 No Content
The 204 (No Content) status code indicates that the server has successfully fulfilled the request and that there is no additional content to send in the response payload body. [...]
If the operation fails:
6.5.1. 400 Bad Request
The 400 (Bad Request) status code indicates that the server cannot will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
11.2. 422 Unprocessable Entity
The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415 (Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.
A 201 Created should be used whenever you creating a new resource without doubt.
As defined in HTTP Method Definitions RFC, either200 Ok or 204 No Contentis an appropriate response if the operation does not create a new resource depending on the response body content.
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see section 14.30).
Now, coming back to your original question about what to use when the operation is successful and there is nothing to return, you should use 204 No Content. This status code is specifically meant for scenarios where the requested operation is successfully completed but there is no additional relevant information that the server can provide.
The 204 (No Content) status code indicates that the server has successfully fulfilled the request and that there is no additional content to send in the response payload body.
I don't think that for this case the idempotency is an issue, because the state of the system is not the same as it was in the inicial request, because the entity now exists, so you can respond with a different code.
200 should be fine, but it is a little weird as you said.
I have never use this, but I read that for some case you should redirect with a 302, to make a get for other resource, in this case I think this apply, return a 302 and make a get pointing for the old semver, assuming that you have a get endpoint for this entity.
If the POST'd resource has the same version number, but different data, then a 409 would be fitting. But if the data is the same as what's already stored, then a 409 might not be required. Through process of elimination I would say 200 OK would be fine.
We could just return a 200, but then that would seem weird, and increases the response codes that the users have to deal with
If this is a costly concern, consider eliminating the 201, not the 200. The fact of the matter is that for any decently complex service there may be at some point a situation where a 20X (where X is not 0) is applicable. So does that mean we code with each of the 20X responses in mind and spend time checking if our services has situations where 20X is preferred over 200? I suspect not. So unless there is a specific reason to respond with a 20X, for example to deal with a specific use case, then just use 200 and reduce the amount of coding and documenting required. I suspect for most scenarios, the calling client does not care.
Ultimately, the correct answer probably depends on whatever client is consuming your API. If you are building the client too, you could do whatever you prefer... (Just don't get too crazy.)
Assuming you are writing the API and client:
My opinion/suggestion is...
If there IS a new version number: The 201 HTTP status code would fit will.
If there is NOT a new version number: The 200 or 204 HTTP status code would fit well.
If there is no benefit to the client knowing the version number has changed or is the same: Send the 200 HTTP status code.
If you don't control the client consuming your API: Obviously defer to what they expect.
You may also wish review all of the HTTP Status Codes in the HTTP RFC spec. The above status codes also link directly to the relevant section.
201 : when new version is created
202 : when existing version is updated
204 : when request is accepted but no processing is done
by def, 204 = No Content
The server has fulfilled the request but does not need to return an
entity-body, and might want to return updated metainformation. The
response MAY include new or updated metainformation in the form of
entity-headers, which if present SHOULD be associated with the
requested variant.
If the client is a user agent, it SHOULD NOT change its document view
from that which caused the request to be sent. This response is
primarily intended to allow input for actions to take place without
causing a change to the user agent's active document view, although
any new or updated metainformation SHOULD be applied to the document
currently in the user agent's active view.
The 204 response MUST NOT include a message-body, and thus is always
terminated by the first empty line after the header fields.
So its slight tangential to your needs but I think its the best fit.

What should I do when there is no data to return from a REST endpoint?

I have the following endpoint, and its happy path is this:
GET /messages/next
Response:
{
"date_published": "...",
"message": "..."
}
Normally, the response is as produced above, however sometimes there just aren't any "next" messages. My question is, in the case where there are no "next" messages do I respond with an HTTP 204 (No Response) or should I simply return {}?
What's the best practice in this situation?
According to W3 :
10.2.5 204 No Content
The server has fulfilled the request but does not need to return an
entity-body, and might want to return updated metainformation.
I think in your situation, it would be appropriate to return a 204 Http response, unless for some reason, a JSON payload would make for a better design decision for your program (i.e. you would like to return something more than just metainformation since 204 does not allow for a message-body to be returned).
Also, take a look at this post: REST API error return good practices
204 is quite tricky. The RFC says
The server has fulfilled the request but does not need to return an entity-body"
So there must be a request to fulfill and there is no need to return anything. This is not the case here. For a GET request the server needs to return a representation of the resource if its there. So either the resource is no there or it returns it. It cannot say "The resource is boring. I won't return it. Guess how it looks like".
Lets have a look at the response codes which come into consideration:
200 OK: the resource logically exists and a representation is returned in the body
204 No Content: the request is fulfilled and there is nothing to return
404 Not Found: the requested resource does not exist
These are all similar but there are subtle differences as there are different kinds of "nothing" to return.
Maybe you have a resource like /messages and a GET returns obviously the list of messages. This list can be empty: [] (or for security reasons rather {"messages": []}). Returning an empty list is fine and results in a 200. A huge benefit of empty lists compared to empty results (corresponding to null) is that the client can often handle an empty list using the same piece of code as it handles a non-empty list. No additional logic is required which reduces complexity and the possibility for errors.
Maybe there is logically nothing to return. This typically occurs when you have a PUT, POST, DELETE, or PATCH action. In these cases you may return a body (the old/new entity) but you needn't. When you do not, return 204.
Maybe the resource is not empty but does not exist. In this case you should return 404.
As an analogy think of resources as files (resources don't need to be files but they can and that's quite common for static HTML which happens to be the origin of HTTP): 200 means the resource/file is there but may be empty. 204 means the service is not obliged to return a file. 404 means the server was requested to return a file but there is no file to return.
So in your example GET /messages/next should return 404 when there is no next message and return 200 if there is a next message but this message is empty. It should never return 204.
When using HATEOAS the resource /messages/next should only be linked iff there is a next message.
Alternatively you could have a resource /messages/newest and request it using a conditional GET request (e.g. using the If-Modified-Since header).
Also have a look at this nice overview.