Ultimately, I think your question has roots in the common misuse of HTTP verbs.
It's common to equate a
PUT to an
UPDATE in an RDBMs but it's actually more like an 'UPSERT' (i.e. update or insert if not present).
So as pointed out by Robert Harvey in comments on another answer, at first glance, it doesn't make sense to return a 404 not found in the case that you understand what kind of resource is being updated (or it's parent). Consider the following URI:
So given the above it makes sense to return a 404 if you try to
PUT against a
parent that don't exist and if these are fixed, then that's likely what a decent framework will do. If
child doesn't exist, then we can create it. However, there are some caveats.
Allow me an aside: Suppose you do allow clients to create resources with
PUT as described above. But lets suppose multiple users get to create off of the same root/parent path. What should happen if one user tried to
PUT to a resource created by another (unaffiliated) user? There are two possibilities here: they have made an error such as trying to create an new resource or they are purposely trying to do something bad. In either case, you don't want to allow that so you can return a
403 (forbidden) error. But you are also allowed to return a
404 in the case that you don't want to give away info about whether that path exists. But if you only return a
201 when a path doesn't exist, you again leak information. This suggests that
404 could be used in this kind of scenario. It also brings into question whether such a scheme is a good idea. If you make a user/client identifier part of the path, you can avoid such accidental collision in the first place. I won't say it never makes sense to go about things this way but it does potentially make it harder to distinguish between error scenarios on the client.
But what if I don't want to let users create their own resources with
No problem: you don't have to. Just because the spec says
PUT can create or update doesn't mean you are forced to create any URI they send on a
PUT. It should be apparent that you can create rules around what URIs can be created with
PUT against a path and one valid rule is 'none'. Some error codes that might work for that are
422. And in the scenario above I made the argument that a
404 might also make sense. Personally, I would avoid
404 here and use a 'bad input' response to make it clear that you aren't allowing creation of resources with
There's also a bit of confusion around
POST. While it's somewhat aligned with the concept of an
INSERT, there's one aspect that I think a lot of people miss: the path in a
POST request doesn't refer to the resource being created. It's the path of the parent resource. That is when you
you are asking to create a new resource
and the identifier
child is created by the server (although nothing says you can't have the client specify that in the content of the request.)
So in the context of your question, it doesn't make sense to return a
404 when the child doesn't exist because you are asking the server to create it and it shouldn't be part of the URI anyway. However, if the parent resource doesn't exist, it makes perfect sense to return a
404 in that case as the URI would be asking to create a child of a non-existent resource.
To conclude, I would suggest avoiding the use of
POST to indicate the lack of a child entity under here because it a little confusing at best and potentially just plain wrong. It does make sense to use
404 to indicate that the parent path is non-existent or not accessible by the client.