I have resources like this
/entities # GET, POST
/entities/<id> # GET, PUT, DELETE
GET /entities gets the list of all entities.
Now I want to poll for updates. The case for a single entity is straight forward:
GET /entities/2
If-Modified-Since: <http date>
The list is tricky. I want the response to be a list of entities, updated or created since a given point in time. I'd intuitively use
GET /entities
Range: after <http date>
Which is a valid request by HTTP specification http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2 . But the spec also mandates a 206 Partial Content response, which has to include a Content-Range header. A Content-Range header, in turn, mandates a byte range to be specified http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16 . This is obviously very inconvenient for my use case.
How would you request a semantic range over HTTP?
From reading section 14.35.1, I would say that the Range header is used to request a specific range of bytes from a resource, not to request a group of entities according to when they were modified.
In this case, I believe you should treat your range as a filter and pass the date as a query string parameter:
GET /entities?modified-since=<date>
Related
Chapter 9.5 POST of the HTTP/1.1 spec includes the sentence:
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
It is referenced frequently. The itention is clear, but I have issues with the meaning of some of the chosen words.
What does "contain an entity which describes the status of the request and refers to the new resource" exactly mean?
How shall the entity (entity-header fields and entity-body) describe the status of the request? Isn't the status of the request 201 (Created)? Whow shall this status be described? Does "describe the status of the request" mean the result, in other words the current entity status?
Thinking of a Web API with JSON representation does it mean that the entity should be included in a JSON representation after a successful POST that created an entity? Thinking of a created image, should the image data be returned in the response body?
What is meant with refers to the new resource? The uri is already in the location header. Shall it be repeated in the body or does it mean just to add an id?
Is there a good source with examples of different entities and its responses to a creation POST?
I think it varies based on the resource you're creating, suppose your posting to a /profile/ resource maybe a payload containing multiple profile fields to update - your return would indicate it was successful and include a reference to the fields you posted (it can even return the entire profile attributes with fields you've updated including all fields);
Another example in the image sense, suppose you are posting a Base64 encoded image to a service that stores the image, the response should show the status (ie: accepted, rejected, file too larage, MIME type accurate or not, etc.) - and within the returned payload if successful you'd want the response to not be vague but return the path and/or filename of the image uploaded;
The header returns the response code - the body returns information related to the invoked action's entity response (it can be a set of fields, a URL, a useful response that when parsed back it can be actionable or informative);
These are principles of good coding, but also keep note of security and not to expose anything in a return that could potentially be damaging for example; when creating a service you want to be clear and provide concise and useful returns so when the client consumes the API it knows what to do, what to expect, etc.
What is the correct verb and response to accept a batch PUT create and then return multiple locations? The Location header only appears to support one single Uri.
I assumed originally I could use PUT for a batch create and return an string array with a list of Uris, but in looking at the specification, that doesn't appear to be supported, but it isn't entirely clear either.
Are multiple Location headers permissible as an alternative?
Any advice?
No, you can have only one Location header field (and yes, it is clear from the spec).
That being said, PUT is for creating/updating a single resource. It seems that you're using it for something it is not designed for...
PUT can only create one resource, because according to the specification:
The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload.
(https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4)
However, it is possible for a request with a different verb (such as POST) to create multiple resources and return a 201 Created status. According to the specification:
The primary resource created by the request is identified by either a Location header field in the response or, if no Location field is received, by the effective request URI.
The 201 response payload typically describes and links to the resource(s) created.
(https://www.rfc-editor.org/rfc/rfc7231#section-6.3.2)
So it is OK to return the URIs of multiple created resources in a 201 response to, e.g., a POST request, but the Location header may only contain one URI.
RFC 5988 introduces Link HTTP Header. It can be used for this purpose.
I'm writting a RESTful api, and at I'm thinking about the process of a user creating a key. I have the following possibilities:
GET request to /new/<keyname> - although it's very easy I think I won't use this, because I heard GET is for retrieving and/or listing information;
POST request to /<keyname> - This seemed to me easy and simple enough, but does not pass any data in the request body. Can I do it this way ? Is this weird ?
POST request to /keys passing in the request body "keyname=SomeKey" - Is this the correct way ?
I looked at this API from joyent and in all their PUT and POST requests they pass some data in the request body. Is this expected ? Is it really wrong not to require a request body in a PUT and POST request ?
I asked this question on the Http-WG. This was the most precise answer I got http://lists.w3.org/Archives/Public/ietf-http-wg/2010JulSep/0276.html
In summary, POST does not require a body. I would expect the same justification can be applied to PUT.
RFC2616 is the base RFC for HTTP 1.1
In the most general form, an HTTP message is this (note the optional body):
generic-message = start-line
*(message-header CRLF)
CRLF
[ message-body ]
start-line = Request-Line | Status-Line
Reading further gives this:
9.5 POST
The POST method is used to request that the origin server accept the
entity enclosed in the request as a new subordinate of the resource
identified by the Request-URI in the Request-Line. ...
and
9.6 PUT
The PUT method requests that the enclosed entity be stored under the
supplied Request-URI. ...
The fundamental difference between the POST and PUT requests is
reflected in the different meaning of the Request-URI. The URI in a
POST request identifies the resource that will handle the enclosed
entity. That resource might be a data-accepting process, a gateway to
some other protocol, or a separate entity that accepts annotations.
In contrast, the URI in a PUT request identifies the entity enclosed
with the request -- the user agent knows what URI is intended and the
server MUST NOT attempt to apply the request to some other resource.
Both POST and PUT include the phrase entity enclosed in the request.
Based on my reading, I believe that a body is desired (a non-normative description, I know) for both POST and PUT.
In the context of REST, POST is create and PUT is update. I can imagine creating an empty object (perhaps a placeholder for future information), but I don't imagine much use of an empty update.
It is not required. You can send a POST/PUT request without a body and instead use query string parameters. But be careful if your parameters contain characters that are not HTTP valid you will have to encode them.
For example if you need to POST 'hello world' to and end point you would have to make it look like this: http://api.com?param=hello%20world
Probably the best way is your third option: POST to /keys with keyname=SomeKey.
Here's why: You may wish to add another function to your API, for example create_new_user. It would then be difficult to tell the difference between a user trying to POST a key called create_new_user and a user trying to use the create_new_user function.
You are correct in saying that you should not be using GET to do this operation as the GET operation "SHOULD NOT have the significance of taking an action
other than retrieval." (RFC 2616).
To answer your question in one line. Yes it is expected to have Body/Content in body, but it is not required(Mandatory).
According to okHttp3 (an HTTP library for android): the following methods need a body: POST, PUT, PATCH, PROPPATCH (WebDAV) and REPORT (source). It even crashes if you try to do a request with the given methods without a body.
I've written a RESTful web service that supports the standard CRUD operations, and that can return a set of objects matching certain criteria (a SEARCH verb), but I'd like to add a higher-order COUNT verb, so clients can count the resources matching search criteria without having to fetch all of them.
A few options that occur to me:
Ignoring the HTTP specification and returning the object count in the response body of a HEAD request.
Duplicating the SEARCH verb's logic, but making a HEAD request instead of a GET request. The server then would encode the object count in a response header.
Defining a new HTTP method, COUNT, that returns the object count in the response body.
I'd prefer the API of the first approach, but I have to strike that option because it's non-compliant. The second approach seems most semantically correct, but the API isn't very convenient: clients will have to deal with response headers, when most of the time they want to be able to do something easy like response.count. So I'm leaning toward the third approach, but I'm concerned about the potential problems involved with defining a new HTTP method.
What would you do?
The main purpose of rest is to define a set of resources that you interact with using well defined verbs. You must thus avoid to define your own verbs. The number of resources should be considered as a different resource, with its own uri that you can simply GET.
For example:
GET resources?crit1=val1&crit2=val2
returns the list of resources and
GET resources/count?crit1=val1&crit2=val2
Another option is to use the conneg: e.g. Accept: text/uri-list returns the resources list and Accept: text/plain returns only the count
You can use HEAD without breaking the HTTP specification and you can indicate the count by using an HTTP Range header in the response:
HEAD /resource/?search=lorem
Response from the service, assuming that you return the first 20 results by default:
...
Content-Range: resources 0-20/12345
...
This way you transfer the amount of resources to the client within the header of the response message without the need to return a message body.
Update:
The solution suggested Yannick Loiseau will work fine. Just wanted to provide one other alternative approach which can be used to achieve what you need without the need to define a new resource of verb.
You can use GET and add the count into the body of the message. Then, if you API allows clients to request a range of results, you can use that in order to limit the size of message body to a minimum (since you only want the count). One way to do that would be to request an empty range (from 0 to 0), for example:
GET /resource/?search=lorem&range=0,0
The service could then respond as follows, indicating that there are 1234 matching resources in the result set:
<?xml version="1.0" encoding="UTF-8" ?>
<resources range="0-0/1234" />
Ignoring the HTTP specification and returning the object count in the response body of a HEAD request.
IMHO, this is a very bad idea. It may not work simply because you might have intermediaries that don't ignore the HTTP spec.
Defining a new HTTP method, COUNT, that returns the object count in the response body.
There is no problem with this approach. HTTP is extendable and you can define your own verbs. Some firewalls prohibit this, but they are usually also prohibit POST and DELETE and X-HTTP-Method-Override header is widely supported.
Another option, to add a query param to your url, something like: ?countOnly=true
See, for example, §13.3.3 and §13.3.4.
It doesn't seem to me that this could be related to "media range" (§14.1, e.g. Accept: text/*), nor "language range" (§14.4, e.g. Accept-Language: da, en-gb;q=0.8, en;q=0.7).
Maybe it's the "accept range" (§14.5), which puts byte limitations on a response? If that's true, how do ETags relate?
I'm pretty sure it's for range retrieval requests, i.e. requesting part of a document (resuming a file download, for example).
14.35.2 Range Retrieval Requests
HTTP retrieval requests using
conditional or unconditional GET
methods MAY request one or more
sub-ranges of the entity, instead of
the entire entity, using the Range
request header, which applies to
the entity returned as the result of
the request:
If the ETag is weak (starts with W/) then it can't be used for a range retrieval - only strong validators can be used for that or the client may end up with an inconsistent file.