Build a rest wrapper which accepts any kind of request - java

I want to build a rest wrapper in a spring boot application which accepts any kind of request (API call). Lets assume I have two API calls /employee/123 (GET method) /dept/123 (PUT method). Now When I hit these two requests from postman client, my wrapper should accepts these two types of requests.
I have tried this with Filter and Interceptor. But those didn't work for me. Can any one please explain how to do this.

Not quite clear what's your problem. Is this what you're looking for?
#RestController
public class SampleController {
#GetMapping(path = "/employee/{id}")
public String getEmployee(#PathVariable int id) {
....
}
#PutMapping(path = "/dept/{id}")
public String putDept(#PathVariable int id) {
....
}
}
Or you want an API proxy? So, perhaps, it makes sense to look at Zuul or any similar project?

if you want to accepts any kind of request like POST,GET,DELETE or PUT the dont mention the method of RequestMethod in #RequestMapping and if you want to do different operation depends on Request method then use HttpServletRequest for getting ReuestMethod
eg.
#RequestMapping({ "/employee/{id}", "/dept/{id}" })
public #ResponseBody String demo(HttpServletRequest request, #PathVariable("id") Integer id) {
if (request.getMethod().equalsIgnoreCase("POST")) {
return "POST MEhod";
} else if (request.getMethod().equalsIgnoreCase("GET")) {
return "GET Method";
} else if (request.getMethod().equalsIgnoreCase("PUT")) {
return "PUT Method";
} else {
return "DELETE Method";
}
}

Related

How to test with Postman a controller's method that has one or more objects parameters (and not simple params) in Spring?

I am a newbie in Spring development. I need to create a simple application, a controller that has a method that takes as parameter an object of a custom designed entity class into the project. The prototype looks like this:
#RestController
public class JobsController {
#PostMapping("/search")
public ResponseEntity<?> search() {
log.info("JobsController -> search method");
//JobSearchEntity jobSearchEntity = modelMapper.map(jobSearch, JobSearchEntity.class);
List<JobEntity> jobs = jobService.searchJobs();
//log.info(String.format("Job found: %s ", jobSearch));
return ResponseEntity.ok(jobs);
}
}
Can someone who is more advanced into this staff with Postman testing tell me how to do that , how to test a controller method which takes parameters?
You can use postman to submit parameters in JSON format after adding # requestbody annotation on the method, or submit parameters directly in form without annotation
You can use this example. Is very simple exemple.
#RestController
#RequestMapping("/root")
public class RootController {
private final RootService service;
public RootController(final RootService service) {
this.service = service;
}
#PostMapping("/exemple")
public void createRoot(#RequestBody final RootDto dto) {
service.createRoot(dto);
}
}
Then you can send request to POST host/root/exemple with your JSON.
More exampls you can find here: https://www.baeldung.com/spring-request-response-body
It seems you are missing an honest search on google about the subject.
You can make use of #RequestBody annotation to accept method arguments.
Check these page for examples --
#RequestBody and #ResponseBody annotations in Spring
https://stackabuse.com/get-http-post-body-in-spring/
https://www.twilio.com/blog/create-rest-apis-java-spring-boot
These set of playlist on youtube are very good starter course for SpringBoot -
https://www.youtube.com/c/JavaBrainsChannel/playlists
Postman Tutorial--
https://www.youtube.com/watch?v=VywxIQ2ZXw4
To get data from api is preferred to use GET method :
#RestController
public class JobsController {
#GetMapping("/search")
public ResponseEntity<?> search(#RequestParam("id") String id,#RequestParam("desc") String desc) {
log.info("JobsController -> search method");
//JobSearchEntity jobSearchEntity = modelMapper.map(jobSearch, JobSearchEntity.class);
List<JobEntity> jobs = jobService.searchJobs();
//log.info(String.format("Job found: %s ", jobSearch));
return ResponseEntity.ok(jobs);
}
}
you call this api with post man this way :
#PostMapping used usually to save new data (example : create job )
Take look on rest resource naming guide

Spring restful API, is there a method being used like router to get other method's end points or URL?

#RequestMapping("/accounts")
public class controller {
#GetMapping("/get/{id}")
public final ResponseEntity<?> getHandler(){
}
#PostMapping(value = "/create")
public final ResponseEntity<?> createHandler(){
/*
trying to use some spring library methods to get the url string of
'/accounts/get/{id}' instead of manually hard coding it
*/
}
}
This is the mock code, now I am in createHandler, after finishing creating something, then I want to return a header including an URL string, but I don't want to manually concat this URL string ('/accounts/get/{id}') which is the end point of method getHandler(), so I am wondering if there is a method to use to achieve that? I know request.getRequestURI(), but that is only for the URI in the current context.
More explanation: if there is some library or framework with the implementation of route:
Routes.Accounts.get(1234)
which return the URL for the accounts get
/api/accounts/1234
The idea is, that you don't need to specify get or create (verbs are a big no-no in REST).
Imagine this:
#RequestMapping("/accounts")
public class controller {
#GetMapping("/{id}")
public final ResponseEntity<?> getHandler(#PathVariable("id") String id) {
//just to illustrate
return complicatedHandlerCalculation(id).asResponse();
}
#PostMapping
public final ResponseEntity<?> createHandler() {
//return a 204 Response, containing the URI from getHandler, with {id} resolved to the id from your database (or wherever).
}
}
This would be accessible like HTTP-GET: /api/accounts/1 and HTTP-POST: /api/accounts, the latter would return an URI for /api/accounts/2 (what can be gotten with HTTP-GET or updated/modified with HTTP-PUT)
To resolve this URI, you could use reflection and evaluate the annotations on the corresponding class/methods like Jersey does.
A Spring equivalent could be:
// Controller requestMapping
String controllerMapping = this.getClass().getAnnotation(RequestMapping.class).value()[0];
and
//Method requestMapping
String methodMapping = new Object(){}.getClass().getEnclosingMethod().getAnnotation(GetMapping.class).value()[0];
taken from How do i get the requestmapping value in the controller?

Spring MVC: IP restriction for a single controller method

I need to hide a specific API for requests coming form IP different to a specific one.
For instance this should work if I try to use it and my IP is 192.168.1.1, but not if my IP is 192.168.1.2.
#RequestMapping(value = "/test/{id}", method = RequestMethod.GET)
#ResponseBody
#IpRestricted
public void download(#PathVariable("id") String id) {
...
}
I read I can make it creating a specific annotation, the one I called "#IpRestricted" in this example, but than how can I proceed? There are better solution to this?
I then realized I can make it without using spring security.
I made an annotation like this:
#Retention(RetentionPolicy.RUNTIME)
public #interface IpRestricted {
}
Than I check the request IP address inside a HandlerInterceptor preHandle method:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod)handler;
if (method.getMethodAnnotation(IpRestricted.class)!=null) {
if (!request.getRemoteAddr().equals("192.168.1.1")) {
throw new UnauthorizedException("Ip not authorized");
}
}
}
[....]
}
And for the download method:
#RequestMapping(value = "/test/{id}", method = RequestMethod.GET)
#ResponseBody
#IpRestricted
public void download(#PathVariable("id") String id) {
...
}
That's it!
I think the best Spring solution available for this case is the hasIpAddress() method from Spring Security. There are many different ways to configure permissions to your services via Spring Security, and the IP-based solution is also implemented.
Here is a good example of how to set it up.

Intecepting Rest Controller responses

I am building a REST service using spring boot. My controller is annotated with #RestController. For debugging purposes I want to intercept the ResponseEntity generated by each of the controller methods (if possible). Then I wish to construct a new ResponseEntity that is somewhat based on the one generated by the controller. Finally the new generated ResponseEntity will replace the one generated by the controller and be returned as part of the response.
I only want to be able to do this when debugging the application. Otherwise I want the standard response generated by the controller returned to the client.
For example I have the controller
#RestController
class SimpleController
#RequestMapping(method=RequestMethod.GET, value="/getname")
public NameObject categories()
{
return new NameObject("John Smith");
}
}
class NameObject{
private String name;
public NameObject(name){
this.name = name;
}
public String getName(){ return name; }
}
This will generate the response:
{"name" : "John Smith"}
But I would like to change the response to include status info of the actual response e.g:
{"result": {"name" : "John Smith"}, "status" : 200 }
Any pointers appreciated.
The way I would try to achieve such a functionality is first by creating an Interceptor. And example can be found here
Second, I would employ Spring profiles to ensure that interceptor is loaded only in profile that I needed it in. Detail here. It's not exaclty debugging, but might do the trick.
You can do this with spring AOP, something like:
#Aspect
#Component
public class ResponseEntityTamperer {
#Around("execution(* my.package.controller..*.*(..))")
public Object tamperWithResponseEntity(ProceedingJoinPoint joinPoint)
throws Throwable {
Object retVal = joinPoint.proceed();
boolean isDebug = java.lang.management.ManagementFactory.getRuntimeMXBean()
.getInputArguments().toString()
.contains("jdwp");
if(isDebug && retVal instanceof ReponseEntity) {
// tamper with the entity or create a new one
}
return retVal;
}
}
The "find out if we're in debug mode" code is from this answer.

2 Request Handlers for POST (ResponseBody + "Normal")

I like to implement a REST-API into my SpringMVC application. At the moment, I have one method to handle POST-Requests, which "returns" a rendered ViewScript.
#RequestMapping(method=RequestMethod.POST)
public String onSubmit(User user, Model model)
{
return "success";
}
It would be nice, to add a second method with the #ResponseBody Annotation for POST-Requests, e.g. to send a JSON-Response.
Furthermore, the old Method still has to exists, to handle "normal" Requests.
But a code like this doesn't work:
#RequestMapping(method=RequestMethod.POST)
public String onSubmit(User user, Model model)
{
return "success";
}
#RequestMapping(method=RequestMethod.POST)
#ResponseBody
public Object add(User user, Model model)
{
// [...]
return myObject;
}
With this code, I'm getting a 405 (Method Not Allowed) Error from Tomcat. How can I fix this?
As it stands, Spring has no way to differentiate between these two requests: same URL, same request method.
You can further differentiate by mimetype:
#RequestMapping(method=RequestMethod.POST, headers="content-type=application/json")
Although there are several mimetypes associated with JSON :/ The headers value takes an array, however, so you can narrow/widen it as necessary.
See the headers docs.
Dont USE TWO ANNOTATION. It is a poor option. Just have one more method without annotation. But the method from the old method by checking the below condition.
JUST PASS ONE MORE ARGUMENT FROM UI by query parameter(request="JSON_Request").
#RequestMapping(method=RequestMethod.POST)
public String onSubmit(User user, Model model)
{
if(request="JSON_Request") {
newMethod(user, model);
}
return "success";
}
private Object newMethod(User user, Model model)
{
// [...]
return myObject;
}

Categories