We have several methods in a spring REST API that designed to handle requests that fit our API exactly, or allow for a trailing slash. We use this annotation:
#RequestMapping(value = {"", "/"}, produces = {"application/json"}, method = RequestMethod.POST)
#ResponseBody
public ClassName ...
When enunciate / swagger docs are generated, they have two items generated ("domain.com/api" and "domain.com/api/"), I am wondering if there is a way to tell enunciate to only show one?
Consider options for handling the mapping of "/api" and "/api/" at a deeper level instead of defining two endpoints in your Java class. I am sure there are many ways to map these as aliases, such as in web.xml.
Enunciate has the ability to ignore an entire class using the ignore annotation but this would require you to restructure your class definitions (in a beautiful and reusable way) so the two endpoints are handled by different classes, and then one you can annotate one with #Ignore.
Related
In my spring controller, I have 2 rest api methods. example: getUser, getRole
One client is accessing it by like "/api/v1".
Now I want to update one of the methods. i.e., getRole. So the new method/version will be "/api/v2".
But no change in methods of v1. i.e., "/api/v1".
How to handle the rest methods with both versions in the same project ?
I mean, getUser rest API should support both "/api/v1" and "/api/v2".
And getRole rest API should support both versions but different functionality (example: database changed, logic changed).
In simple words,
1. getUser will have 1 method which supports both versions.
2. getRole will have 2 methods for each versions.
Please help me here.
If you want to do use separate method for both version you can by defining different value in #RequestMapping
method 1
#RequestMapping(
value = "baseurl/v1/role",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
and
#RequestMapping(
value = "baseurl/v2/role",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
but if you want to handle it in same method you can using
method 2: use #PathVariable
#RequestMapping(
value = "baseurl/{version}/role",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public returnType methodName(#PathVariable("version") String version){
// code to check version
}
method 3: use #RequestHeader
#RequestMapping(
value = "baseurl/role",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public returnType methodName(#RequestHeader("version") String version){
// code to check version
}
But as you said you have different version of api's prefer to manage them in separate controller using #RequestMapping at class level
method 4:
#RestController
#RequestMapping("/v1")
public class anyController {
}
and
#RestController
#RequestMapping("/v2")
public class anyController {
}
It really depends on your use case and what all is changing. There are technically many different paths you can take, but I will describe two that sound like they would work for you.
Create path param for v1 and add conditional that checks to see if the path param is v2 and call different method.
Create new path for api/v2, add changes functionality and call v1 endpoint method.
This really gets into specifics and should probably be evaluated on which way you should take it, depending on how the existing code is implemented.
I would do the following approach
Define a version at the application level (Start with /v1) -- this version is changed only when you want to make bigger changes to your whole API and is usually stable.
Resources (roles, users) etc. should be versioned additionally using content negotiation via the headers
e.g.
GET /v1/users/503deb67-ff6e-4d1c-a225-408b910b7252/ HTTP/1.1
Accept: application/vnd.yourorg.users-v1+json
Here the client uses content negotiation for the specific resource she is interested in via the HTTP header
See https://www.mashery.com/blog/ultimate-solution-versioning-rest-apis-content-negotiation and http://blog.ploeh.dk/2015/06/22/rest-implies-content-negotiation/ for more details
There are many ways, but most likely you want to keep the code as decoupled as possible. This makes keeping the versions in separate classes a good option:
V1Controller.java:
#RestController
#RequestMapping("/api/v1")
public class V1Controller{
// version 1 api
}
V2Controller.java :
#RestController
#RequestMapping("/api/v2")
public class V2Controller{
// version 2 api
}
But for a even higher degree of decoupling you could have two different webapps deployed on the same Tomcat or Jetty server - version 1 under the context path "/api/v1" and version 2 on the context path "/api/v2". The webapps would simply be builds of different versions of the same code (or builds of different branches - if you're using git).
In Spring we've got #ExposesResourceFor annotation which can link our resource with other resources. Thanks to this our Value objects (representations) can know nothing of the actual resources.
Is there a way to do it in JAX-RS? I'm using Dropwizard with Jersey and Jackson and all I see is #InjectLinks annotation which I can use in a value object like this:
public class UserGroup {
#JsonProperty
public String name;
#InjectLinks(GroupsResource.class)
public URI myResource;
public UserGroup(String name){
this.name = name;
}
}
But unfortunatelly my Value Objects should know nothing about Resources, so I'm asking can I do such linking on the level of resources - link in spring-hateoas in controllers, as mentioned above.
With #InjectLinks, you don't have to declare the links in your model class. You can create a "wrapper" representation class, as shown in declarative-linking from the Jersey examples (though this solution is not really on the resource class level as you wish).
Another possible solution (rather than declarative linking) is to use the JAX-RS 2.0 Link class, and do the linking programmatically (with no ties to the Jersey implementation/annotations). You can either add the links to your response headers, as see here, or add Links to you model classes, as seen here (or use the wrapper class for this also, so as to not to invade your model classes)
Some Resources
Declarative Hyperlinking
Using Link for headers
I am new to spring framework. Even I dont have any deep concept about annotation.
I am developing a very small application using spring mvc 3 framework and also I used annotation.
I have a confusion. I have one spring-servlet.xml. Here I have not defined any handler mapping. But still it is working. So must be there some default handler mapping. Can you please let me what is this default handler mapping and how I can override it so that I do some customization.
It is all explained in: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-config
Also see this question: How to use default-servlet-handler and Where to put default-servlet-handler in Spring MVC configuration
Spring 3.1 and later doesnt need DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter declaration in the [servelt-name]-servlet.xml
These links might help:
Spring Controller to handle all requests not matched by other Controllers
https://dzone.com/articles/using-the-spring-requestmapping-annotation
I had the same problem that I just resolved so I have confirmed the approach below works, although this is with annotations rather than an XML configuration.
You specify URL prefixes at the controller class level and include a request mapping annotation for ** to ensure you match on anything that falls through your other handlers for this class. There's really nothing special or default about this handler other than the fact that you're defining a handler that is guaranteed to match everything under the class level mappings.
Note: This is not magic. Your handlers are still subject to Spring's ordering algorithm regarding the "best match". It would be nice to have an annotation providing for a true default when nothing else matches handler, especially in cases with complex mappings where "**" is useful outside of this catch-all handler. The basic implementation is:
#RestController
#RequestMapping(value={"/path1/","/path2/"})
public class MyRestController {
#RequestMapping("/subpath")
String matchedRequestHandler () {
return "This matches /path1/subpath and /path2/subpath.";
}
#RequestMapping("**")
String unmatchedRequestsHandler () {
return "This matches everything else.";
}
}
In my actual use case, I needed to handle arbitrary paths to resources inside of the URL pattern and therefore needed to support a variable number of directories. Ideally, that would be handled using a pattern such as:
"/base/{optionaldir}/**/{entityName}/{describeVar:describe.json}"
which works fine by itself, but it isn't compatible with a default handler bound to "**" since the "**" mapping is calculated by Spring as a better match for these types of requests.
Instead, I had to add a bunch of separate entries to my request mapping to support the arbitrary paths within the URL pattern, e.g.
value={"/base/{optionaldir}/{entityName}/{describeVar:describe.json}",
"/base/{optionaldir}/*/{entityName}/{describeVar:describe.json}",
"/base/{optionaldir}/*/*/{entityName}/{describeVar:describe.json}",
"/base/{optionaldir}/*/*/*/{entityName}/{describeVar:describe.json}"
}
Alternatively, I could have handled everything with a "**" mapping and parsed the URL myself, but that kind of defeats the purpose of using request mappings with path variables. Hopefully Spring's capabilities will evolve in this area in the future.
Imagine that I have a Spring MVC controller something like this:
#Controller
#RequestMapping("/base-url")
public class MyController{
//..snip
#RequestMapping(method=RequestMethod.GET, value="/edit/{id}")
public String edit(Model model, HttpServletRequest request, Authentication authentication){
//..snip
}
}
My question is regarding the inner value parameter to the #RequestMapping annotation at the function level. Is the pre-slash on /edit/{id} required, or does edit/{id} do the job just as well? I would have imagined that the pre-slash would set the request to be absolute, regardless of the class level mapping, but it seems to be ignored.
Is one or the other considered better practice?
In the Spring documentation, they seem to always use the pre-slash. Are there any practical benefits to doing that?
Thanks,
idb.
According to the spring documentation, having a class level #RequestMapping annotation implies that all method level #RequestMappings will be relative to that of the class'.
It might be nice however, to have the ability to override the relative mappings in some rare cases.
I personally prefer to add pre-slash in value of #RequestMapping. In code level you can see: If the value does not start with an / then Spring (DefaultAnnotationHandlerMapping) will add it. Details answer you can visit: Use or not leading slash in value for #RequestMapping. Need official docs or point to Spring source?
I would like to implement custom metric or statistics to my spring boot rest web service using actuator but i am not able to find simple tutorials.
For example:
how to show how many times a certain controller was called and what exact parameter field was filled?
how can i create a metric that when its URL is called, it runs certain query and shows back a json with some result
This seems like a good scenario for AOP (Aspect Oriented Programing) as this will allow you to separate this statistic logic from the business logic.
Have a look at Spring doc for more info about AOP and how to achieve that with Spring.
You can then define a pointcut on your controller and have a service for counting (and probably then storing) the data.
Refer below link
AOP Example
For point two the solution is to create an endpoint class (it can be or not a rest controller class). For example:
#Component
#RestControllerEndpoint(id = "pfm-statistics")
public class StatisticsEndpoint {
#GetMapping(value = "/", produces = "application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet")
#ResponseBody
public byte[] generateStatisticsAsExcel() {
...
Note that the ID is the path to be called from URL. We can create a simple endpoint too and just return a string if we want. In this case instead of #RestControllerEndpoint annotation we can use #Endpoint, as a side note, the id should always contain dash