How do I implement dry run option to a REST api so I have a way of knowing it is implemented? - rest

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

Related

Why HTTP Rest has different methods like GET, PUT, POST instead of just one or no method at all?

Why do we have different methods for HTTP request. GET can not send data(body) and can only request something only through URL params. Put is like changing a field value on the server and Post performs an operation everytime we execute it (concept of Idempotence).
Why can't there be one method or no method at all ?
Why can't there be just a simple HTTP request where we can send data if we want. Now it depends on server logic how it wants to process that request based on the request content (data / body). If the server wants to just execute it like a get request & return something or perform an operation like a POST request & return something. It would have been more simpler.
Why can't there be just a simple HTTP request where we can send data if we want
Because that's not how HTTP works. Each HTTP request has a required request method.
REST leverages this by reusing the semantics of the methods.
Why can't there be one method or no method at all ? Why can't there be just a simple HTTP request where we can send data if we want.
Because describing the semantics of the messages in a consistent way allows generic components to participate in a meaningful way.
For instance, the semantics of a given request are constrained by the common method properties; if the metadata of the message describes itself as idempotent, then generic participants know that, in the event that a response is lost, they can simply repeat the message.
Likewise, if a message is known to be safe, then each of the components know that the message can be dispatched speculatively -- allowing caches to prefetch representations that you may need, communicating to spiders that the content is safe for retrieval and so on.
The HTTP methods support finer grains of distinction; GET vs HEAD, PUT vs DELETE, POST vs PATCH. And of course there are extensions that support other semantics as well.
From the perspective of REST, it doesn't have to be a method per se, so long as the semantics are expressed in such a way that generic components can act on it. HTTP happens to have used methods.
The request method token is the primary source of request semantics; it indicates the purpose for which the client has made this request and what is expected by the client as a successful result.
You are absolutely right that no method at all would be much simpler. But it would also be a lot less powerful: you lose the ability to leverage generic components (like web browsers, caching proxies). The metadata constraints are what make the web possible.
It's all about the semantics of the request. From the RFC 7231:
The request method token is the primary source of request semantics;
it indicates the purpose for which the client has made this request
and what is expected by the client as a successful result.
Here's a brief description of some HTTP methods defined in the RFC 7231 (click the links to check the full method definition):
GET: Transfer a current representation of the target resource.
HEAD: Same as GET, but only transfer the status line and header section.
POST: Perform resource-specific processing on the request payload.
PUT: Replace all current representations of the target resource with the request payload.
DELETE: Remove all current representations of the target resource

restful service parameters in headers or body

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?

REST creation without persisting

Right now I have a REST service which creates a report via a POST:
POST http://myhost/reports
The report however is not persisted, and cannot later on be retrieved via a GET:
GET http://myhost/reports/{id}
Instead I return the report immediately in the response to the POST. Am I violating any REST principle here, e.g. anything a POST creates should always be accessible via a GET, or is this setup OK?
The POST method isn't a synonym to the create in CRUD. The POST method is used for any operation that isn't standardized, so as long as you document what it does, you're not violating REST, no matter what you do.
There's no such REST principle saying "anything a POST creates should always be accessible via a GET". This is a common misunderstanding due to conflating REST with CRUD. Read this answer for some clarification on that.
In informal language, what a POST says to the server is "take this data and apply it to the resource identified by the given URI, following the rules you documented for the resource media type."
No, you are not violating REST. As long as your interface is uniform it is up to you to determine what actions the urls of your API perform.
As part of your documentation you simply need to state which methods are valid for certain resources and which aren't. I really like to use the Twitter API as a good example of "What to do"
Example: Twitter REST API
POST statuses/update
does not create an object available for access at
GET statuses/update/3
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
So according to the HTTP standard this is okay.

Restful web service GET request parameters

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).

HTTP POST with URL query parameters -- good idea or not?

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}/ ...
{
...
}