Two identical REST mappings with different HTTP request types - rest

Let's assume we have two methods on the REST controller:
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "/{userId}", method = RequestMethod.GET)
#ResponseBody
public UserDTO showUserDetails(#PathVariable("userId") Long userId) {
/* code here */
}
#ResponseStatus(HttpStatus.ACCEPTED)
#RequestMapping(value = "/{userId}", method = RequestMethod.POST)
#ResponseBody
public UserDTO editUser(#PathVariable("userId") Long userId, UserDTO userToEdit) {
/* code here */
}
So we have two identical URIs mappings, but supporting different HTTP requests. My question is: is this approach acceptable in terms of designing APIs? Or it is better to map second method to something like /{userId}/edit ?
Also, when using hateoas paradigm, the response will look somewhat strange:
"links":[{"rel":"self","href":"http://1localhost:8080/root/users/1"},{"rel":"edit","href":"http://localhost7:8080/root/users/1"}]
With 2 different URIs looking identical.

In terms of REST API design, you mapping is correct. For a given resource, you should interact with it via a single URI, In you example:
http://localhost:8080/root/users/1
And specify the operation via HTTP verbs.
Check the RESTful API HTTP methods in REST - Applied to web services, for an example.

I would definitely change the request mappings. For your editUser I'd add a /edit/ so your URL would look like http://localhost7:8080/root/users/edit/1
For the show you could add a /view/ to the URL, but that's not really necessary, but for the edit I'd personally prefer to have the URL be selfexplanatory

From a REST perspective what matters that you use the proper HTTP method and a single resource identifier (URL) is mapped only to a single resource. The URL structure does not matter. It matters only for you by routing the requests.
Your choice of method is bad. By edit you have to use PUT (full) or PATCH (partial) instead of POST. If you cannot use these methods because of some purposes (for example you use plain HTML forms to send requests), then you should use method override. For example send the real method in a _method param, in the body, in the query, or in a header. (It does not really matter which you choose because it is already an ugly workaround. Most ppl prefer the query.)
By choosing the URL most ppl prefer to use only nouns. This is because you don't map URLs to operations (like SOAP RPC), which are verbs (and probably nouns). For example POST /GetCurrentPrice. You map URLs to web resources, which are nouns for example GET /currentPrice.
REST is pretty simple. It uses existing standards to describe an uniform interface. Sadly most web developers do not know the HTTP standard. You should read at least the HTTP method definitions, the HTTP status code definitions and the URI RFC. These are the basics by REST.

Related

Best practice for including common http error codes in swagger / openapi definition

I'm wondering about good practices about including common error types in Swagger/OpenAPI definition.
Let's consider following controller method:
[HttpGet]
[ProducesResponseType(StatusCodes.Status400BadRequest)] // to be or not to be?
public ActionResult SomeMethod(Foo foo)
{
if (foo.Property != "expectedValue")
{
return BadRequest();
}
return Ok();
}
So, I'm performing some logic in the controller, which might end up in a state in which I want to return 400 BadRequest. Note, that I don't return any content.
Since I develop a REST API that generates Swagger/OpenAPI definition and tools like autorest may be used to generate client code based on that definition, I want to be sure it is as accurate as possible.
My question is:
should I declare explicitly that the user might get 400 Bad Request
OR
this makes sense only in case I want to describe the format of response content (in case 400Bad request has some content)
The same applies to codes like 401, 404 etc.
Even if (in addition to the returned http code, 400, 401, etc..) you do not return any payload at all, you should yet explicitly declare such responses.
Do not forget that in a "code-first" approach, your build chain could automatically generate the OpenApi contract (based on your code) as well as a nice user documentation.
In the contrary approach (contract-first), the code generated based on your OpenApi file would contain these response descriptions.
If you plan to use client code generation, then it's always better to use these declarations, because code generators (like autorest or NSwag) can use this information (usually from a swagger definition aka swagger.json) to generate more correct responses and error handling procedures.
Here, for example, you can see what can happen if you omit such declarations.
Also, remember, that in API controllers you can use web API conventions.
It says that these conventions allow you to:
Define the most common return types and status codes returned from a specific type of action.
Identify actions that deviate from the defined standard.
So, generally speaking, they can help you to make your code more concise.
The object BadRequest is used as a response (Result) with StatusCode=400.
DotNet has several response types with predefined StatusCode, so you can use different methods, for example:
NotFound(404):https://learn.microsoft.com/en-us/dotnet/api/system.web.http.apicontroller.notfound?view=aspnetcore-2.2
InternalServerError(500):https://learn.microsoft.com/en-us/dotnet/api/system.web.http.apicontroller.internalservererror?view=aspnetcore-2.2
Or simply use StatusCode for any other code that is not predefined:https://learn.microsoft.com/en-us/dotnet/api/system.web.http.apicontroller.statuscode?view=aspnetcore-2.2

What REST action should I use for Validate?

I have a design question on REST. I need to expose a validate method as a rest resource. Let us say it looks like this
public ValidatedResult validate(ObjectToBeValidated object)
ObjectToBeValidated is a class that contains the actual Object and also some parameters concerning the validation.
When I design this as a Restful resource, which action do I use? From my understanding GET is the action that best suits this case. If that is so, how I can pass my ObjectTobeValidated as an object but not as URL parameters? I shy away from URL parameters because ObjectToBeValidated may contain a lot of properties, ending up with an URL like below which is feel is too long
http://localhost/rest/validate?prop1=somevalu&prop2=somevalue&prop3=something&prop11=somevalu&prop22=somevalue&prop33=something
Any help would be appreciated
Thanks
Kay
The HTTP standard allows you to use the POST method. It does not necessary need to have a side effect.
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.
HTTP 1.1 / method definitions / POST
In your case you can do something like this if you want to follow the noun-verb approach Tim suggested:
POST /api/my/object/validator
Be aware that by REST the messages must be self-descriptive, so either you need a vendor MIME type or you need to add meta-data e.g. RDF to describe what this link does and what params are allowed. Otherwise we are not talking about REST, just a regular webapp.

REST Best practices

For REST service is it a best practice to accept the complete Request as input to your service (as below - Option- A) or should we accept individual parameters as in option - B:
Option - A:
#GET
#Produces("text/plain")
public String hello(#Context HttpServletRequest req) {
}
Option - B
#GET
#Produces("text/plain")
public String hello(#PathParam("id") int id, #BeanParam etc.) {
}
I think it's better to leverage support provided by JAX-RS to extract content from request than working directly on the request object. This will remove some technical plumbing and you will be able to focus on your own processing.
Moreover the Servlet API isn't really REST oriented. I mean, for example, regarding path variables / parameters, you need to extract them by your own.
Hope it helps you,
Thierry
A rest resource is generally identified by its name and the path parameters(optional).
Example : /tweets/{123} - This indicates 'Give me a tweet from the tweets collection identified by its id(123)'
The rest style of design might not mandate the service provider to expose the resource through path/query parameters but the general idea is that the path parameters uniquely identify a resource and query parameters are to be used as filters.
In your case, the obvious choice would be is to go for path parameters but you should use the injected request object only for the purpose of keeping track of things like remote user, session id etc.. which would not be used to identify the resource but something which will be used internally.

Does my application considered as restful?

I created a page called api.aspx
I am displaying my output using a JSON serialize.
Each type of function is based on query string. For example:
If Request.QueryString("action") = "getMember"
Then from there, I do a
Request.QueryString("memberid")
For the variable I required for my function to work. Lastly the output is displayed as JSON.
In REST, there should be no verbs in the URI, especially no things such as ?action=getMember. The core REST principle is HATEOAS - which says that the state of the application is represented by the state of its resources.
Furthermore, the application should use a uniform interface - that is, use the standard HTTP methods POST, GET, PUT and DELETE for CRUD operations respectively.
So, such a member resource from your example should be accessed via GET request to a URI such as:
http://example.com/api/member/{memberId}
Where {memberId} is path parameter that represents the memberId.
I would say it's not restful since the url scheme is depending on query string parameters. For a real restful API the url's shoud be http://asite/member/2 and not be named.
If you want to make your api truly restful, use the URL routing from ASP.NET MVC, it's possible to integrate with webforms.

How to version REST URIs

What is the best way to version REST URIs? Currently we have a version # in the URI itself, ie.
http://example.com/users/v4/1234/
for version 4 of this representation.
Does the version belong in the queryString? ie.
http://example.com/users/1234?version=4
Or is versioning best accomplished another way?
Do not version URLs, because ...
you break permalinks
The url changes will spread like a disease through your interface. What do you do with representations that have not changed but point to the representation that has? If you change the url, you break old clients. If you leave the url, your new clients may not work.
Versioning media types is a much more flexible solution.
Assuming that your resource is returning some variant of application/vnd.yourcompany.user+xml all you need to do is create support for a new application/vnd.yourcompany.userV2+xml media type and through the magic of content negotiation your v1 and v2 clients can co-exist peacefully.
In a RESTful interface, the closest thing you have to a contract is the definition of the media-types that are exchanged between the client and the server.
The URLs that the client uses to interact with the server should be provided by the server embedded in previously retrieved representations. The only URL that needs to be known by the client is the root URL of the interface. Adding version numbers to urls only has value if you construct urls on the client, which you are not suppose to do with a RESTful interface.
If you need to make a change to your media-types that will break your existing clients then create a new one and leave your urls alone!
And for those readers currently saying that this makes no sense if I am using application/xml and application/json as media-types. How are we supposed to version those? You're not. Those media-types are pretty much useless to a RESTful interface unless you parse them using code-download, at which point versioning is a moot point.
I would say making it part of the URI itself (option 1) is best because v4 identifies a different resource than v3. Query parameters like in your second option can be best used to pass-in additional (query) info related to the request, rather than the resource.
Ah, I'm putting my old grumpy hat on again.
From a ReST perspective, it doesn't matter at all. Not a sausage.
The client receives a URI it wants to follow, and treats it as an opaque string. Put whatever you want in it, the client has no knowledge of such a thing as a version identifier on it.
What the client knows is that it can process the media type, and I'll advise to follow Darrel's advice. Also I personally feel that needing to change the format used in a restful architecture 4 times should bring huge massive warning signs that you're doing something seriously wrong, and completely bypassing the need to design your media type for change resiliance.
But either way, the client can only process a document with a format it can understand, and follow links in it. It should know about the link relationships (the transitions). So what's in the URI is completely irrelevant.
I personally would vote for http://localhost/3f3405d5-5984-4683-bf26-aca186d21c04
A perfectly valid identifier that will prevent any further client developer or person touching the system to question if one should put v4 at the beginning or at the end of a URI (and I suggest that, from the server perspective, you shouldn't have 4 versions, but 4 media types).
You should NOT put the version in the URL, you should put the version in the Accept Header of the request - see my post on this thread:
Best practices for API versioning?
If you start sticking versions in the URL you end up with silly URLs like this:
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/
And there are a bunch of other problems that creep in as well - see my blog:
http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html
These (less-specific) SO questions about REST API versioning may be helpful:
Versioning RESTful services?
Best practices for web service REST API versioning
There are 4 different approaches to versioning the API:
Adding version to the URI path:
http://example.com/api/v1/foo
http://example.com/api/v2/foo
When you have breaking change, you must increment the version like: v1, v2, v3...
You can implement a controller in you code like this:
#RestController
public class FooVersioningController {
#GetMapping("v1/foo")
public FooV1 fooV1() {
return new FooV1("firstname lastname");
}
#GetMapping("v2/foo")
public FooV2 fooV2() {
return new FooV2(new Name("firstname", "lastname"));
}
Request parameter versioning:
http://example.com/api/v2/foo/param?version=1
http://example.com/api/v2/foo/param?version=2
The version parameter can be optional or required depending on how you want the API to be used.
The implementation can be similar to this:
#GetMapping(value = "/foo/param", params = "version=1")
public FooV1 paramV1() {
return new FooV1("firstname lastname");
}
#GetMapping(value = "/foo/param", params = "version=2")
public FooV2 paramV2() {
return new FooV2(new Name("firstname", "lastname"));
}
Passing a custom header:
http://localhost:8080/foo/produces
With header:
headers[Accept=application/vnd.company.app-v1+json]
or:
headers[Accept=application/vnd.company.app-v2+json]
Largest advantage of this scheme is mostly semantics: You aren’t cluttering the URI with anything to do with the versioning.
Possible implementation:
#GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v1+json")
public FooV1 producesV1() {
return new FooV1("firstname lastname");
}
#GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v2+json")
public FooV2 producesV2() {
return new FooV2(new Name("firstname", "lastname"));
}
Changing Hostnames or using API Gateways:
Essentially, you’re moving the API from one hostname to another. You might even just call this building a new API to the same resources.
Also,you can do this using API Gateways.
I wanted to create versioned APIs and I found this article very useful:
http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http
There is a small section on "I want my API to be versioned". I found it simple and easy to understand. The crux is to use Accept field in the header to pass version information.
If the REST services require authentication before use, you could easily associate the API key/token with an API version and do the routing internally. To use a new version of the API, a new API key could be required, linked to that version.
Unfortunately, this solution only works for auth-based APIs. However, it does keep versions out of the URIs.
If you use URIs for versioning, then the version number should be in the URI of the API root, so every resource identifier can include it.
Technically a REST API does not break by URL changes (the result of the uniform interface constraint). It breaks only when the related semantics (for example an API specific RDF vocab) changes in a non backward compatible way (rare). Currently a lot of ppl do not use links for navigation (HATEOAS constraint) and vocabs to annotate their REST responses (self-descriptive message constraint) that's why their clients break.
Custom MIME types and MIME type versioning does not help, because putting the related metadata and the structure of the representation into a short string does not work. Ofc. the metadata and the structure will frequently change, and so the version number too...
So to answer your question the best way to annotate your requests and responses with vocabs (Hydra, linked data) and forget versioning or use it only by non backward compatible vocab changes (for example if you want to replace a vocab with another one).
I'd include the version as an optional value at the end of the URI. This could be a suffix like /V4 or a query parameter like you've described. You might even redirect the /V4 to the query parameter so you support both variations.
I vote up for doing this in mime type but not in URL.
But the reason is not the same as other guys.
I think the URL should be unique (excepting those redirects) for locating the unique resource.
So, if you accept /v2.0 in URLs, why it is not /ver2.0 or /v2/ or /v2.0.0? Or even -alpha and -beta? (then it totally becomes the concept of semver)
So, the version in mime type is more acceptable than the URL.