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.
Related
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).
Assuming a resource X(http://example.com/a/foo/7) from rest-service A needs to hold a reference to a second resource Y(http://example.com/b/bar/1) from rest-service B.
How would one persist the reference?
Currently I'm storing the whole URI (as a string) of Y in the persistence layer of service A. Is this a common/valid approach?
It seems wrong to me to extract the id(1) out of Y's URI as I would implement assumptions about the URI structure of service B in service A. Is this correct?
How do you solve this problem?
Thx!
Lets discuss it with some actual business domain , then the answers will make sense.
So first example:
X represents Order Entity in Amazon Order Service, Y represent Customer in Customer Service.
Now while fetching the order from Amazon from Order Service, you also want to show some basic customer detail and link to customer Object to go to Customer Detail Page.
In this case what I would do is while creating the order copy some basic attributes of the customer in Order Entity (customerName , customerArea).
Also store customerId, customerType. And as the API for fetching customer is Public and also exposed to various internal services, Order Service will do a Service discovery and create URL and call. In these cases generally customer service will not stop supporting the old way (even if they are building a new one).
So storing just the id is a solution.
CASE 2:
Amazon Order Entity wants to store delivery details and delivery partner is some third party entity like DHL , then if DHL provides a URL to fetch the delivery updates to the order, in those cases I will just store the URL.
Generally I will prefer to store id and service type and some basic details to create a good customer experience and also avoid hitting one extra service api for getting the basic detail like customer name.
Storing direct URL makes sense when its a third party URL.
Also if you can give certain example of your business case like this, we can discuss better
IMO references should be stored as is. How you get the actual data from reference should not be part of the data but the logic which may change from time to time.
I will store them as reference of external reference (just to paint the picture that reference is out side our service) and coupled it with a logic to query the data.
URL is very volatile and may change. As a rule of thumb you should never keep urls in you database and should rely on service discovery to identify where the service is even if its within you own infra.
Its not an assumption, its a contract, which may changes and if it does, your service will be dependent service and has to make due changes
Also by your logic, even if you keep url, response to it is still a contract that both of you adhere to.
I'm using the MEAN stack on my site, where users can add events with player information (2-4/event) to the cart. Sometimes they purchase multiple events. I'd like this information to be safe from user manipulation (changing info before checking out if they use console) and able to be stored for a short time in case they are interrupted during checkout.
Would I be able to add their cart items to their JWT, and then remove it once they checkout and the data is stored in the database or is there a better option? I saw options for local-storage or session-storage but am not sure what the best option is.
In theory there is no limit max size of JWT, but in practice, it is used to authenticate the user so supposedly the smaller the better. I think it's totally possible strategy. The advantage of using jwt would be that it doesn't have to hit the db. On the other hand, a lookup like this (normally) should be be trivial. You also should be careful that you don't leak any secrets into the jwt since it is possible to view the contents.
For example: We have a User model, which in turn has several Company entities. I see 2 solutions:
1) Classical. Make an API like:
/users/
/users/3/
/users/3/companies/
and issue /users or companies request separately. However, if we need to have both user and his/her companies information in one view (on Angular2) - we need to send 2 requests to the server.
2) Put the related/nested data inside the level-1 object model. In request:
/users/3/
the server will provide information about the User, together with his Companies. In this case we get all information for 1 request. But again, the company has an unlimited number of Storage entities. What if they are required in one separate view?
I'm more inclined to the first option, but I'm confused by the description of the REST style: "The view must fully represent the resource." Satisfaction of this requirement can lead to a partition of the resource into child resources and, accordingly, to smaller representations. "
Please, help with advice, I doubt in connection with the lack of experience what decision will be correct in this case. Oh yes, I forgot, Backend on Django (Python) using Django-Rest-Framework - All this is a SaaS for ~ 1000 users.
Approach 1 is an an ideal approach for REST. But when it comes to designing APIs for the displaying information on the UI it involves much more than just partitioning the APIs as per resources.
So I would suggest including the Company information in the User API. But as you suggested Company object can have very large list of Storage objects, in this case I would recommend including only the necessary and sufficient fields of Company model into User API. So that you will be able to render one view. And then later when user expands the Company section then you can pull the left-over fields from /company/<id> API.
This way you will have lesser API calls for the hits where user doesn't look for Company details and your API will be light weight as well.
I know that to make a stateless application, we need to transfer the user state back and forth instead of server holds the user state.
However, there must be some states stored in the server, I read this article that the state stored in server is called resource state.So if I am right, client state which we often call should be the same as application state.
So, how do I distinguish these two, since it will determine that whether they should stored in server or transferred.
Take a shopping cart as an example.
If there is 5 steps before a user to complete his purchase, the user's phase where he is(#3,#4) in seems to be an application state, but does this mean if they close the browser and click on pay again, he will have to start from the step1?
What about the items in his chart? If we treat it as application state, we need to put all of the items in the request. But if we do this, when user close the browser and login again, he will not able to find his items again, since the browser can not remember all the items. So it seems we should treat it as a resource state. But if so, when a user click on pay , they will have a different page: go to pay or say "your cart is empty" based on whether his shopping cart is empty or not. So , the same requests with exactly the same param input, comes out the different result, can we still say it is stateless?
Maybe I understand something wrong, can any body please answer how to distinguish different kinds of state and how to treat them differently?
Resource state is a state that needs to be persistent and survivable even after client disconnect/restart/session end/whatever.
Application state should live on the client and should be supplied with each client request(if we are talking about REST architecture and planning to scale our application well).
How to distinguish application state and resource state?
It depends on the task your are working on. E.g. if you are trying to figure out where to save index of the picture that is currently viewed in your gallery, probably, you could do it in your Application state, because you, likely, don't need this state to survive for the next session of this client. Of course, you can save it in your Resource state(database), but it would be overhead(a lot of effort for a very small gain).
But if your are working on multistep purchasing process, probably, it's better to save state of this process in your Resource state(database), because you want this state to be saved permanently. Otherwise, your clients need to refill a lot of information after disconnect/restart/whatever.
Of course you could do it in cookies for example(and it would be Application state), and this state can live after browser restart. But it has the two downsides: 1)This state unavailable on other user's devices, 2)If you are creating genuine REST service, cookies would complicate client's life, because not all clients operate cookies well(except browsers).
Let me just quote one paragraph of the book RESTful Web Services :
The Flickr
web service lets you upload pictures to your account, and those pictures are stored on
the server. It would be crazy to make the client send every one of its pictures along with
every request to flickr.com, just to keep the server from having to store any state
The application state is related to the path that the client can follow to make some actions.
For example, when consulting an article, a link "add to cart" appears. When consulting his cart, a link "pay your order" is provided if you have one article in your cart otherwise this link does not appears. Feel free to the user to make its own application state based on the link that he follows. Basically, application state is a matter of context.
One other quote from the same book mentionned earlier before I go back to you example:
Resource state stays on the server and is
only sent to the client in the form of representations. Application state stays on the
client until it can be used to create, modify, or delete a resource. Then it’s sent to the
server as part of a POST, PUT, or DELETE request, and becomes resource state.
So let's say that you have some authentification mechanism (based on token). And to one user account is associated one cart.
When you are adding items in your cart, you are modifying your cart resource. As resource state are server-side, it's on server.
Suppose that you disconnect, and reconnect like described in your first point. The cart is still here.
As long as the client send the different authentification credential at each request, your application remains stateless.
A good discussion on SO about how to manage it: Do sessions really violate RESTfulness?
Now, what about the fact that: consulting your cart can leads you to 2 different action depending on whether it has items or not.
Pretty simple. What is served by the server to the client depends on the resource state maintains by the server.
A very simple example on this good website. You can see that depending on the amount of money on the account, the server provides a link to the client to make a withdraw or not.
Feel free to the client to make its own application (again) and to follow the link or not.
I recommand you to take a look at HATEOAS and the Richardson Maturity Model that explains it.
By the way, the quotes from the 2 paragraphs are from the same author that this model.