I have a model named Booking with a User, a Service and the createdAt fields.
The URL to create a new Booking should be:
[POST] /bookings?user_id={user_id}&service_id={service_id}
or
[POST] /users/{user_id}/bookings?service_id={service_id}
or
[POST] /services/{service_id}/bookings?user_id={user}
All of those are fine, but....
It's a good idea to pay attention to cache invalidation. The target URI of your request is one of three resource identifiers that will be automatically invalidated by a successful POST request. You can take advantage of that to evict a web page in the client's cache whose information will be changed by the message you send.
For example, if creating a new booking adds a new link to the /bookings resource, then
POST /bookings
has the advantage of automatically evicting the previously cached copy of the resource that doesn't include the link you just created.
Related
If i have a post endpoint for a car, but only get endpoints for a collection of cars, what should be the created URL in the Response. Usually it should be cars/{id-of-new-car}
But since that endpoint does not exists, that URL is misleading.
If you only have a collection, and you used POST on that collection to add a new car, you didn't create any new resources, you just updated one (the collection).
So if your question is: What should go in the Location header that goes along with the 201 Created response, I'd say you probably don't need either.
Let's say I am modeling blogging REST API which has resources Blog, Post and Comment.
Then I add following URIs for Blog and Post resources:
/api/blogs
/api/blogs/{blogId}
/api/blogs/{blogId}/posts
and since deep nesting should be avoided I create separate endpoint for all Posts in order to get their Comment`s:
/api/posts
/api/posts/{postId}
/api/posts/{postId}/comments
Now, if I implement POST action that creates a new Post for a specific Blog on /api/blogs/{blogId}/posts endpoint, should I set Location header value in response to:
/api/blogs/{blogId}/posts/123
or
/api/posts/123
?
In either case I can GET the same resource, but is there some preference, according to REST style, which should be returned to client after successful POST?
If one or more resources has been created on the origin server as a result of successfully processing a POST request, the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created (Section 7.1.2) and a representation that describes the status of the request while referring to the new resource(s). -- RFC 7231
Which resource is the "primary resource"? That's up to you - priority of the resources is going to depend on your resource model, and REST / HTTP do not care what model you use.
In effect, it comes down to "which URI do you want to see in your access logs?"
Let's say we have a collection resource called shelf (of book resources) and we would like to POST a new book:
[POST] /shelves/{shelf-id}/books [request body -- a book]
I know that the response should be either empty with a reference to the newly created resource (201) or include the created resource (200).
Let's say the clients that are creating book resources, will need to show summary of the shelf the new book is added to. One solution should be making clients to first do a POST (let's call it Req#1 -- to create the new book), and then a GET (Req#2) on the shelf resource to get the summary.
What if we care a lot about efficiency and want to return the result of Req#2 implicitly when getting Req#1 on the server and save one request on the client side? Is it OK based on REST principles to return the parent collection resource information in the response when a resource is added to the collection?
Any alternative design?
It's 'OK' for REST design to return different resource states, but HTTP doesn't have a standard way to do this. If you uses the HAL format for you REST api, it does have a way to do embedding, so I suppose you could embed different resources to the response of a POST request.
Note that there's no standard I know of that suggests that the following statement is true: I know that the response should be either empty with a reference to the newly created resource (201) or include the created resource (200).
Anyway, what are you trying to solve? Is it really that expensive to do an extra HTTP request? Where do you base that concern on? What's expensive about it? Is it the latency of having to do an extra roundtrip?
If that's the case, you could consider using HTTP/2 push to push a new version of your parent resource. It's probably the most standards compliant way. If your server and client support this well, then this also means you can use this as a great standard mechanism to push things to clients because they might soon request it.
I know that the response should be either empty with a reference to the newly created resource (201) or include the created resource (200).
This isn't true. According to the spec:
The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a Location header field. The response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. The origin server MUST create the resource before returning the 201 status code.
In summary, use a 201 status response with information about the new resource. Please don't mix information about other resources with it. That is not RESTful, and apart from pedantry, it probably will make a messy API for very little benefit.
My REST service needs to support the ability to load/reload a resource vs. outright create it.
API thus far:
GET /books
GET /books/12345
DELETE /books/12345
A book looks something like:
{"id": 12345, "title": "three little bears", "author": ...}
It's unclear as to whether
Request: PUT /books/12345
Response: HTTP 204 No Content
or
Request: POST /books
Payload: {"id": 12345}
Response: HTTP 201 Created, Location: /books/12345
is the better approach to "load"/"reload" the book.
Details: The "load"/"reload" will consult a database to retrieve the book by id, and place the result in a persistent cache. The cache is what is consulted for the GET requests. The book's attributes can change in the database, meaning a "load"/"reload" isn't idempotent. Only an admin will be able to use the load/reload and delete operations.
I believe the correct approach is a POST, because a PUT is supposed to be idempotent. However, a POST seems odd because multiple POSTs against /book for id=12345 will only result in a single resource being created (albeit re-created multiple times)
I've considered the additional options below, but they seem more egregious:
* POST /books/12345/load
* POST /books/load, with payload {"id": 12345}
* POST /load/book, with payload {"id": 12345}
Thoughts?
To complicate matters further, I'd also like to offer an asynchronous load/reload operation, but i don't want to create an operation/job resource that the user can track, I just want a fire-and-forget.
Example: For Book 12345, load/reload asynchronously into the cache. I only need the service to respond with a HTTP 202 Accepted and that's sufficient. No need to ever ask what the progress of the load/reload.
TL;DR: I'm building a REST service to front a cache of books. The load/reload and delete operations can only be executed by an admin, whereas GET is open for all. The load/reload operation should load/reload the record from the database.
If I get you correct, you have a
origin
database
clients
If a client GETs a book, he fetches the resource from the database.
The database doesn't know if this book is altered in the meantime, it serves an outdated version? Therefore you want the client to POST or PUT the resource to force the database to fetch the entry again from the origin?
Think about this:
The origin caches its content, the database caches its content and the client caches too.
If a user would hit F5 the client would reload the resource, right?
Is this a good behaviour? no.
Would it be better for the client to check wether the resource is outdated or not and only fetch if neccessary? yes.
This could be achieved by sending a HTTP-HEAD asking the server for the date of the last modification, if the clients retrieval-date is older he needs to fetch again, otherwise he can serve from cache.
Same would apply for the databse/origin-constellation. The database needs to validate its content is still the latest for the request and serve it or fetch it from the origin, update the caches and serve the new entry.
So the client would still GET the resoure, what would be accurate if he doesn't want to alter the resource in any way.
I think that you shouldn't use action names within resource paths (something like /books/12345/reload, ...) since it's not really RESTful. That said, I agree with you that a method POST is the right method to use.
IMO, you should use a method POST for the resource path /books/12345. It will correspond to an action load / reload and can be asynchronous, i.e. return a status code 202รจ. If you already have a methodPOST` for this resource, you should consider to use the strategy described in this blog post: https://templth.wordpress.com/2015/03/20/handling-multiple-actions-for-a-post-method/.
Hope it helps you,
Thierry
We are trying to implement a REST API for an application we have now. We want to expose read/write capabilities for various resources using the REST API. How do we implement the "form" part of this? I get how to expose "read" of our data by creating RESTful URLs that essentially function as method calls and return the data:
GET /restapi/myobject?param=object-id-maybe
...and an XML document representing some data structure is returned. Fine.
But, normally, in a web application, an "edit" would involve two requests: one to load the current version of the resources and populate the form with that data, and one to post the modified data back.
But I don't get how you would do the same thing with HTTP methods that REST is sort of mapped to. It's a PUT, right? Can someone explain this?
(Additional consideration: The UI would be primarily done with AJAX)
--
Update: That definitely helps. But, I am still a bit confused about the server side? Obviously, I am not simply dealing with files here. On the server, the code that answers the requests should be filtering the request method to determine what to do with it? Is that the "switch" between reads and writes?
There are many different alternatives you can use. A good solution is provided at the microformats wiki and has also been referenced by the RESTful JSON crew. As close as you can get to a standard, really.
Operate on a Record
GET /people/1
return the first record
DELETE /people/1
destroy the first record
POST /people/1?_method=DELETE
alias for DELETE, to compensate for browser limitations
GET /people/1/edit
return a form to edit the first record
PUT /people/1
submit fields for updating the first record
POST /people/1?_method=PUT
alias for PUT, to compensate for browser limitations
I think you need to separate data services from web UI. When providing data services, a RESTful system is entirely appropriate, including the use of verbs that browsers can't support (like PUT and DELETE).
When describing a UI, I think most people confuse "RESTful" with "nice, predictable URLs". I wouldn't be all that worried about a purely RESTful URL syntax when you're describing web UI.
If you're submitting the data via plain HTML, you're restricted to doing a POST based form. The URI that the POST request is sent to should not be the URI for the resource being modified. You should either POST to a collection resource that ADDs a newly created resource each time (with the URI for the new resource in the Location header and a 202 status code) or POST to an updater resource that updates a resource with a supplied URI in the request's content (or custom header).
If you're using an XmlHttpRequest object, you can set the method to PUT and submit the data to the resource's URI. This can also work with empty forms if the server supplies a valid URI for the yet-nonexistent resource. The first PUT would create the resource (returning 202). Subsequent PUTs will either do nothing if it's the same data or modify the existing resource (in either case a 200 is returned unless an error occurs).
The load should just be a normal GET request, and the saving of new data should be a POST to the URL which currently has the data...
For example, load the current data from http://www.example.com/record/matt-s-example and then, change the data, and POST back to the same URL with the new data.
A PUT request could be used when creating a new record (i.e. PUT the data at a URL which doesn't currently exist), but in practice just POSTing is probably a better approach to get started with.