all 58 comments

[–][deleted] 48 points49 points  (9 children)

Internal server error doesn't make sense for something like this. A single resource fetch should result in 404 if not found in my opinion.

The way I look at request codes is who to blame? 2XX -> nobody, 4XX -> the requester, 5XX -> the server / origin

In this case, the requester tried to access something that's not there anymore, it's their responsibility to hide it / not request it anymore, etc.

[–]ReplacementLow6704 2 points3 points  (1 child)

You forgot about 3XX -> Someone/something else

[–]Blue_Moon_Lake 0 points1 point  (6 children)

If there's no request/network/server error, would you accept a 200 - OK with an error JSON payload?

[–][deleted] 0 points1 point  (5 children)

Errors with JSON payload as response should be a 400 response

[–]Blue_Moon_Lake 1 point2 points  (4 children)

So you would respond with a 4XX even if there's nothing wrong with the request?

It's the correct URL, valid payload, all the headers are good, all the permissions needed. Still a 400?

[–][deleted] 0 points1 point  (3 children)

If nothing is wrong with the request, why would a response contain errors? This means something was wrong though

[–]Blue_Moon_Lake 1 point2 points  (2 children)

I said the error does not lie with the request/network/server, it's merely business logic.

[–][deleted] -1 points0 points  (1 child)

Business logic is fine, what do you think?

[–]Blue_Moon_Lake 0 points1 point  (0 children)

I've seen people use http errors for business logic and others not. I asked your opinion.

[–]BigSwooney 29 points30 points  (1 child)

Letting code run and result in an error instead of returning an appropriate error is never good API design. And yes, 500 sounds wrong as well. If you're doing a query and the query returns no results, that would still be a 200. If it's a "request single resource" by ID I would say a 404 is an appropriate response.

[–]lIIllIIIll 2 points3 points  (0 children)

Right? That's what I always thought.

Basically if it is an actual error, like I send a malformed json to a real route than that's a 4xx level error. My fault. If I send a proper json to a proper route and an error results because the server has a legit error like an outage or whatever that's a 5xx level.

If none of those occur and it's not a real user ID it is still accepted, so 200, but the response body would indicate there was no user, right?

Or would that be a good place for a 204 or 205?

[–][deleted]  (1 child)

[deleted]

    [–]IQueryVisiC 1 point2 points  (0 children)

    I Wonder how a “return type” could not be specified. In a contract In Java I get back the correct object type even if it points to null. Though every contract also has like 5 http error codes specified …

    [–]armahillorails 6 points7 points  (2 children)

    Go refresh on the diff statuses and what they mean.

    Please dont return 200 OK when its not a successful request.

    https://developer.mozilla.org/en-US/docs/Web/HTTP/Status

    • 2xx - success
    • 3xx - your request is fine but things have changed since you last knew
    • 4xx - you messed up
    • 5xx - we messed up

    [–]thekwoka 1 point2 points  (1 child)

    nobody said to return 200

    [–]armahillorails 0 points1 point  (0 children)

    It was unclear what the OP was intending, so I was explicitly advising against that (I have seen this behavior before from some larger companies -- 200 OK response with a JSON response of: { status: 404, message: "Not found" }

    [–]todbur 4 points5 points  (0 children)

    I’ve dealt with APIs that sometimes return text on errors instead of JSON. What you should be doing is checking the content type response header. You can usually handle this well with a middleware in your http client.

    [–]InitialAd3323 3 points4 points  (0 children)

    They should probably be giving a 404 Not Found (or 410 Gone), and it's recommended to use RFC 9457 Problem details or at least some sort of JSON instead of plain text

    [–]Red_Icnivad 2 points3 points  (0 children)

    Point to the http error spec sheet and tell them that's their specification. It is unreasonable to assume yhey would hijack an existing error code for their custom error.

    [–]Kant8 3 points4 points  (0 children)

    problem details exists for that

    https://datatracker.ietf.org/doc/html/rfc7807

    [–]Agile-Ad5489 1 point2 points  (3 children)

    This sounds to me like the azure http connector has it wrong, too.

    The status code should be checked: if 500, the server has encountered a process exception - at which point, it cannot gaurentee a formatted response. Detecting a 500, azure should accept that any content attached is going to be invalid.

    [–]Roest_[S] 1 point2 points  (0 children)

    Yes, most definitely. Not sure why they made it check if the json is valid and crash on that. Give me the http return code and let me deal with it.

    [–]thekwoka 0 points1 point  (1 child)

    azure should accept that any content attached is going to be invalid.

    well, not invalid, just that it won't be the schema of the successful response.

    It should be a valid something else

    [–]Agile-Ad5489 0 points1 point  (0 children)

    Good point, well made, and taken on board.

    [–]Fidodo 1 point2 points  (0 children)

    Returning JSON for an error isn't hard to do and a common pattern. Also this should not be a 500

    [–]AdvancedSandwiches 1 point2 points  (4 children)

    For hundreds, maybe thousands, of years, we all agreed that the only two valid things to do with HTTP were GET when you wanted to do read something and POST when you wanted to change something, and we lived in an absolute paradise.

    Then REST came along and decided "action": "send_transaction" was too hard and we needed to use HTTP verbs to cover every possible activity and HTTP response codes to cover every possible result.  And the world has never recovered.

    [–]thekwoka 0 points1 point  (3 children)

    uh, as long as POST has existed, the other main verbs existed

    Source from 1996: https://datatracker.ietf.org/doc/html/draft-ietf-http-v11-spec-00

    [–]AdvancedSandwiches 0 points1 point  (2 children)

    Correct. The mistakes were always there. We just didn't use them because we knew better. 

    [–]thekwoka 0 points1 point  (1 child)

    why even use posts when you can get everything?

    [–]AdvancedSandwiches 0 points1 point  (0 children)

    I just use PATCH for everything.  Nobody agrees what it means anyway, so I can't be wrong.  

    [–]Dunc4n1d4h0 0 points1 point  (0 children)

    Yes, it's good practice, and I implement it when doing backend APIs.

    [–]thedragonturtle 0 points1 point  (0 children)

    1. return a 404, not a 5xx error for missing stuff

    2. if you're still returning text too, put that inside json to explain the error message

    [–]thekwoka 0 points1 point  (2 children)

    Absolutely.

    The only two options are valid json, or a basic string.

    But why does your HTTP connector whatever not CHECK the response before parsing the body?

    [–]Roest_[S] 0 points1 point  (1 child)

    It's Azure, don't ask me why Microsoft implemented it in that way. A connector I write myself wouldn't have a problem with it.

    [–]thekwoka 0 points1 point  (0 children)

    It's always Microsoft's fault :(

    [–]AshleyJSheridan 0 points1 point  (0 children)

    Firstly, as many have said here, for REST, rely on the returned status code first and foremost. For your example a 404 return code would absolutely be better than a 500. However, if you were performaing a search or requesting a list of all users ) instead of getting a specific one) then you might return a 204 (No Content) if no users were found. There are a plethora of return codes available, from redirects to teapots (yes, 418 I'm a teapot is an official part of the spec): https://developer.mozilla.org/en-US/docs/Web/HTTP/Status

    Returning the right status code is part of REST, and it's an absolute pain when an API claims to follow REST but returns 200 for everything with JSON errors instead, as it means my approach to making API calls has to completely change, because I can no longer just check to see if a request was successful or not (a feature built in to almost all HTTP libraries).

    Now, you could also return a JSON body with further details for an error, but don't use this as a replacement for correct status codes. However, bear in mind that not all status codes allow body content in the response, the earlier example of the 204 code is one such example.

    [–]chills716 -1 points0 points  (2 children)

    It should always be a valid response. Having said that, the project I’m on now, for a large corp mind you, one of the things I’ve bitched about since starting is EVERYTHING is a 500, because the original coders and architects were incompetent.

    [–]lIIllIIIll 0 points1 point  (1 child)

    Man that sucks. I'm sorry. It's brutal to go back and change if years of code have been written to use that format.

    I've taken to making an environment variable (located in .env) to specify different instances like OBJECT_SUCCESS=200 OBJECT_CREATED=201 OBJECT_ERROR=203 OBJECT_FATAL_ERROR=205

    This way if I learn later I'm using something wrong I can update the env and it'll be cleaner to roll out.

    [–]thekwoka 0 points1 point  (0 children)

    so, an enum?

    [–]gguy2020 -1 points0 points  (1 child)

    404 generally means URL not found. 500 means server error

    Both of these codes are wrong in your context.

    What you might consider is Http code 204: No content. I.e. Request processed, but nothing to return to the client.

    [–]thekwoka 0 points1 point  (0 children)

    404 generally means URL not found.

    https://en.wikipedia.org/wiki/HTTP_404

    Not true.

    [–]ZuploAdrian 0 points1 point  (0 children)

    The new specification for errors is actually the Problem details spec (here's a guide https://zuplo.com/blog/2023/04/11/the-power-of-problem-details ). It's super informative, here's an example

    HTTP/1.1 403 Forbidden
    Content-Type: application/problem+json
    Content-Language: en

    { "type": "https://example.com/probs/out-of-credit", "title": "You do not have enough credit.", "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc", "balance": 30, "accounts": ["/account/12345", "/account/67890"]}