A) When the content of a shopping cart is purchased the cart is copied to a fixed order and the cart is deleted.
B) If a placed order will be changed a shopping cart is created that allows for editing of the order. (Cancellations may result in cancellation fees). When the changes are accepted the changes are transferred from the cart to the order. The cart will be deleted again.
I'm struggling to model those state changes in a RESTful API using resources? How would I express the changes of the resources? Purchasing the cart content deltes the cart and creates a new one. Here are some ideas...
a) Creating the order:
POST Orders?cart=cartId
or
PATCH Cart/:id {status: purchased}
(the response would hold the link to Orders/:newid)
b) Saving the updated cart of an existing order:
PUT Orders/:id?cart=cartId
or
PATCH Cart/:id {status: changeConfirmed}
or
PUT Orders/:id/:cartID
Heuristic: think about how you would do it on the web.
You are looking at a web page that describes the contents of your shopping cart. On that same page is a "Place Order" form. When you submit that form, the browser sends an HTTP POST request to your web server, targeting whichever resource was described by the form's action metadata. This triggers some business activity behind your HTTP facade, manipulating the shopping cart and order entities in your domain model.
You are looking at a web page that describes your order. On that same page is an "Edit Order" form. When you submit that form, the browser sends an HTTP POST request to your web server, targeting whichever resource was described by the forms action metadata. This triggers some business activity behind your HTTP facade, manipulating the shopping card and order entities in your domain model.
That's REST.
The request targets can be anything you want; but the general purpose transfer of documents over a network uses request targets for caching, and cache invalidation. That means if you choose your request targets cleverly, you can ensure that successful requests invalidate stale copies of resources.
For your first example, the obvious resource that would be changed by the Place Order request is the shopping cart resource itself, so that's a reasonable first guess at what the form action should be.
In the second example, the order resource is a reasonable first guess.
Does it have to be POST? No - you can use PUT instead with similar effect; the client sends edited copies of the resources back to the server (PUT) and then the server triggers the business activities.
(PATCH is an alternative to PUT, where instead of sending the entire document, we send a description of the edits in a form that the server has advertised that it understands; for resources with JSON representations, we'd normally use something like JSON Patch or JSON Merge Patch).
Creating the order
PATCH /Cart/12345 HTTP/2
Content-Type: application/merge-patch+json
{ "status": "purchased" }
Saving the updated cart of an existing order
PATCH /Cart/12345 HTTP/2
Content-Type: application/merge-patch+json
{"status": "changeConfirmed" }
Both perfectly reasonable. PUT - including an entire copy of the /Cart/12345 representation with the changes - might be a better answer if that document isn't too big (compared to the HTTP headers): requests with idempotent semantics can be retried if an HTTP response is lost on an unreliable network.
Note that the HTTP method and request target can be the same even though the intent is to trigger two different business activities. That's perfectly normal in REST (but not necessarily common - your server's HTTP routing framework probably won't be able to discriminate between the two cases, so you'll have to write some bespoke code to trigger the correct activities).
Related
In my current API design I'm following these rules:
PATCH is used to partially update a resource
POST is used to create resources
PUT isn't used at all
I need to expose specific update actions (not exposed as PATCH, for security reasons), i.e. change the status of an order to "confirmed", "partially confirmed" or "refused".
I'm struggling on:
POST /carts/:id/:status and DELETE /carts/:id/:status: seems wrong as POST should create resources
PATCH /carts/:id/:status: seems wrong because the payload would be empty
Which one would be the most consistent and appropriate with the above API design? Do I have other options?
It may help to review Webber 2011
You have to learn to use HTTP to trigger business activity as a side effect of moving documents around the network.
I need to expose specific update actions (not exposed as PATCH, for security reasons), i.e. change the status of an order to "confirmed", "partially confirmed" or "refused".
How would you do this on the Web?
The most common answer would look something like this: you would have a web page for "the order"; and that page would include hyperlinks to some forms - it might be a simple "change order status form", or you might have different forms for each change. When we submit the form, the browser would create from form data and metadata an HTTP POST request, targeting whatever resource was specified by the form.
Important takeaways
It is okay to use POST.
The server can choose whatever URI it likes as the form target.
One convenient choice would be to use the URI for "the order" web page, because that allows you to take advantage of the general purpose cache invalidation defined by the HTTP standard.
You can, of course, use PUT or PATCH semantics instead, if you like. The primary difference is that these methods use remote authoring semantics - they are the HTTP methods we would use if we were trying to edit a web page.
To change the status of an order, it might go roughly like this: you would GET the current web page, and edit your local copy to change the status information. Then you would use HTTP to save your copy of the web page on the server:
For PUT, the payload of the request would be the entire web page with your edits.
For PATCH, the payload of the request would be a patch document describing just your edits.
The server would then need to either accept your request (applying your changes to its copy of the web page) or reject them (for example, if those changes are not consistent with business policy).
Which one would be the most consistent and appropriate with the above API design? Do I have other options?
You'll probably have an easier time if you relax the restriction that POST is only used to create resources.
Remember, the world wide web is the reference implementation of the REST architectural style, and it was catastrophically successful. Yet PUT and PATCH were used only rarely -- almost all information was carried to web servers using POST semantics.
But if must limit yourself to these rules for non technical reasons, then you might consider a resource model where information is sent to the business by creating new resources on the web server. In other words, instead of changing the status of the order by editing the order web page, you could instead create a new "change the status of the order" document on the server.
(Technically, you could use any of POST/PUT/PATCH to create the new document, but POST is normal and consistent with your constraints, so it seems a reasonable starting point).
I have a REST API which serves data from the database to the frontend React app and to Android app.
The API have multiple common endpoints for each model:
- GET /model/<id> to retrieve a single object
- POST /model to create
- PATCH /model/<id> to update a single model
- GET /model to list objects
- DELETE /model/<id> to delete an object
Currently I'm developing an Android app and I find such scheme to make me do many extra requests to the API. For example, each Order object has a user_creator entry. So, if I want to delete all the orders created by specified user I need to
1) List all users GET /user
2) Select the one I need
3) List all orders he created GET /order?user=user_id
4) Select the order I want to delete
5) Delete the order DELETE /order/<id>
I'm wondering whether this will be okay to add several endpoints like GET /order/delete?user=user_id. By doing this I can get rid of action 4 and 5. And all the filtering will be done at the backend. However it seems to me as a bad architecture solution because all the APIs I've used before don't have such methods and all the filtering, sorting and other "beautifying" stuff is usually at the API user side, not the backend.
In your answer please offer a solution that is the best in your opinion for this problem and explain your point of view at least in brief, so I can learn from it
Taking your problem is in isolation:
You have an Order collection and a User collection
User 1..* Orders
You want to delete all orders for a given user ID
I would use the following URI:
// delete all orders for a given user
POST /users/:id/orders/delete
Naturally, this shows the relationship between Users & Orders and is self-explanatory that you are only dealing with orders associated with a particular user. Also, given the operation will result in side-effects on the server then you should POST rather than GET (reading a resource should never change the server). The same logic could be used to create an endpoint for pulling only user orders e.g.
// get all orders for a given user
GET /users/:id/orders
The application domain of HTTP is the transfer of documents over a network. Your "REST API" is a facade that acts like a document store, and performs useful work as a side effect of transferring documents. See Jim Webber (2011).
So the basic idioms are that we post a document, or we send a bunch of edits to an existing document, and the server interprets those changes and does something useful.
So a simple protocol, based on the existing remote authoring semantics, might look like
GET /orders?user=user_id
Make local edits to the representation of that list provided by the server
PUT /orders?user=user_id
The semantics of how to do that are something that needs to be understood by both ends of the exchange. Maybe you remove unwanted items from the list? Maybe there is a status entry for each record in the list, and you change the status from active to expired.
On the web, instead of remote authoring semantics we tend to instead use form submissions. You get a blank form from somewhere, you fill it out yourself, you post it to the indicated inbox, and the person responsible for processing that inbox does the work.
So we load a blank form into our browser, and we make our changes to it, and then we post it to the resource listed in the form.
GET /the-blank-form?user=user_id
Make changes in the form...
POST ????
What should the target-uri be? The web browser doesn't care; it is just going to submit the form to whatever target is specified by the representation it received. One answer might be to send it right back where we got it:
POST /the-blank-form?user=user_id
And that works fine (as long as you manage the metadata correctly). Another possibility is to instead send the changes to the resource you expect to reflect those changes:
POST /orders?user=user_id
and it turns out that works fine too. HTTP has interesting cache invalidation semantics built into the specification, so we can make sure the client's stale copy or the orders collection resource is invalidated by using that same resource as the target of the POST call.
Currently my API satisfies the table from the bottom of the REST, so, any extra endpoint will break it. Will it be fatal or not, that's the question.
No, it will be fine -- just add/extend a POST handler on the appropriate resource to handle the new semantics.
Longer answer: the table in wikipedia is a good representation of common practices; but common practices aren't quite on the mark. Part of the problem is that REST includes a uniform interface. Among other things, that means that all resources understand the same message semantics. The notion of "collection resources" vs "member resources" doesn't exist in REST -- the semantics are the same for both.
Another way of saying this is that a general-purpose component never knows if the resource it is talking to is a collection or a member. All unsafe methods (POST/PUT/PATCH/DELETE/etc) imply invalidation of the representations of the target-uri.
Now POST, as it happens, means "do something that hasn't been standardized" -- see Fielding 2009. It's the method that has the fewest semantic constraints.
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. -- RFC 7231
It's perfectly fine for a POST handler to branch based on the contents of the request payload; if you see X, create something, if you see Y delete something else. It's analogous to having two different web forms, with different semantics, that submit to the same target resource.
The frontend/client shows a list of items. Make a request to the backend/ API to change some items. For example, add an item or delete one. How to reflect these changes on the client side after the backend has processed this request successfully?
Examples:
POST request to the backend that adds a new item to the list. The response body contains the added item. Http Status Code 201 CREATED
DELETE request to the backend that removed an item from the list. The response body contains nothing. Http Status Code 204 NO CONTENT
Solutions?
After the request has been processed successfully (client receives 2xx status code) the complete list is going to be fetched again from the backend. Downside: This means we have two requests. First the POST, then a GET.
Return the complete list in the response body of the POST request. This seems strange, because how the client consumes the API affects the behavior of the API.
The client handles the addition or removal of the item itself after it has received a 2xx from the backend. Pro: Only one request. Downside: Problematic if multiple users operate on the data. How to keep everything in sync?
Is there a common pattern of how to handle this in regards to clean API design? I noticed, that a lot of tools make only one request if you change data. Think of Trello or something similar.
How to keep everything in sync?
In REST, you don't. Each client (potentially) has their own local cache. The server includes standardized caching metadata in its responses, to provide the clients with a hint of how often the information may change.
Cache invalidation is standardized, but only the caches that an HTTP request passes through are going to see the triggering requests. So unless your clients are sharing a cache (not likely in the world of HTTPS), somebody is going to have stale data.
The server still has the authoritative copy, of course, and we have standardized conditional requests that give us options when the clients data is too stale.
How to reflect these changes on the client side after the backend has processed this request successfully?
There is a section of the HTTP specification that describes how to identify the representation in an HTTP message. It includes this passage
If the response has a Content-Location header field and its field-value is a reference to the same URI as the effective request URI, the payload is a representation of the resource identified by the effective request URI.
So POST /foo PUT /foo PATCH /foo have a standardized way of announcing that the representation enclosed in the response is a new representation of /foo
There isn't, as far as I can see, any standardized way to communicate side effects; which is to say changes to other resources. We have to fall back on cache invalidation semantics.
For the most part, REST is a bunch of machines pretending to be web browsers talking to a machine that pretends to be a web server.
The REST interface is designed to be efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an interface that is not optimal for other forms of architectural interaction. -- Fielding, 2000
I am creating a RESTful API where “entries” can be added, modified, and deleted. Each entry is automatically assigned an expiration date when it’s created and is automatically deleted unless renewed before that date. When an entry is renewed, it is simply given a later expiration date (by the server, the user cannot choose the expiration date).
My question is, what would be the RESTful way to expose the “renew” functionality?
A few possibilities that I thought of (though none of them really seem right):
DELETE /api/entries/:id/expiration-date
PATCH /api/entries/:id with "expirationDate": null in the (JSON) body
PATCH /api/entries/:id with any or no body
PUT /api/entries/:id (Essentially require the entry to be resubmitted)
Note: Currently the only intended consumers of the API will be my own client applications, but I may choose to make it public in the future.
I would use
PUT /api/entries/id/renew
with the expiration date in the body (or with no expiry to use the default). Reason being that the expiry isn't really pertaining to the object itself; it's metadata associated with how the object is managed by your system.
My question is, what would be the RESTful way to expose the “renew” functionality?
How would you do provide this functionality on a website?
You would presumably start by looking at the web page of the entry, via a GET request, that would load the current representation of the page into your local cache.ou
When the server judged that the entry was eligible for renewal, the web page would include some sort of hypermedia affordance for allowing the client to trigger the renew protocol. In this case, you probably don't want that affordance to have safe semantics, so it would be a form using the POST method. When the user submitted the form, the browser would create an HTTP request with the correct meta data and form data copied into the request body as described by the HTML processing rules; the request would be submitted to the URL specified in the form.action by the server.
Does the spelling of the URL matter to the user? Not really, the user just submits the form, the URL is just opaque data. Indirectly, it matters because of the way that cache invalidation semantics are defined -- if we intend that renewing should evict previously cached representations of the web page, then the post request should have the URL of the page itself.
Similarly, the web form doesn't need to be on the page - you could have a link to a form managed elsewhere, using different caching rules.
Do that, in a machine readable way, and you have yourself a REST API.
PUT and PATCH work the same basic way, except that request body is a description of the page itself. Download the HTML, make edits, then either PUT the new document in its entirety or compute a patch document and send that instead.
PUT and PATCH work really well for anemic domains - like document stores; it's more challenging to work with representations directly when you need to reverse engineer the change in order to work out the intent.
Can a shopping cart be implemented using REST architecture constraints?
I would like to focus my question with respect to session state. In a typical MVC application implementing a shopping cart, it most likely, session object will be managed in session, shopping cart as a list of products.
How would this same shopping cart be managed in if the application had followed REST architecture. One of the REST constraints is state management is responsibility of clients.
Should a shopping cart and it's progress be managed by client? Any examples? Any disadvantages of managing state in client with respect to a simple shopping cart or any other enterprise applications?
There is nothing wrong with storing the shopping cart as a resource on the server. It is session state that should be stored on the client. https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_3
In order to be stateless, your shopping-cart URI should be able to identify a unique cart without needing to rely on any session information.
For example, /shopping-cart is probably not sufficient unless there will only ever be one shopping cart throughout your application.
Likely, there will be at least one cart per user. So, you could use something like /user/1234/shopping-cart or /shopping-cart?userID=1234.
Even more likely, you will probably need to have multiple shopping-carts per user. So, you will want to give your carts a unique ID like /user/1234/shopping-cart/5678 or just /shopping-cart/5678.
The point is, everything needed to process the request should be in the request.
In REST applications, the session state is entirely managed by the client and the request must contain all the necessary information to be understood by the server. If the server requires authentication, for example, each request must contain the credentials.
The REST stateless constraint is defined as the following:
5.1.3 Stateless
[...] each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. [...]
However, the stateless constraint doesn't mean the server shouldn't store any data.
In applications which the session state is managed by the server, it's a common approach storing the shopping cart data in the HTTP session. But a shopping cart is not a session state. And, probably, it should not be entirely managed by the client.
In REST, a shopping cart, can be a resource identified by a URL such as /shopping-cart and operations can be performed over it. All the shopping cart data can be persisted to a database on the server.
Any information that can be named can be a REST resource, even a shopping cart:
5.2.1.1 Resources and Resource Identifiers
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time. [...]
You can perform operations like these on your shopping cart:
GET /shopping-cart: Get the shopping cart.
POST /shopping-cart: Add an item to the shopping cart (sending some data with the item you are adding and the amount in the request body).
DELETE /shopping-cart/1: Remove an item with id 1 from the shopping cart.
PATCH /shopping-cart: Update the shopping cart (sending some data to be updated in the request body).
PUT /shopping-cart: Replace the whole content of the shopping cart (sending some data with the content of your shopping cart in the request body).
DELETE /shopping-cart: Remove the shopping cart
POST /shopping-cart/order: Order the shopping cart content
So, observe the client won't store any information about the shopping cart at any time. All the information related to the shopping cart will be stored in the server.
For more information about REST, I do recommend reading the chapter 5 of Roy T. Fielding's dissertation.
A lot of confusion about REST exists because lots of people hear about REST constraints and think they are rules that are applied for no reason other than following the architecture as an end in itself.
The real question you should be asking is why the stateless constraint exists in REST, and what advantages do you get from following it. Keep in mind that REST is an architectural style intended for long-term evolution of large-scale distributed systems. You simply won't have the problems REST is supposed to solve in a small-scale application where a single database holds all your information.
The stateless constraint induces the property of visibility,
reliability and scalability. Visibility is improved
because a monitoring system does not have to look beyond a single
request datum in order to determine the full nature of the request.
Reliability is improved because it eases the task of recovering from
partial failures. Scalability is improved because not having to
store state between requests allows the server component to quickly
free resources, and further simplifies implementation because the
server doesn't have to manage resource usage across requests.
So, being stateless means the client request should have all the information required to process it.
How important is visibility for you? Do you want to be able to see the whole contents of the shopping cart from the client request when you are debugging something, or are you ok with having to get that information from the databases?
How important is reliability? Do you have a large distributed system with several servers and databases, where that matters? If you have a large distributed system where the shopping cart information might be stored in different databases depending on the exact HTTP server that responded the request, if a server fails only another server from that group will be able to fulfill the request and finish the session, or a server from another group will force the client to restart the session. If all the information is contained in the request, then any server can do it.
How important is scalability? If you have a distributed system and you're storing shopping cart information on a single database, it becomes a funnel for all your requests and you lose scalability. If you store it on several databases, you lose reliability as explained above.
So, do you have ambitious long-term goals or is your application going to be large enough that you'll face the problems REST attempts to solve? If you'll always have a few servers and a single database, and you'll use it for every single request, then it doesn't matter if you go stateless or not. You can just have a /shopping_cart resource or something like that, add stuff to it with POST requests, and close or delete it when you're done.
If you'll have your data sharded across multiple databases, lots of HTTP servers responding requests, cache servers, etc, and you want to have the ability to provision capacity dynamically by setting up new servers as they're needed and removing them when load is reduced, then go full stateless and leave the shopping cart with the client.
I think somebody chose very unfortunate name for STATELESS concept and that's why the whole misunderstanding is caused. It's not about storing any kind of resources, but rather about the relationship between the client and the server.
Client: I'm sending you the "task list", which needs to be processed. Do your job.
Server: All right.. let me take the responsibility of processing the data that is important for you, in order to give you the proper response.
Meaning, the server is the "slave" of the client and has to forget about his "master" after each request.
Yes you can,
Shopping cart data (added products) can be saved on the clients session, that ain't a problem.
Then once the user hits /checkout, the shopping cart should be persisted on the DB on the server. The key about rest is that every petition the client makes has to contain all data to identify himself, I suggest reading something about JWT or OAuth.
The app itself would work as any other shopping cart app you have seen, most of them do not persist the shopping cart in DB, just store it the clients session.
I think that is where SPA(Single page applications) come into use since the SPA are loaded at once and after that the variables maintain the state and between components you can pass them if the components are hierarchical or otherwise as well you can use stores(like Redux) to maintain state.
However I feel ideally in real scenario you would want to persist the shopping cart for users for following scenarios:
1)User adds items to shopping cart but does not order.Later, maybe next day he wants to continue from where he left.So it should be persisted
2)User is logged on from multiple devices, say multiple family members using the same account. Here as well the cart should be in sync.