zalando / restful-api-guidelines

A model set of guidelines for RESTful APIs and Events, created by Zalando
https://opensource.zalando.com/restful-api-guidelines/
Creative Commons Attribution 4.0 International
2.65k stars 390 forks source link

http 302 is missing in the list of [Success codes, Redirection codes, Client side error codes or Server side error codes] #655

Closed lflzrk closed 3 years ago

lflzrk commented 3 years ago

As per the use case, APIs are showing 302 Found when the try to create a resource which is already available and they give link to the available resource under the "Location" http header.

Zally Violations details:
The "should" tag has the following explanation "302 is not a well-understood response code".

The rule 150 say is Below we list the most commonly used and best understood HTTP status codes, consistent with their semantic in the RFCs. APIs should only use these to prevent misconceptions that arise from less commonly used HTTP status codes. They are saying that 302 response code can be misconceptions with 301 and 303.

Also RFC7231 says regarding 302 that the target resource resides temporarily under a different URI see more here: https://tools.ietf.org/html/rfc7231#section-6.4.3 .

why this is not included in their Guideline, this sounds strange ? https://github.com/zalando/restful-api-guidelines

ePaul commented 3 years ago

From the meeting:

We have some doubts whether it makes sense generally to add 3xx responses to an API definition – API clients should in general be able to follow them, whether or not they are declared. (@tkrop will elaborate on that.)

Nevertheless it seems sensible to add the other 3xx codes to the list in the guidelines, with some notes when to use them and when not.

tkrop commented 3 years ago

Hi @lflzrk, we have some doubts why it should make sense to complicate APIs by declaring 3xx responses. In general, you may need 301 to migrate resources to use a new service location, however, this is usually implemented more robust by switching the traffic to the new service location instead of redirecting the client on a resource level.

Also 303 usually does not make sense. In RESTful APIs you usually deliver a resource instead of redirecting a user to a different location, since your clients also care more about the resource content and not the location they are getting it from. The resource itslef should in general transport its location indirectly by carrying its resource identifiers inside as best practice.

The only use case that we see so far makes sense to document in an API is the GET/HEAD with conditional headers. Here you need 304 for signalling an unchanged resource to the consumer.

With respect to the 302 use case, I cannot see, why it should use a temporary redirect instead of a permanent redirect, i.e. 301. More over:

tkrop commented 3 years ago

Side note for API guild: There is no real reason not to document 302, however, I would also like to document the above considerations in the API guidelines to guide users to not use 301-303 to keep their APIs simple.

ddkserv commented 3 years ago

Hi @tkrop, You still have the "Post-Redirect-Get"/"PRG use case which has a resource that is idempotency. In this case if you do 2 POST commands with the exact same data then you do not want 2 item on the resource, that is not possible due to idempotency. Idempotency say you can only have 1 unique item on the resource, so what to do about the second POST call? For me at least it make sense that the response is 301 to say that the resource is created and found permanently somewhere else. So 301 does have value in the API specification.

tkrop commented 3 years ago

@ddkserv sorry, for the really late reply. Why should you send a 302 on a POST command?

It is much simpler to directly respond to the POST request with 201 with the Location-header for the first (creating) and 200 with the Location-header pointing to the same location transmitting the same content for the second (idempotent) request. Alternatively, you can also react with a 409 to expose a conflict on the second request.

ePaul commented 3 years ago

We thought of adding a section with status codes which are recommended not to use with explanations (which could also include the infamous 422), but this would bloat up the guidelines even more.

So I'm closing this for now.

ddkserv commented 3 years ago

Sorry for the late response. @ePaul And @tkrop

Let me put forward the example. You have a resource that can only be created if you have a unique input. And let us say that for simplicity it is e-mail.

I create an API to create entries on that resoure which is a POST.

So far so good.

I do my first Call to the POST with e-mail "123@123.com" and get a 201 created.

Another client does the same POST Call with e-mail "123@123.com"

What should The response be by the API?

End of problem statement.

I would say 301 and/or 302 make sense with location header telling where the unique resource is located.

Let me know what you Think.

BR /ddkserv

tfrauenstein commented 3 years ago

As discussed above, our recommendation: We prefer being robust against create repetition, i.e. 2nd identical create call has the same outcome (idempotent) as the 1st call but returns 200 instead of 201 success code. So the 2nd call client has the chance to recognize that the resource already exists and may react differently. In situations where robustness is not feasible and it is important that the client behaves differently, 2nd call should deliver 409 error code. Return code 302 ('found', previously 'moved temporarily') is not recommended here -- it is outdated, not related to resource location / addressing changes, and gives false indication that the client must take additional action to complete the create request. P.S: I think it is helpful to make this clearer in the guidelines.

ddkserv commented 3 years ago

Hi @tfrauenstein,

Thank you for your reply and making it more clear.

So the recommendation is to have either:

Or

Where it depend on how robust you want the API design?

Thanks.

BR /ddkserv

tfrauenstein commented 3 years ago

@ddkserv 1st call: 201 (incl. resource created) 2nd call: 200 (incl. resource found) or 409, if robustness is not feasible and it is important that client behaves differently (e.g. payment resource)

ddkserv commented 3 years ago

Hi @tfrauenstein thank you for making that crystal clear for me that POST should respond with 200 and 201 and include the location header. Make sense now.

I have one extra question for you to make me understand this in full.

Say we have the same scenario as above but let say all free e-mail services are blocked for creation as part for the API business logic. (Subject to frequent change so OAS rules is not an option) What should the responde be for the POST. 404 - Not found? 204 - No content? 409 - Conflict?

Thanks. /ddkserv

Thank you for your support so far.

tfrauenstein commented 3 years ago

@ddkserv If I understand you use case correctly, you defined a range constraint for the ids. Here, violations should be reported via client side error 400, i.e. input payload fails business logic validation.

ddkserv commented 3 years ago

Hi @tfrauenstein, thank you for the clarification. One thing that is puzzling me in your recommedation is the 400 response. The client did nothing wrong (Followed the spec to the letter) and the input is not malformed or an unsupported media type... so a bad request is a bit hard on the client... (if the business Logic is Update to allow the given e-mail then it would be accepted) so From my point of view is this business Logic is hidden for the client and the e-mail is rejected hence the 422 (unprocessable entity) would make more sense. Let me know what you think.

BR /ddkserv

ePaul commented 2 years ago

We decided (years ago) to not use 422, in favor of 400, because the definition of the exact line between both is not clear, and in general also not very useful for the client.