I'm using fiddler to test a Web API service I'm writing.
I know I can pass parameters to a RESTful web service in the querystring with a request like -
www.example.com/api/Book?Id=123&category=fiction.
Are there other ways of passing the parameters to the service, while still using a GET.
There are many parts of the HTTP request which you can use to pass parameters, namely the URI, headers and body. GET requests don't have bodies (some frameworks actually allow that, but they're not common so for all purposes, let's just assume that they can't), so you're limited to the headers and the URI.
In the URI you can pass parameters in different places:
Query string (as you're already doing)
Ex.: www.example.com/api/Book?Id=123&category=fiction
Request path
Many frameworks will allow you to get parameters to your actions from paths in the request URI. With ASP.NET Web API you'd typically do that using routing
Ex.: www.example.com/api/Book/fiction/123
In the fragment, or the part of the URI after the # character. See the URI RFC, section 3.5.
Ex.: www.example.com/api/Book?Id=123&category=fiction#somethingElse
You can also pass paramters in the HTTP request headers. One parameter which is honored by the ASP.NET Web API is the Accept header, which is used when doing content negotiation. You can also expect custom parameters from those headers, and read them in your actions (or even have value providers which will read them and map them to the parameters in the methods themselves).
Related
The query URL / endpoint below seems to successfully make a request to the API resource and returns a JSON response:
https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/en.wikipedia/all-access/all-agents/Albert_Einstein/daily/2015100100/2015103100
Given that a request is made up of not only the URL, but also of a method, headers, and body, could someone explain how the API knows which method to use, as well as how the headers and body get transmitted (if they did exist)?
Given that a request is made up of not only the URL, but also of a method, headers, and body, could someone explain how the API knows which method to use, as well as how the headers and body get transmitted (if they did exist)?
If I'm understanding your question correctly... the API doesn't know these things, the client knows these things.
Which is to say when I'm looking at your question in my web browser, what I'm really looking at is the web browsers interpretation of an HTML document. Because the web browser speaks HTML, it knows what <a href="..."> means; that the quoted text is an identifier for another resource that I the use might want to navigate to.
The browser also knows RFC 3986, so it knows how to parse the quoted string and extract from it the protocol, the host, and the target uri.
Because the browser also knows about https, it knows which port number it should default to when the port isn't specified.
Because the browser knows HTTP, it knows how to construct a valid HTTP request, and the semantics of the required and optional headers it might want to attach.
Because HTTP follows the REST architectural style, we also know that the interface is uniform -- all HTTP resources use the same semantics. So the browser doesn't need to know what the identifier is in order to know that GET, HEAD, OPTIONS are all safe. Similarly, the rules for authentication, caching, content-negotiation, and so on are all the same, so the browser can craft the appropriate headers as it generates the request.
For instance, the browser knows that it is itself HTML capable, so it includes headers that communicate a preference for an HTML or XHTML+xml representation of the resource, if one is available.
Were I to instead switch to the command line, I could use curl(1) to generate the http request instead, which would produce an HTTP request with different headers.
The browser (and curl) know not to send a body with a HEAD or GET request because the HTTP specification explains that the payload of a GET or HEAD request has no defined semantics.
On the API side of the conversation, the server knows about HTTP, so knows how to correctly interpret the bytes of the HTTP request. Thus, the server knows where to look in the request for the HTTP method, the target URI, the headers that may (or may not) modify the context of the request, and so on. The implementation can then do whatever it likes with that information, and construct a suitable HTTP response (in effect, lifting into the headers of the response the metadata in a representation that can be understood by all of the general purpose components participating in the conversation.
In my system, I have multiple services exposing REST apis for their resources. A specific service on the system needs to make rest calls to other services in dry-run mode in specific circumstances just to do validation. Even though the body of the request has meaningful payload for the api, nothing will be persisted, no states will be changed and no messages will be sent. The tricky part is that if this service calls a REST api which didn't implement dry-run mode, it will modify the resource instead of just validating. I need a way to make dry-run requests only if the receiving service implemented dry-run in its api, otherwise the request must fail.
I had these ideas so far:
Passing a query parameter
I could pass a flag as a query parameter but the request still goes through if the api doesn't know of the parameter.
POST /resource?dry-run=true
Passing a flag in header
Similar to query parameter, unknown header fields are ignored.
Exposing a dry-run api just for validating
This solution works as I can verify dry-run version of the URL exists or not but I don't want to expose more endpoints just for validation
POST /resource
POST /resource/dry-run
PUT /resource/{id}
PUT /resource/{id}/dry-run
Inject the flag to the body of resource
This looks to be a solution but when the api doesn't support this field, JSON serialization will fail. In that case, I can't tell whether it is because dry-run is not supported by the api or there is actually a problem in the body. Also, it doesn't feel right since dry-run is not a part of the resource.
POST /resource
{
"dry-run":true,
...
...
}
Is there a better way to implement a dry-run feature to REST api where the request will fail if the service have not implemented it?
The headers way
There does not seem to be a "correct" answer for this. That being said, I would go with the headers way.
You can easily block off unknown headers as preflight checks. You can change the allow list of headers for you service to block off headers that are not used by the service.
Access-Control-Allow-Headers: [<header-name>[, <header-name>]*]
Access-Control-Allow-Headers: *
To see the list of headers allowed by your service, make a call to it and check the response headers and search for Access-Control-Allow-Headers header field.
Let's say you have three services, Cat, Dog and Animal. Animal being the caller service which calls the Cat service and Dog service.
Dog -> Access-Control-Allow-Headers: [....,"X-Request-Dry-Run",..] // dog accepts the header
Cat -> Access-Control-Allow-Headers: [.....] // cat doesn't accept the 'dry-run' header
Now when caller calls the Cat service which X-Request-Dry-Run: true header, it gets a request error.
MDN Ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
Comparisons
Passing a query parameter
could pass a flag as a query parameter but the request still goes through if the api doesn't know of the parameter.
It's generally not a convention to mix post body and query params in a post request.
Exposing a dry-run api just for validating
This solution works as I can verify dry-run version of the URL exists or not but I don't want to expose more endpoints just for validation
APIs have clashing paths.
Inject the flag to the body of resource
This looks to be a solution but when the api doesn't support this field, JSON serialization will fail. In that case, I can't tell whether it is because dry-run is not supported by the api or there is actually a problem in the body. Also, it doesn't feel right since dry-run is not a part of the resource.
Agreed
I am developing a restful web service based on a database query and the tool that i am using tends to generate the parameters as a part of the HTTP Header ?
I always thought the parameters for POST to the restful service should always be passed in HTTP Body ?
Any ideas what should be the best practice or the usual practice ?
For POST requests, you can do either, but generally you'll use the body of the request for content that you are appending, mutating, deleting, etc. or for any data that is simply too large to put in the URI while one generally uses URI parameters for information that identifies the resource that is being accessed or modified (such as the element's ID) or restrictions or other search criteria (e.g. page, limit, etc.).
The primary tradeoffs off the top of my head are linkability (do you need a special POST extension, for example, just for developers to test a particular handler on your server?), URI size limits, and also whether the user would need to perform a click in order to cause the request to be sent (though using POST body is not a substitute for requiring a valid XSRF token/signature on the request).
Did I miss any other tradeoffs?
I'm designing an API to go over HTTP and I am wondering if using the HTTP POST command, but with URL query parameters only and no request body, is a good way to go.
Considerations:
"Good Web design" requires non-idempotent actions to be sent via POST. This is a non-idempotent action.
It is easier to develop and debug this app when the request parameters are present in the URL.
The API is not intended for widespread use.
It seems like making a POST request with no body will take a bit more work, e.g. a Content-Length: 0 header must be explicitly added.
It also seems to me that a POST with no body is a bit counter to most developer's and HTTP frameworks' expectations.
Are there any more pitfalls or advantages to sending parameters on a POST request via the URL query rather than the request body?
Edit: The reason this is under consideration is that the operations are not idempotent and have side effects other than retrieval. See the HTTP spec:
In particular, the convention has been
established that the GET and HEAD
methods SHOULD NOT have the
significance of taking an action other
than retrieval. These methods ought to
be considered "safe". This allows user
agents to represent other methods,
such as POST, PUT and DELETE, in a
special way, so that the user is made
aware of the fact that a possibly
unsafe action is being requested.
...
Methods can also have the property of
"idempotence" in that (aside from
error or expiration issues) the
side-effects of N > 0 identical
requests is the same as for a single
request. The methods GET, HEAD, PUT
and DELETE share this property. Also,
the methods OPTIONS and TRACE SHOULD
NOT have side effects, and so are
inherently idempotent.
If your action is not idempotent, then you MUST use POST. If you don't, you're just asking for trouble down the line. GET, PUT and DELETE methods are required to be idempotent. Imagine what would happen in your application if the client was pre-fetching every possible GET request for your service – if this would cause side effects visible to the client, then something's wrong.
I agree that sending a POST with a query string but without a body seems odd, but I think it can be appropriate in some situations.
Think of the query part of a URL as a command to the resource to limit the scope of the current request. Typically, query strings are used to sort or filter a GET request (like ?page=1&sort=title) but I suppose it makes sense on a POST to also limit the scope (perhaps like ?action=delete&id=5).
Everyone is right: stick with POST for non-idempotent requests.
What about using both an URI query string and request content? Well it's valid HTTP (see note 1), so why not?!
It is also perfectly logical: URLs, including their query string part, are for locating resources. Whereas HTTP method verbs (POST - and its optional request content) are for specifying actions, or what to do with resources. Those should be orthogonal concerns. (But, they are not beautifully orthogonal concerns for the special case of ContentType=application/x-www-form-urlencoded, see note 2 below.)
Note 1: HTTP specification (1.1) does not state that query parameters and content are mutually exclusive for a HTTP server that accepts POST or PUT requests. So any server is free to accept both. I.e. if you write the server there's nothing to stop you choosing to accept both (except maybe an inflexible framework). Generally, the server can interpret query strings according to whatever rules it wants. It can even interpret them with conditional logic that refers to other headers like Content-Type too, which leads to Note 2:
Note 2: if a web browser is the primary way people are accessing your web application, and application/x-www-form-urlencoded is the Content-Type they are posting, then you should follow the rules for that Content-Type. And the rules for application/x-www-form-urlencoded are much more specific (and frankly, unusual): in this case you must interpret the URI as a set of parameters, and not a resource location. [This is the same point of usefulness Powerlord raised; that it may be hard to use web forms to POST content to your server. Just explained a little differently.]
Note 3: what are query strings originally for? RFC 3986 defines HTTP query strings as an URI part that works as a non-hierarchical way of locating a resource.
In case readers asking this question wish to ask what is good RESTful architecture: the RESTful architecture pattern doesn't require URI schemes to work a specific way. RESTful architecture concerns itself with other properties of the system, like cacheability of resources, the design of the resources themselves (their behavior, capabilities, and representations), and whether idempotence is satisfied. Or in other words, achieving a design which is highly compatible with HTTP protocol and its set of HTTP method verbs. :-) (In other words, RESTful architecture is not very presciptive with how the resources are located.)
Final note: sometimes query parameters get used for yet other things, which are neither locating resources nor encoding content. Ever seen a query parameter like 'PUT=true' or 'POST=true'? These are workarounds for browsers that don't allow you to use PUT and POST methods. While such parameters are seen as part of the URL query string (on the wire), I argue that they are not part of the URL's query in spirit.
You want reasons? Here's one:
A web form can't be used to send a request to a page that uses a mix of GET and POST. If you set the form's method to GET, all the parameters are in the query string. If you set the form's method to POST, all the parameters are in the request body.
Source: HTML 4.01 standard, section 17.13 Form Submission
From a programmatic standpoint, for the client it's packaging up parameters and appending them onto the url and conducting a POST vs. a GET. On the server-side, it's evaluating inbound parameters from the querystring instead of the posted bytes. Basically, it's a wash.
Where there could be advantages/disadvantages might be in how specific client platforms work with POST and GET routines in their networking stack, as well as how the web server deals with those requests. Depending on your implementation, one approach may be more efficient than the other. Knowing that would guide your decision here.
Nonetheless, from a programmer's perspective, I prefer allowing either a POST with all parameters in the body, or a GET with all params on the url, and explicitly ignoring url parameters with any POST request. It avoids confusion.
I would think it could still be quite RESTful to have query arguments that identify the resource on the URL while keeping the content payload confined to the POST body. This would seem to separate the considerations of "What am I sending?" versus "Who am I sending it to?".
The REST camp have some guiding principles that we can use to standardize the way we use HTTP verbs. This is helpful when building RESTful API's as you are doing.
In a nutshell:
GET should be Read Only i.e. have no effect on server state.
POST is used to create a resource on the server.
PUT is used to update or create a resource.
DELETE is used to delete a resource.
In other words, if your API action changes the server state, REST advises us to use POST/PUT/DELETE, but not GET.
User agents usually understand that doing multiple POSTs is bad and will warn against it, because the intent of POST is to alter server state (eg. pay for goods at checkout), and you probably don't want to do that twice!
Compare to a GET which you can do as often as you like (idempotent).
I find it perfectly acceptable to use query parameters on a POST end-point if they refer to an already-existing resource that must be updated through the POST end-point (not created).
For example:
POST /user_settings?user_id=4
{
"use_safe_mode": 1
}
The POST above has a query parameter referring to an existing resource, mirroring the GET end-point definition to get the same resource.
The body parameter defines how to update the existing resource.
Edited:
I prefer this to having the path of the end-point to point directly to the already-existing recourse, like some suggest to do, like so:
POST /user_settings/4
{
...
}
The reason is three-fold:
I find it has better readability, since the query parameters are named, like "user_id" in the above, in stead of just "4".
Usually, there is also a GET endpoint to get the same resource. In that case the path of the end-point and the query parameters will be the same and I like that symmetry.
I find the nesting can become cumbersome and difficult to read in case multiple parameters are needed to define the already-existing resource:
POST /user_settings/{user_id}/{which_settings_id}/{xyz}/{abc}/ ...
{
...
}
I'm looking into a restful design and would like to use the HTTP methods (POST, GET, ...) and HTTP headers as much as possible. I already found out that the HTTP methods PUT and DELETE are not supported from the browser.
Now I'm looking to get different representations of the same resource and would like to do this by changing the Accept header of the request. Depending on this Accept header, the server can serve a different view on the same resource.
Problem is that I didn't find a way to tell my browser to change this header.
The <a..> tag has a type attribute, that can have a mime type, looked like a good candidate but the header was still the browser default (in Firefox it can be changed in about:config with the network.http.accept.default key).
I would partially disagree with Milan's suggestion of embedding the requested representation in the URI.
If anyhow possible, URIs should only be used for addressing resources and not for tunneling HTTP methods/verbs. Eventually, specific business action (edit, lock, etc.) could be embedded in the URI if create (POST) or update (PUT) alone do not serve the purpose:
POST http://shonzilla.com/orders/08/165;edit
In the case of requesting a particular representation in URI you would need to disrupt your URI design eventually making it uglier, mixing two distinct REST concepts in the same place (i.e. URI) and making it harder to generically process requests on the server-side. What Milan is suggesting and many are doing the same, incl. Flickr, is exactly this.
Instead, a more RESTful approach would be using a separate place to encode preferred representation by using Accept HTTP header which is used for content negotiation where client tells to the server which content types it can handle/process and server tries to fulfill client's request. This approach is a part of HTTP 1.1 standard, software compliant and supported by web browsers as well.
Compare this:
GET /orders/08/165.xml HTTP/1.1
or
GET /orders/08/165&format=xml HTTP/1.1
to this:
GET /orders/08/165 HTTP/1.1
Accept: application/xml
From a web browser you can request any content type by using setRequestHeader method of XMLHttpRequest object. For example:
function getOrder(year, yearlyOrderId, contentType) {
var client = new XMLHttpRequest();
client.open("GET", "/order/" + year + "/" + yearlyOrderId);
client.setRequestHeader("Accept", contentType);
client.send(orderDetails);
}
To sum it up: the address, i.e. the URI of a resource should be independent of its representation and XMLHttpRequest.setRequestHeader method allows you to request any representation using the Accept HTTP header.
Cheers!
Shonzilla
I was looking to do exactly the same thing (RESTful web service), and I stumbled upon this firefox addon, which lets you modify the accept headers (actually, any request headers) for requests. It works perfectly.
https://addons.mozilla.org/en-US/firefox/addon/967/
I don't think it's possible to do it in the way you are trying to do it.
Indication of the accepted data format is usually done through adding the extension to the resource name. So, if you have resource like
/resources/resource
and GET /resources/resource returns its HTML representation, to indicate that you want its XML representation instead, you can use following pattern:
/resources/resource.xml
You have to do the accepted content type determination magic on the server side, then.
Or use Javascript as James suggests.
ModHeader extension for Google Chrome, is also a good option. You can just set the Headers you want and just enter the URL in the browser, it will automatically take the headers from the extension when you hit the url. Only thing is, it will send headers for each and every URL you will hit so you have to disable or delete it after use.
Use some javascript!
xmlhttp=new XMLHttpRequest();
xmlhttp.open('PUT',http://www.mydomain.org/documents/standards/browsers/supportlist)
xmlhttp.send("page content goes here");