I've been wrestling with the problem of representing a checkout / checkin system via a REST api.
To give you a small example our system handles nodes and we need a way for one user to be able to lock this node and then make changes to it and then commit it.
So I was thinking something like
/nodeId (this is the base location for a node and provides an up to date checked in revision read only view of the node)
/nodeId/edited (posting to here creates an edited version of the doc this is checkout, gettting gets the edited version, and putting makes a change)
Now I want to represent checkin, im tempted to say that POSTing to /nodeId/edited again will commit the edited document but then we are, giving post two distinct meanings. I could create another checkin endpoint but that seems messy? Another alternative is having a POST to /nodeId which creates the edited version but again this seems confused.
To lock/checkout a Resource, POST to /nodeId with the partial document {"locked":"true"}. The server must handle Resource state and check if the Resource can be locked etc. The server could answer 204 No Content if the lock suceeded and 409 Conflict if the lock was not possible.
To unlock/checkin the locked Resource, POST to /nodeId with the partial document {"locked":"false", "someKey":"someValue", ...}. The server must handle Resource state, check if the Resource is locked, and update it usinng the POSTed data. Again, the server could answer 204 No Content if the unlock suceeded and 409 Conflict if not.
Edit: added possible HTTP status codes.
Edit 2: There is no "endpoint" in REST like in SOAP. You manipulate Resources, you don't call methods.
Related
I'm wondering what are the best ways to delete items from a subset in a restful way. I got users and series, each user has his own list of series (watching, completed, etc). For example, if we want to get a list from a user we can do it with: GET /users/:id_user/series
If we want to delete a serie from the list of that user (but we don't want to delete the serie itself), how should it be?
I thought about the possibility of using DELETE /users/:id_user/series/:id_serie, but I'm not sure if it's the correct way for this case (maybe PATCH?).
I got another case, we got series and reviews. We can get the reviews like this: GET /series/:serie_id/reviews. In the other case we didn't want to delete the serie itself when deleting from a user list of series, but in this case we want to delete the review because its existence depends on the serie. So I guess in this case DELETE /series/:serie_id/reviews/:review_id is correct.
Is this difference important in order to choose the rest operation to delete the object/item from the subset?
How would you do it on the web?
You'd follow a link to a form, with input controls. You might have a something like a dropdown if you wanted to delete one series at a time, or lots of check boxes if you wanted to support a bulk delete. The user would provide input, hit the submit button, and the browser would create an application/x-www-form-urlencoded document and send it to the server.
What method would be used? Normally POST, because we are intending an edit to some resource on the server.
What resource would we be editing? Well, in trutch, it could be anything -- the server would include that information in the form metadata, so the client can just do what it is told.
So where should the server tell it to submit the form? Again, it could be anywhere... but a useful approach is to think about what resource in the client's cache is being updated. Because if we send the request to that resource, we get intelligent cache invalidation "for free".
So on the web, we would expect to see:
POST /users/:id_user/series
Does it have to be POST? On the HTML web, maybe it does, because the ubiquitous client of the web is a browser, not an editor.
It is okay to use POST.
But a perfectly valid alternative would be to edit the local copy of /users/:id_user/series, and then send back to the server a complete copy of the new version (PUT) or a patch-document describing the edits (PATCH). Notice that with both of these choices, the target uri is still /user/:id_user/series, so we still get the cache invalidation magic.
Creating a new resource in your model just to have something to DELETE is probably the wrong idea.
There are cases where an edit, or a delete, will necessarily impact more than one resource.
There are some specific circumstances when you can get the right magic cache invalidation with two resources (for instance, delete one document, and send back an updated copy of another).
But we don't, today, have a general purpose cache invalidation mechanism. (Closest thing I've been able to find is this, which seems to have stalled out in 2012.
I'm building a REST API which has the followings endpoints:
GET /api/v1/categories - Get all categories
DELETE /api/v1/categories/$id - Delete a specific category
The mobile app shall gets all categories in the first time but later, it shall gets only the last modified categories (using Last-Modified HTTP header).
When a second app deletes a category, the server deletes it from the database. After the deletion, if others apps request the last modified categories, the server returns nothing about the deleted category and those apps don't remove it from their local database.
What is the best solution to this problem?
I'm thinking to use soft delete (a flag indicating that the category was deleted) and when the apps get the last modified categories, the server returns all modified categories since the date passed in HTTP header, including the deleted categories. However, if the apps request all categories (without Last-Modified header), the server returns all categories, except deleted (marked with the flag).
Is the presented solution the best one to this problem?
What is the best solution to this problem?
You might look to the web for inspiration. See RFC 7234.
The high points being this: the web is a distributed system, and each client gets to manage their own local cache of representations of resources. Resources are delivered to the clients with metadata describing its freshness; the client is entitled to re-use their local copy of state until it is stale. Successful unsafe operations on a resource automatically evict previously cached representations for that resource, and a mechanism (304) exists to allow the server to cheaply communicate to the client that a previously cached representation is still fresh.
But changes on the server don't automatically propagate to all clients, nor do they cascade from one resource to another. You need to instead think in terms of selecting the right freshness policy for each resource in isolation.
This is one of the reasons it is important to recognize that the design of your resource model needs to satisfy a different set of constraints than does the design of your data model.
Does anyone have best practice pattern for cqrs with put/post, specifically the client is doing a get for updated resource after it has sent command/event... Would you allow/require the client to keep local copy of the updated resource, and send a last updated timestamp in the get response? Or ensure that get includes the unprocessed commands? Of course, if the same resource is retrieved by another client, may/not get the updated resource.
What's worked best for you?
Would you contend with added complexity of the get also checking command queue?
Does anyone have best practice pattern for cqrs with put/post, specifically the client is doing a get for updated resource after it has sent command/event...
How would you do it on a web site?
Normally, you would do a GET to load the resource, and that would give you version 0, possibly with some validators in the meta data to let you know what version of the representation you received. If you tried to GET the resource again, the generic components could see from the headers that your copy was up to date, and would send you back a message to that effect (304 Not Modified).
When you POST to that resource, a successful response lets all of the intermediate components know that the previously cached copy of the resource has been invalidated, so the next GET request will retrieve a fresh copy, with all of the modifications.
This all works great, right up to the point where, in a CQRS setting, the read requests follow a different path than the write requests. The read side will update itself eventually, so the trick is how to avoid returning a stale representation to the client that knows it should have changed.
The analogy you are looking for is 202 Accepted; we want the write side to let the client know that the operation succeeded, and that there is a resource that can be used to get the change.
Which is to say, the write side returns a response indicating that the command was successful, and provides a link that includes data that the read model can use to determine if its copy is up to date.
The client's job is to follow the links, just like everywhere else in REST.
The link provided will of course be some safe operation, pointing to the read model. The read model compares the information in the link to the meta data of the currently available representation; if the read model copy is up to date, it returns that, otherwise it returns a message telling the client to retry (presumably after some interval).
In short, we use polling on the read model, waiting for it to catch up.
I want to naI want to know if there is a real practical difference between different types of content in an HTTP response. Let me explain my self better.
Say I submit a POST request to a server with typical resource payload. Let's use a client with client_name, client_email, client_phone.
Would there be an actual difference if the server returns just an id:
{id:100}
Or if it returns the fully created resource without sensible data, like so:
{client_name: 'Some Client', client_email: 'email#sample.com', client_phone: '417-235-4622'}
Suppose that the application as a considerable amount of active users, creating resources at any given moment. Is there a significant cost in server resources associated with returning data from the server (just an ID or a full object)
Given the following scenarios when creating a resource:
Submit POST request, receive resource ID, complete all data visualization feedback with data in memory (info in form element).
Submit POST request, receive full object with id, email and phone. Continue with UI things.
If there is a difference in cost, and its significant, then the response ID is the way to go. But, I'm thinking that if I have lot's fields to submit, and most of them are required, and I'm only expecting an ID in return, then that'a a guarantee that te resource got created but it doesn't mean it was created completely. Suppose I submit the data, and one of those fields fails silently to submit to database (email for example), the server returns ID, the UI shows the user that the resource was created, the user reloads the page and the email is gone.
If the server returns the full object I get the feeling that the transaction is more atomic.
So, to wrap up. Is there a significante difference in terms of cost to the server ?
but it doesn't mean it was created completely. Suppose I submit the data, and one of those fields fails silently to submit to database (email for example)
Even if the email were to be saved in a different table than the rest of the data, it will still have to be done in a transactional manner (an indivisible operation that must succeed or fail as a complete unit; it can never be only partially complete). This could even mean rolling back changes if a failure is detected at any point during the save operation.
Now back to the main question, REST just says that you should conform to the uniform interface. In other words, it says you should do what POST is supposed to do as per the HTTP spec. Here is the quote from that spec that is relevant,
If a resource has been created on the
origin server, the response SHOULD
be 201 (Created) and contain an entity
which describes the status of the
request and refers to the new
resource, and a Location header
(see section 14.30).
I think it all depends on the use case scenarios. If the client immediately needs to display info regarding the newly created object, I really do not see any advantage to returning only the ID and doing a GET request after, to get the data you could have got with your initial POST.
Anyway as long as your API is consistent I think that you should choose the pattern that fits your needs the best. There is not any correct way of how to build a REST API, imo.
Is there a significante difference in terms of cost to the server ?
That's totally unanswerable by us. How powerful is the server? What software are you running on it? What's the breakdown of your expected traffic? What performance targets are you expected to hit? etc..
Performance problems should be solved through a combination of more better hardware and a sensible software architecture that still does everything you need it to. You don't even know if you have a problem yet and you're trying to fix it.
You're asking the wrong question. The question you should be asking is: when my clients create a user, are they likely to need server-created information beyond the URI immediately? Of course, we can't really answer that either. If the server isn't (and won't ever!) be creating anything, there's an obvious answer. If it is, or may, you may want to return a full representation even if the client doesn't need it now, so it's not a breaking change later if they decide they do. The pain there depends a lot on whether this is an internal- or external-facing API, and who owns the clients.
In addition to the other answers given, which are quite comprehensive, I would just like to add that it is contrary to the design of the web to provide object IDs and expect the client to know what to do with them. You should instead be providing URLs to the object in question. Clients can then do a GET request on the provided URL to fetch the full set of data for the object, should they want to. And I f the responses to these GET requests have already been cached, your server will not have to do any work at all to satisfy them!
I am in the process of designing a REST API for a project we are working on. That is, I am writing the specifications which will be implemented later on.
I am having troubles to think into nouns/resources instead of actions/verbs. Without going into too much project specifics, we are writing an API around SVN. For example, take the action which commits changes to the SVN server. In our project, we have multiple definitions/versions of the commit action:
simply commit all changed files
commit a list of changed files (a subset, instead of the whole set of changed files)
...
(1) How would you design the URL? The first question is, how do I describe the commit action as a noun/resource instead of a verb?
Some would say:
POST/PUT http://server.com/api/revision/commit
Should it be a POST or a PUT? I am not really creating a commit resource, so it's not a POST. However, I am not really changing a commit resource, so it's not a PUT. Actually, it's not a resource, it's an action. Once the action is executed, it's gone, there is no resource to be created, changed or kept for later reference.
That said, it must be a resource, so the URL should probably be like this
POST http://server.com/api/revision/commitment
It's also a POST, since we are creating a commitment. We are not changing anything, so no PUT. Also note that I changed commit into commitment, to reflect the fact that we are dealing with resources.
Does this make sense? To me it doesn't, it drives me nuts. I want to execute an action, not create a resource which resembles the action. But anyway.
That said, going further, I just created a commitment resource. So logically, I should be able to retrieve it later on:
GET http://server.com/api/revision/commitment/:id
But there is no commitment resource! I was forced to make one in order to be RESTful. head explodes
So, how do you really specify actions on resources in a REST API? I am not talking about the kind of actions which create a resource (create user, ...), but about the kind of actions which manipulate a resource or act on a resource (commit revision, ...).
(2) Then, secondly, in case of the second definition (see above), how do we specify the subset of changed files? Through parameters or in some structure (for example JSON array) in the BODY? Which one is preferred? Are there any general rules?
Thanks all!
Sometimes it's easier to back up in a URL design than go forward. It seems to me like what you're calling a "commitment" is actually a revision itself. svn commit basically means, "please accept these differences from my currently selected revision as a new (child) revision". Therefore, you need to identify that currently selected revision (in order to remain stateless) and then append to it in a meaningful way:
POST http://server.com/api/revisions/16/children/
That is, POST an entity which encapsulates the differences from revision 16. The server could then respond with 201 Created, plus Location: /api/revisions/23/ (or /api/revisions/16/children/1, which redirects to the former).
Then, not only have you provided for the creation of new revisions, but also most likely added a useful list of the direct children of a given revision.
Stop thinking in actions ;D
First of all put your SVN to be file based and not based on a database, that will help in thinking.
If you think about it you only have 3 restfull (well in fact 4 perhaps) operations on your repository: svn add + svn commit to put a new file under version controll. This translates into a PUT on the folder into which you want to add and commit the file. svnroot:/project/folder in fact as the "id" of the file is known you actually can PUT directly on the URL of the file: svnroot:/project/folder/file.c
You want to commit a change, that translates to a POST on the resource (not the folder but the actual existing file in that folder). POST svnroot:/project/folder/file.c
If you want to remove a file it obvioulsy is a DELETE.
If you want to know what revision number a certain file has use STATUS.
Start thinking in terms of what actually is happening, not how the verbs are called (co, ci, add, update etc.), what happening is that files are 'created' in the repository, thats a PUT, or modified, thats a POST or deleted/removed thats a DELETE or the status is queried that is STATUS.
If you retrive the file it is obviously a GET.
So, that above is an actuall existing resource. Now you could start inventing more features, give the file a size and an author or last commiter or a commit message! Now you need to work on URLs, for which no real resource exists. Some call this virtual resources.
Just add "/authors" etc. to the end of the resource URLs and use POST to add an author and GET to read the authors. (Matter of taste, you as well could use PUT, would perhaps be more clean according to the REST paradigm)