2

When implementing GET on a resource is makes sense to respond with 404 if the resource cannot be found. For POST and PUT verbs it is a little more complicated.

To respond with 404 in that case I would need to do some kind of pre flight check. First do a SELECT in the database, check if there is a matching row, if not, respond with 404. But due to concurrent users there is no guarantee that the following UPDATE sql command will affect any rows.

Is it good practice to implement a pre flight check for resources in a REST API even if there is no guarantee that the request will be processed successfully anyway?

  • transactions are a thing – Ewan Feb 10 '20 at 14:21
  • But how does that help in this case? Can I expect the exception from a failed transaction to tell me whether it failed because of a concurrently deleted or modified row? 404 is only appropriate in the former. – Gabriel Smoljar Feb 10 '20 at 14:40
  • HTTPS error codes don't have to be precisely correct. They're already not a comprehensive list of things that can go wrong anyway. They're certainly not precise enough to tell you why a page was not found. – Robert Harvey Feb 10 '20 at 14:43
  • 2
    And what @Ewan is pointing out (more or less) is that the entire transaction succeeds or the entire transaction fails. Once again, the HTTP Response Code doesn't have anything to say about why. – Robert Harvey Feb 10 '20 at 14:46
  • "Can I expect the exception from a failed transaction to tell me whether it failed because of a concurrently deleted or modified row?" You might want to consider 409 Conflict if that's a concern. – JimmyJames Feb 10 '20 at 22:04

2 Answers2

5

I feel safe in saying that there is a large consensus amongst experts against using 404 to indicate that the object your API is looking for in its database was not found.

The main issue is that you will also get 404 when your webserver or client is misconfigured, or you simply mistype the domain.

The second is that you often don't want to throw an exception when a resource is not found, but html libraries will often throw exceptions on receipt of a 404 code.

However, If you want to use 404 for this purpose the implementation is simple enough even for an "attempted update against non existing resource".

  • Begin a transaction
  • Check for existence of the resource
  • If its not there, return 404 and roll back transaction
  • If it is there, continue with update and commit transaction

There is also the perhaps more optimal 'run sql and check number of rows affected' but the result is more open to interpretation.

Alternatives to 404 (note this part is only for those who want an explanation of the first sentence)

Basically it comes down to the design of your code. You want to avoid forcing the user to check whether the method they just called succeeded or not. This allows them to write clear, simple code.

So. Exceptions when you can't recover, but more importantly, methods designed never to throw exceptions.

So if I'm trying to load objects that might not exist, Help me out with a method which recognised that "that doesn't exist" is a valid result of the call, not an exceptional circumstance.

If I'm trying to update an Object, think about how the system should handle it being deleted while I've had it open. Maybe you can just create object that don't already exist, or maybe updating sets where the is no match is fine.

In code a get function might return a null, an update might return number of rows affected. These can be represented as "null" or 0 rather than an error code.

Ewan
  • 75,506
  • 5
    Can you provide sources for your claim that there is a large consensus amongst experts against using 404 for this situation? – Vincent Savard Feb 10 '20 at 16:21
  • well at least 5 people agree :) but if you search for similar questions and blogs you will see this question comes up frequently and the various pros and cons are discussed at length. – Ewan Feb 10 '20 at 16:24
  • 5
    I wouldn't take the upvotes as agreement as it is unrelated to the question and you do answer it quite well. That being said, my experience is actually the complete opposite of the "large consensus", both in my actual field of work and on most articles or blogs I have read. I also can't say your arguments convinced me, but I'm willing to stay open if you have any other sources that could enlighten me. – Vincent Savard Feb 10 '20 at 16:28
  • I've added a bit about alternatives to 404 which hopefully explains a bit more, but you are correct, there are a large number of people who think 404 is good too. You will have to research if you want to decide which side are the experts – Ewan Feb 10 '20 at 16:42
  • 4
    To add to the pedantry: technically a PUT should never return 404. In the absence of an existing resource, the correct behavior is to create a new resource and return 201. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT – Robert Harvey Feb 10 '20 at 16:57
  • I want to vote for the first half but not the second one – max630 Feb 10 '20 at 17:29
  • @RobertHarvey I think that in the context of the question, your point is exactly right but 'never'? What about trying to put to resource where the parent resource path does not exist? I don't think it makes sense to say you must accept a PUT to any arbitrary URI. – JimmyJames Feb 10 '20 at 18:04
  • 1
    @JimmyJames: If you want full control over exactly what happens, you can always use a POST. – Robert Harvey Feb 10 '20 at 18:05
  • @RobertHarvey That doesn't address the question. Are you saying that if a site/API supports PUT on any path, it must support PUT against any arbitrary path? – JimmyJames Feb 10 '20 at 18:08
  • @Jimmy: No, that's not what I'm saying. Arbitrary paths that don't resolve to any identifiable resource are 404's, just like the answer says. Just like your links illustrate. That's different than a valid path that leads to an empty resource (unknown identifier). – Robert Harvey Feb 10 '20 at 18:12
  • @RobertHarvey That's what I thought you meant and I agree as I noted in my first response. It's just that you wrote: "technically a PUT should never return 404" which, if taken literally could be misinterpreted. – JimmyJames Feb 10 '20 at 18:15
  • Naturally, if you try to PUT to some arbitrary, non-existent path, it's unlikely you're going to get any meaningful result. – Robert Harvey Feb 10 '20 at 18:17
  • @RobertHarvey But that's the interesting part, does a 404 make sense there? The parent resource does not exist and it's (apparently) a user error. And given that 404 is an allowable substitute for a 403 or 401, it would also seem valid for the scenario you are trying to create something on an existing resource when you don't have rights to do so. – JimmyJames Feb 10 '20 at 18:22
  • @JimmyJames: All good evidence that this level of pedantry wrt to HTTP Status Codes merely amounts to mental masturbation. – Robert Harvey Feb 10 '20 at 18:23
  • @RobertHarvey Eh, I'm not so sure. I think we'd have a lot less problems if people (and especially tool writers) would follow the flippin' spec. – JimmyJames Feb 10 '20 at 18:24
  • @RobertHarvey Returning 404 instead of 403 is spec or maybe I missed your point? – JimmyJames Feb 10 '20 at 18:29
  • omg. this is why you just use POST and 200/500. so you never have to have this discussion again – Ewan Feb 10 '20 at 21:31
  • @Ewan: I'm inclined to agree. There are many successful API's that just use GET and POST for everything. – Robert Harvey Feb 10 '20 at 21:39
  • Although... maybe not 500. More times than I can count, that's an uncaught exception due to bad error handling. Maybe with a stacktrace spilling out to the user. – Berin Loritsch Feb 10 '20 at 21:49
  • 1
    @Ewan "POST and 200/500. so you never have to have this discussion again" Right because that worked so well with the SOAP/WSDL debacle. 500 indicates a server error. When you return that, you are indicating you have bugs and/or misconfiguration on the server. – JimmyJames Feb 10 '20 at 22:02
  • ok 1. yes send the stack trace 2. web services were amazing. 3. once you write a client no-one cares what verb or code you used – Ewan Feb 10 '20 at 23:39
  • if you are trying to use an api you dont want it not to reply because you used the wrong verb. or have to look up what error code x means. you are trying to make it easy, not obscured by rarely used HTTP codes that kind of fit if you squint at them
  • – Ewan Feb 10 '20 at 23:46
  • 1
    @Ewan "1. yes send the stack trace" I'm sorry, are you saying this is a good idea? It's not. "2. web services were amazing." Yes it's 'amazing' is one word you could use to describe the need for an interoperability standard on top of your interoperability 'standard'. It's also 'amazing' when your 'standard' fails to meet any of it's goals. So basically, you can't be bothered to try to understand the design of the web so you just slop things together and call it a day. – JimmyJames Feb 11 '20 at 15:47
  • 1
    on the contrary, json and REST is 'slapping things together' proper SOAP with schema and various transmission protocols etc is doing it properly. here we are mucking around arguing about which code is most 'restful' when WCF can do reliable messaging, transactions, multiple protocols etc etc – Ewan Feb 11 '20 at 15:52
  • @Ewan FYI you can use SOAP with REST but why? You can also have a schema with JSON. And which 'various transmission protocols' are you talking about? Are you talking about doing SOAP over something other than misusing HTTP? That's interesting, if so. I didn't think anyone really took that idea seriously. – JimmyJames Feb 11 '20 at 18:18
  • microsoft took it seriously and still do. WCF is far more powerful than REST. REST is making things easy for people who want to use javascript to make their webpages pretty. Its the easy low featured option – Ewan Feb 11 '20 at 19:05
  • its crazy to argue about the details of a method which is basically "cramming stuff into the only thing we can do with javascript in a webbrowser". None of it has any technical merit, its all a compromise – Ewan Feb 11 '20 at 19:09
  • Right, that must be why MS kicked it to the curb. Because it is so great. Not because it's outdated bloatware. – JimmyJames Feb 11 '20 at 22:48