I Shall Say This Only Once
CRUD is a rather well known backronym to describe the set of basic actions that is supported by virtually every persistence system, more specifically databases. Whilst the HTTP methods have a striking resemblance to the classic ‘CRUD’ operations, they do not map one to one! I personally think this comparison should never be made.
CRUD
Create
HTTP does not create resources.
That I shall repeat, the HTTP protocol says nothing at all about creating anything.
You think I’m crazy? Tell me then, how do you create a resource with HTTP? With POST, or maybe PUT, you say? Oh no no no, just think about what you said. “The act of POSTing a thing makes the thing come into existence.” Do you see the flaw in that thinking? You cannot create a resource with POST, for it must already exist for you to POST it. The client must make the resource, with POST all you are doing is asking the server to take care of this resource.
Oh yes, I am getting that pedantic. The resource is created entirely by the client, and then a representation is POSTed to the server. The server then stores a resource that was created by the client; you do want to validate it though. This pedantic view is not entirely without merit, it’s all part of trying to maintain separation of concerns. For those new to REST it can help with the ‘stateless mindset’ to think that the client should not rely on the server for creating resources; though of course, the server should never trust the client to get things right.
Read
Yeah, OK, this does map to GET rather well. The only clarification I feel never hurts to restate is that you are GETting a representation, not the data as it is stored. With an SQL SELECT the data you are pulling out is more or less exactly like it is in the DB. The representation that is sent back to you via HTTP could be transformed, or completely synthesised for this request. It can be very easy to overlook that you can GET anything, just so long as you do so responsibly.
Update
This is where my patience can be really tested. PUT does not modify, it replaces; it quite literally PUTs a brand new thing in a given location. Whatever data was originally at the URI is overwritten. Now, yes, you can try to leave it to the client manage this, and hope they can handle what is effectively transactions; the client has to GET the original version (which could be huge), make a change to one tiny part and finally PUT this new version back (sending that huge thing a second time). Oh sure, that can work, but please, PATCH it!
I touched on this in my last post, PATCH is a perfectly valid method to use. The only (honestly rather trivial) issue is to decide just how you want the information about the PATCHing to be represented.
I am well aware that this is controversial stance to take. PUT is so often used as the ‘modify’ method, that doesn’t make it right though. If you refer back to the original RFC that defined PUT, it states “If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server.” Now yes, I see how one could take this to mean that PUT is for updating a resource, but consider the following.
We GET /user/6
, from our system, and the following is returned:
Next, we want to update the location, so we PUT /user/6
the following:
If the server handles PUT as the specification says it should, the user will be confused when the GET /user/6
and find that the username and reputation are nowhere to be seen.
There are ways to handle this, but it doesn’t change the fact that the user asked to store this JSON object with one field at this location “as a modified version” of what was already there;
the user said “change the location, and remove the username and reputation field”.
If they wanted to modify the data that was at the given URI, leaving whatever was not mentioned as it was, they should of used an appropriate method, PATCH.
Delete
Yeah, this is just what HTTP DELETE is. Wish I could say more, but this at least really is that simple.
BREAD
Not only is it a marvelous substrate for some maple-cured ham, sharp extra mature cheddar, tangy onion pickle and crisp fresh lettuce, but it turns out to be a far superior acronym. Bread stands for “Browse, Read, Edit, Add, Delete”, and this can map to the HTTP methods much better.
- Browse -> GET
- Read -> GET
- Edit -> PATCH
- Add -> POST
- Delete -> Delete
Now, that set of words is from the Wiki page on CRUD, it was added back in 2012, but I can’t seem to find where it came from (this is why we use citations people!). Personally, I think this can be improved. Really, Browse and Read are the same thing, and map to the same HTTP method, and whilst PATCH is the method you should use for modifications, we have neglected PUT. As such, I’d propose the following:
BREAD | HTTP | CRUD |
---|---|---|
Browse | GET | Read |
Replace | PUT | |
Edit | PATCH | Update |
Add | POST | Create |
Delete | Delete | Delete |
Parting Crumbs
So yes, I think it’s worthy of a slap when someone starts talking about HTTP methods in comparison to CRUD. It’s worthy of a second one if that discussion is not about how CRUD is not really appropriate when talk about HTTP methods. The BREAD acronym is the way forward, as it better matches what you can do with HTTP and how. You might also start to realise I am quite the PATCH atavist, and anti-PUT.
Oh, and if you didn’t get the classic TV reference, ‘Allo ‘Allo.