Without moving away from the RESTful paradigm, how could you model object validation in a RESTful way? Best to explain the theoretical use case I've come up with...
Imagine you have a system with a very thin web layer making calls to back-end RESTful services. Say a user visited a registration form and submitted it, the web layer would send the unvalidated data straight to a back-end service and, if the service responds with validation errors in JSON format, these can be sent back to the user as HTML.
However, imagine we want to have AJAX behaviour on the form. For example, the user enters their email address and we want to validate using AJAX, sending an error to the user if their email address is already registered.
Would it make sense to implement a single call to validate just the email address, or could the whole object be sent and validated in a back-end service? If the latter, what URL could you use to only validate an object, rather than actually create it?
In the past I have used the notion of a sandbox sub-resource to do what you are suggesting,
http://example.com/customer/23/sandbox
This allows me to POST deltas and have the changes applied and validated but not actually committed. This works quite well for the traditional "save/cancel" type dialogs.
However, I found dealing with those deltas to be a real pain, so I developed a different media type that recorded a sequence of events on the client and then posted that document to the sandbox resource. By replaying the sequence of events I could update and validate the server side resource in a simpler fashion.
Later on I realized that I really didn't need the distinct "sandbox" resource and now I just post the "sequence of events" document directly to the resource it is affecting. I have some data in the document itself that determines whether the changes are going to be permanent or just transient. It just depends if the user has pressed the save button yet or not.
Validating a single form field can improve user experience while the user is filling the form, but when the form is submitted, I would validate the whole object, because it's less error prone. The URL can be simply https://mysite.com/users/emailvalidator for validating the e-mail only (a single field), and the form could be POSTed to https://mysite.com/users (the whole object). In the former case, the URL tells clearly that the resource you want to use is an object which is able to validate an e-mail.
Related
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.
I'm trying to figure out best or common practices for API design.
My concern is basically this:
PUT /users/:id
In my view this endpoint could by used for a wide array of functions.
I would use it to change the user name or profile, but what about ex, resetting a password?
From a "model" point of view, that could be flag, a property of the user, so it would "work" to send a modification.
But I would expect more something like
POST /users/:id/reset_password
But that means that almost for each modification I could create a different endpoint according to the meaning of the modification, i.e
POST /users/:id/enable
POST /users/:id/birthday
...
or even
GET /user/:id/birthday
compared to simply
GET /users/:id
So basically I don't understand when to stop using a single POST/GET and creating instead different endpoints.
It looks to me as a simple matter of choice, I just want to know if there is some standard way of doing this or some guideline. After reading and looking at example I'm still not really sure.
Disclaimer: In a lot of cases, people ask about REST when what they really want is an HTTP compliant RPC design with pretty URLs. In what follows, I'm answering about REST.
In my view this endpoint could by used for a wide array of functions. I would use it to change the user name or profile, but what about ex, resetting a password?
Sure, why not?
I don't understand when to stop using a single POST/GET and creating instead different endpoints.
A really good starting point is Jim Webber's talk Domain Driven Design for RESTful systems.
First key idea - your resources are not your domain model entities. Your REST API is really a facade in front of your domain model, which supports the illusion that you are just a website.
So your resources are analogous to documents that represent information. The URI identifies the document.
Second key idea - that URI is used by clients to cache representations of the resource, so that we don't need to send requests back to the server all the time. Instead, we have built into HTTP a bunch of standard ways for communicating caching meta data from the server to the client.
Critical to that is the rule for cache invalidation: a successful unsafe request invalidates previously cached representations of the same resource (ie, the same URI).
So the general rule is, if the client is going to do something that will modify a resource they have already cached, then we want the modification request to go to that same URI.
Your REST API is a facade to make your domain model look like a web site. So if we think about how we might build a web site to do the same thing, it can give us insights to how we arrange our resources.
So to borrow your example, we might have a web page representation of the user. If we were going to allow the client to modify that page, then we might think through a bunch of use cases (enable, change birthday, change name, reset password). For each of these supported cases, we would have a link to a task-specific form. Each of those forms would have fields allowing the client to describe the change, and a url in the form action to decide where the form gets submitted.
Since what the client is trying to achieve is to modify the profile page itself, we would have each of those forms submit back to the profile page URI, so that the client would know to invalidate the previously cached representations if the request were successful.
So your resource identifiers might look like:
/users/:id
/users/:id/forms/enable
/users/:id/forms/changeName
/users/:id/forms/changeBirthday
/users/:id/forms/resetPassword
Where each of the forms submits its information to /users/:id.
That does mean, in your implementation, you are probably going to end up with a lot of different requests routed to the same handler, and so you may need to disambiguate them there.
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.
I am developing a feature, where a user requests some data by filling a form and posting it. The form contains user details (name, email, mobile etc.) and these details need to be saved in the database as a lead. Once the lead data is saved successfully then only the requested data will have to be retrieved from the database and shown to the user.
I started looking into this problem by dividing it into below two APIs and calling it sequentially
A POST API to create a lead resource.
A GET API to fetch the requested resource on the success of POST.
But then I realized that the solution will affect the speed of data retrieval as I will be doing two separate network request sequentially and I cannot compromise on speed.
How can I solve this problem without compromising on speed? Should I use POST request and return the requested data in its response?
P.S. I cannot call both the APIs in parallel
Yes, that's exactly what you should do - the POST request should respond with the newly created resource, that the client can subsequently use.
You have been thinking about the problem from the web developer's perspective. You have this byte stream and to send it to clients doesn't need any form submission, a GET request ought to suffice. But from the business' perspective, retrieving the file does require a form submission, namely, the user's personal data. Even from the user's perspective it is a single operation. The user sends in the requisite data in order to get out the desired response (e.g. a file download). The saving of the input data (user's private details) is a side effect, not a user-intended outcome.
As such, a single POST request which submits the user data, saves it, then responds with the requested resource, is sufficient to cover the situation.
I am supposed to make web services for an app and thought I could do a nice job practicing the good practice. As I found out it's using REST. But there is one thing that makes very little sense in it.
Why use URI to pass any variable?
What we did in our last project is use POST only and pass whatever as raw POST data (which was JSON). That's not very RESTful. But it has some advantages. It was quite simple on the client side - I had a general function that takes URI and data as arguments and then it wraps it up and sends it.
Now, if I used proper REST, I would have to pass some data as part of the URI (user ID, for instance). All the other data (username, email and etc.) would have to go as raw data, like we did, I guess. That means I would have to separate user ID and the other data at some point. That's not so bad but still - why?
EDIT
Here is a more detailed example:
Let's say you want to access (GET) and update (POST) user data. You may have a service accessible under /user but what RESTful service would do is accept user's ID as part of the URI (/user/1234). All the other data (name, email and etc) would go to request content (probably as JSON).
What I pose is that it seems useless to make put user id in the URI. If you wanted to update user data - you would send additional data as content anyway. If you wanted to access it - you could use same generic method to request web service.
I know GET gets cached by a browser but I believe you have to cache it manually anyway if you use AJAX (web) or any HTTP client library (other platforms).
From point of scalability - you can always add more services.
You use the URI to identify the resource (user/document/webpage) you want to work with, and pass the related data inside the request.
It has the advantage that web infrastructure components can find out the location of the resource without having any idea how your content is represented. For example, you can use standard caches and load balancers, all they need to know is the URL and headers (which are always represented the same way) Whether you use JSON, protobuf or WAV audio to communicate with your resource is irrelevant.
This will for example let you keep different resources in totally different places, if you send it all as content you won't have the advantage of being able to place the resources in totally different locations, as for example http://cloud.google.com/resource1 and http://cloud.amazon.com/resource2.
All this will allow you to scale massively, which you won't be able to do if you put it all on http://my.url.com/rest and pass all resource info as content.
Re: Your edit
Passing the user id in the URL is the only way to identify the individual resource (user). Remember, it's the user that's the resource, not the "user store".
For example, a cache that caches http://my.url/user won't be much good, since it would return the same cached page for every user. If the cache can work with http://my.url/user/4711, it can cache every user separately. In the same way, a load balancer could know that users 1-5000 are handled by one machine, 5001-10000 by another etc. and make intelligent decisions based on the URL only.
Imagine a RESTful web service as a database.
To get or modify specific object you need to identify it by providing its primary key.
You identify a user by his ID, not his Name+Nickname+e-mail+mother's maiden name.
The information that identifies an object or selects a set of objects goes to the URL. The information that modifies objects should be POSTed to the corresponding URL.