5 ms·
I generally use a pattern like: GET /api/resource POST /api/resource/action Where 'action' is something a bit more descriptive than 'PUT' or 'DELETE' or what
by bluepnume 11y ago
I generally use a pattern like:
GET /api/resource
POST /api/resource/action
Where 'action' is something a bit more descriptive than 'PUT' or 'DELETE' or whatever. Kind of like an object-oriented api... I'm still always dealing with resources, but I have custom actions for specific use cases.
- happyshadows 11y agoThis is my approach as well. Works very well with an event-sourcing model. It is much easier to capture user intent with POST /api/customer/1/change-address-due-to-move { "address_1": "...", "address_2": "...", ... } than with: PUT /api/customer/1 { "address_1": "...", "address_2": "...", ... } Also, GET /api/resource/action is nice place for a payload describing the expected inputs to the action. Link it all together with hypermedia and you really have something ;) Believe others are coming around to this line of thought: ThoughtWorks included "REST without PUT" onto their technology radar earlier this year.
- Zikes 11y agoHow about POST /api/customer/1/address {"address": "..."}
- deleted 11y ago[deleted]
- wise_young_man 11y agoPOST is used to create a resource. PUT is used to update an entire resource. PATCH is to partially update a resource.
- oldmanjay 11y agoSure, just so long as you realize that is a convention and not a law.
- hartror 11y agoIt isn't just a convention, the reasons for doing this are laid out in the HTTP 1.1 spec and assumed by servers, proxies, browsers, clients and developers. For example if I hand someone an API with a URI that accepts a PUT they know they can safely retry PUTs to that endpoint because the server state will always end up the same.
- oldmanjay 11y agothere is nothing in the specification of the PUT verb that indicates it is meant only for complete replacement of an existing resource. in fact, the RFC specifically has a section describing the semantics of creation using PUT. therefore, either your stance is trivially falsified, or you were replying to me out of context, which is intellectually dishonest. https://tools.ietf.org/html/rfc7231#section-4.3.4 https://tools.ietf.org/html/rfc7231#section-4.3.4
- hartror 11y ago> The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. So PUT either creates or replaces a resource. Definition of replaced: > 1. take the place of. Source: https://www.google.com.au/search?q=define%3A+replaced https://www.google.com.au/search?q=define%3A+replaced It is pretty clear to me that the spec says PUT completely replaces the state of a resource. So not just a convention but what the spec says. BUT lets take it further. Lets say you do allow partial updates with a PUT. Can you guarantee that your resource's state will always be internally consistent? Say you have two clients, both doing partial PUTs and do the following: Client 1: GET /foo Client 2: GET /foo Client 1: PUT /foo {'bar': 1} Client 2: PUT /foo {'baz': 2} Is the foo resource is a consistent state? For some applications it could be but for many it won't be. And worse for some applications it may not be idempotent and a client's proxy is going to silently retry a PUT that isn't safe to do so. So by allowing partial PUTs we're requiring the developer to consider all combinations a resource could be updated. They then need to communicate the valid combinations to any clients. OR they can split the resource up finer grained resources, each one representing a valid PUT.
- eyko 11y agoWhy not PATCH /api/customer/1 {"address_1": "...", "history": "moved", ...} (i.e. send your intent as a parameter that may not necessarily get saved in this resource)
- jameshart 11y agoBecause now your client needs to know what parts of the object need to be updated when a customer moves, and explain to the server exactly what those changes should be; and the server has to know how to validate that the client made a valid set of changes to the customer object. If you instead have the client tell the server what kind of change you want to make, and provide the parameters to the operation, the server can do everything that needs to be done and the client doesn't need to care.
- zzalpha 11y agoI tend to prefer path parameters for actions. Eg: POST /api/resource;action As that doesn't pollute the idea that the path itself leads to a resource.
- 3pt14159 11y agoWhy would you do this? It makes no sense. By (mostly) adhering to REST patterns you get so much stuff for free. Other developers can quickly get up to speed quickly. Client libraries are easier to write. Things like Ember Data work out of the box. I agree that every now and then doing a POST to /logout is easier than doing a DELETE /access_token/23, but a consistent API is far more worth it.
- leeoniya 11y agothe problem with HTTP REST verbs is that not everything can be (or should be) represented as a resource. a simple example is a one-click payment + order action. you're creating multiple records in different tables - payment gateway transaction log, payment table, an order table, probably creating a customer record, sending email notification, logging a conversion, etc. that sequence of actions does not adhere neatly to any HTTP verbs. it can be more clearly called "processorder" because it involves a lot more than creating an order record in a table. if you'd like, you can of course do POST /orders, but the nuance of what's happening is unnecessarily lost. another example is a taking that order and marking it as "shipped". it is not a simple PATCH /orders/123 shipped=true. the front-end does not know all the fields that must be set in all the places on the backend. it is in fact a series of actions that take some data from the front, and some from the back and do a bunch of things that represent the setShipped() sequence. HTTP verbs were designed for managing documents, for which they work well. They also happen to map well for direct db entries via CRUD. but trying to shoehorn them into all aspects of complex web apps is misguided. a true RPC is often what is necessary.
- pekk 11y ago"Buy this" might create multiple records in different tables, but there is no requirement that one URL in a REST API corresponds directly to one record or one table. The REST API does not have to expose the entire sequence of under-the-hood actions. This does not somehow require RPC to address.
- leeoniya 11y agohow would you differentiate a direct CRUD route with one that performs a lot of additional things? PATCH /orders/123 shipped=1 what does this do? does it simply set a field or does it trigger a shipOrder() sequence that also sets that field? what if you need the ability to do both (eg: admin interface & customer frontend)? I understand that in this case you can instead do something like: POST /shipments order=123 but not everything has a record backing it that would yield to this pattern. the response to a POST is supposed to be a Location header of the created record, so in fact you do need some form of URI and record for the created shipment. HTTP REST's multi-item and hierarchical item management are also very hacked-in and necessarily too chatty. You cannot return multiple Locations in a header, for example, when multiple records are created. Strict adherence to the purity of HTTP verbs and limits quickly degenerates into custom hackery above and beyond the RFCs for anything mildly complex.