Spring : Responding to a REST-ful API call - java

I am trying to implement REST API endpoints in y application.
#Controller
public class HerokuController {
#RequestMapping(value = "/heroku/resources/", method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<JSONObject> provision(#RequestBody JSONObject body){
System.out.println("called! \n");
JSONObject response = new JSONObject();
response.put("id", 555);
response.put("message", "Provision successful!");
return new ResponseEntity<JSONObject>(response,HttpStatus.OK);
}
So I wrote this class containing a method which mapping is (heroku/ressources).
But when I try to call it, I get a 404 error because /WEB-INF/heroku/resources.jsp not found. However, I don't even want to get a view but a HTTP response.
Can anyone tell me which configuration file should we generally modify to tell Spring that this controller doesn't want to send back a view but a HTTP response?
The method is however called if I change it to this :
#RequestMapping(value = "/heroku/resources/", method = RequestMethod.POST)
public ModelAndView provision(final HttpServletRequest request){
System.out.println("called! \n");
JSONObject response = new JSONObject();
response.put("id", 555);
response.put("message", "Provision successful!");
final Map<String, Object> result = new HashMap<String, Object>();
return new ModelAndView("jsonView",result);
}
So changing the return type to "ModelAndView".
thanks.

You are missing the #ResponseBody
#RequestMapping(value = "/heroku/resources/", method = RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ResponseEntity<JSONObject> provision(#RequestBody JSONObject body){
System.out.println("called! \n");
JSONObject response = new JSONObject();
response.put("id", 555);
response.put("message", "Provision successful!");
return new ResponseEntity<JSONObject>(response,HttpStatus.OK);
}

I had the same problem once, for fix that you can use #RestController instead of #controller (this will send Json by default) and you can definy your method like this
#RequestMapping(value = "/heroku/resources/", method = RequestMethod.POST)
public JsonOut provision(#RequestBody JsonIn json)
I always made my object with the value that i will get from the client, and alway the definition of the output
Ex
public class JsonOut{
protected String id;
protected String message;
...set ....get
}
and you have to put in the spring xml file this two value
<mvc:annotation-driven />
<context:annotation-config/>
With this configuration you will have json always!
This will work with spring 4, i dont know if with spring 3 will work

Related

Return XML or JSON from a REST controller based on request parameters

This is my controller:
#PostMapping(value = "/endpoint", produces = { APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE})
#ResponseBody
public Result generateResult(#Valid #RequestBody Request request) throws JsonProcessingException {
Result result = new Result();
// some code here
return result;
}
and this is my Request class:
#Data
#NoArgsConstructor
public class Request {
#NotNull
private String name;
private String type = "application/json";
}
the controller produces the correct output based on the Accept header in the request sent by the client. However, I want to send no Accept header and only send the following request:
{
"name": "my name",
"type": "application/xml"
}
Then based on the type the correct format should be output. I tried to add HttpServletResponse response to the parameter list of the controller method and then set the content type like this:
response.setHeader(CONTENT_TYPE, request.geType());
but it always returns json. any idea what else I should do?
I think a standard Spring's ResponseEntity builder give you all needed variety:
return ResponseEntity
.ok(//any object for json structure)
.headers(//any header)
.build();
Instead .ok() you can you any other method (that's http status code)
or
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.OK);
based on the comments I post this answer which worked for me. I changed my controller method like this:
#PostMapping(value = "/endpoint", produces = { APPLICATION_JSON_VALUE,
APPLICATION_XML_VALUE})
#ResponseBody
public ResponseEntity<Result> generateResult(#Valid #RequestBody Request request)
throws JsonProcessingException {
Result result = new Result();
// some code here
return ResponseEntity.accepted()
.headers(headers)
.body(result);
}

How can I make a Put rest call along with POJO using RestTemplate

How can I make a PUT request to a rest service using RestTemplate, so that I get a response also.
The rest service I have to call is:
#RequestMapping(value = /forgotpassword, method = RequestMethod.PUT, produces = "application/json")
public SuccessResponse resetUserPassword(#RequestBody ResetPasswordDTO resetPasswordDTO) throws GenericException {
logger.info("--->reset Password");
return new SuccessResponse(userservice.resetUserPassword(resetPasswordDTO));
}
I need to send one POJO also which has two String properties.
The method put of RestTempalte in (Spring)[https://spring.io/] has no return,so if your want get response from server,please try use POST method.I modify your code like this:
In server side:
#RequestMapping(value = "/forgotpassword", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<SuccessResponse> resetUserPassword(#RequestBody ResetPasswordDTO resetPasswordDTO) throws Exception {
log.info("--->reset Password");
SuccessResponse response = new SuccessResponse();
response.setName(resetPasswordDTO.getUsername());
response.setMessage("success");
return new ResponseEntity<SuccessResponse>(response, HttpStatus.OK);
}
In client side you can use RestTemplate do a request:
ResetPasswordDTO request = new ResetPasswordDTO();
request.setPasswork("Huawei#123");
request.setUsername("c00382802");
ResponseEntity<SuccessResponse> response =template.postForEntity("http://localhost:8080//forgotpassword",request,SuccessResponse.class);
System.out.println(response.getBody().toString());
More info you can get from (Spring)[https://spring.io/]
For PUT use RestTemplate.exchange() method
Example
MyJaxbRequestDataObjectrequest = createMyJaxbRequestDataObject();
Map<String, String> uriArguments= createUriArguments();
String url = restBaseUrl + "/myputservice/{usertId}?servicekey={servicekey}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<MyJaxbRequestDataObject> entity = new HttpEntity<MyJaxbRequestDataObject>(request, headers);
ResponseEntity<MyJaxbResponseDataObject> responseWrapper = shogunRestTemplate.exchange(url, HttpMethod.PUT, entity, MyJaxbResponseDataObject.class, uriArguments);
MyJaxbResponseDataObjectresponse = responseWrapper.getBody();

Using RestTemplate in spring-boot returns with 404

I am trying to send a body in a post request in a springboot application using rest template. Here is the controller:(I removed #RequestBody because I used application/x-www-form-urlencoded header)
#RestController
#CrossOrigin
#RequestMapping("/api")
public class SentimentParserController {
#Autowired
private SentimentParserService sentimentParserService;
#RequestMapping(value = "/something", method = RequestMethod.POST, consumes="application/x-www-form-urlencoded")
public ResponseEntity<mcResponse>getTheSentiments( mcSentimentRequestDTO sentimentRequestDTO){
return sentimentParserService.getSentimentsMc(sentimentRequestDTO);
}
}
I want to send the sentimentRequestDTO object(lang, key, and text) as the body in a post request to get the mcResponse:
public mcResponse parseTheSentiments(String text, Languages lang, String key) throws Exception {
RestTemplate restTemplate = new RestTemplate();
String request = "http://localhost:8080";
mcSentimentRequestDTO mSentiments =new mcSentimentRequestDTO(key,"EN",text);
HttpHeaders headers = new HttpHeaders();
headers.add("content-type", "application/x-www-form-urlencoded");
MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
map.add("key", key);
map.add("txt", text);
map.add("lang", Languages.ENGLISH.toString());
HttpEntity<MultiValueMap<String, String>> request1 = new HttpEntity<MultiValueMap<String, String>>(map, headers);
mcResponse response = restTemplate.postForObject(request, request1 , mcResponse.class );
return response;
}
However, I am getting the following error: 404 null.
Can you please help me? Thanks in advance
and here is the service class:
public ResponseEntity<mcResponse> getSentimentsMc(mcSentimentRequestDTO sentimentRequestDTO){
ResponseEntity<mcResponse> dto = null;
try {
dto = sentimentConverter.getTheSentiments(mcsParser.parseTheSentiments(sentimentRequestDTO.getText(),
Languages.ENGLISH, sentimentRequestDTO.getKey()));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return dto;
}
Looks like variable request should be
String request = "http://localhost:8080/something";
Also if controller class has prefix, this prefix also should be in request.
I mean if your class looks like this
#RestController
#RequestMapping("/myApi")
public class CertificateController {
....
#RequestMapping(value = "/something", method = RequestMethod.POST)
public ResponseEntity<mcResponse>getTheSentiments( mcSentimentRequestDTO sentimentRequestDTO){
return sentimentParserService.getSentimentsMc(sentimentRequestDTO);
}
Then request should be
String request = "http://localhost:8080/myApi/something";
It sounds like the controller isn't getting included in the spring context. If you just have an app annotated with #SpringBootApplication, then make sure that your controller is in a package that is the same as or lower than your annotated application.
To check the controller is being picked up you can add the following logging options to your application.properties
logging.level.org.springframework.beans=debug
logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping=trace
When your server starts up you should see something like the following in the log
1. To show the controller is in the spring-context
DefaultListableBeanFactory : Creating shared instance of singleton bean 'sentimentParserController'
2. To show the mapping for the /api/something url
RequestMappingHandlerMapping : Mapped 1 handler method(s) for class SentimentParserController: {public org.springframework.http.ResponseEntity SentimentParserController.getTheSentiments(mcSentimentRequestDTO)={[/api/something],methods=[POST]}}
If you see both of these, then what you say you're doing should work. Just make sure you are sending the request to /api/something and the server is running on port 8080.

Java Spring rest return unauthorized json

Currently have a java spring application in development. It utilizes a ui along with restful apis which send/receive json via post requests.
Each api request needs to be validated with a token which will be sent with the request. This action is completed and a boolean is returned. Now the problem is when the boolean value is false(token not valid) I need to return a 401 error to the end user. Currently I am returning List which is being converted to json. How can I return some 401 error to the end user.
Example
//done
#RequestMapping(value = "/getSomething"
, method = RequestMethod.POST
, consumes = "application/json"
, produces = "application/json")
#ResponseBody
public List<Obj> getSomething(#RequestBody Input f) {
DAOImpl dAOImpl = (MapDAOImpl) appContext.getBean("DAOImpl");
Boolean res = dAOImpl.validateToken(f.session);
if(res) {
List<Obj> response = dAOImpl.getSomething(f.ID);
return response;
} else {
return new ResponseEntity<String>("test", HttpStatus.UNAUTHORIZED);
}
}
You just need to change your return type to ResponseEntity.
#RequestMapping(value = "/getSomething"
, method = RequestMethod.POST
, consumes = "application/json"
, produces = "application/json")
#ResponseBody
public ResponseEntity<?> getSomething(#RequestBody Input f) {
DAOImpl dAOImpl = (MapDAOImpl) appContext.getBean("DAOImpl");
Boolean res = dAOImpl.validateToken(f.session);
if(res) {
List<Obj> response = dAOImpl.getSomething(f.ID);
return new ResponseEntity<>(response, HttpStatus.OK);
}
return new ResponseEntity<String>("Unauthorized", HttpStatus.UNAUTHORIZED);
}
Note : I would recommend to pass proper JSON in error response so that client can parse and use if required.

In Spring, Is there a way to return different Content-Type values for the header?

I would like to set the produces = text/plain to produces = application/json when I encounter an error.
#RequestMapping(value = "/v0.1/content/body", method = RequestMethod.GET, produces = "text/plain")
#ResponseBody
public Object getBody(#RequestParam(value = "pageid") final List<String> pageid, #RequestParam(value = "test") final String test) {
if (!UUIDUtil.isValid(pageid)) {
Map map = new HashMap();
map.put("reason", "bad pageId");
map.put("pageId", pageId);
map.put("test", test);
return new ResponseEntity<Object>(map, HttpStatus.BAD_REQUEST);
}
return "hello";
}
The problem with this code is that it doesn't print the error as json when I send an invalid pageId. It gives me a HTTP 406 error Not acceptable, because it expects to produce text/plain but I didn't return a String.
The cleanest way to handle errors is to use #ExceptionHandler:
#ExceptionHandler(EntityNotFoundException.class) //Made up that exception
#ResponseBody
#ResponseStatus(value = HttpStatus.NOT_FOUND)
public ErrorObject handleException(Exception e) {
return new ErrorObject(e.getMessage());
}
Then assuming you've configured your resolvers properly and put the right JSON serialization library in the classpath, the instance of ErrorObject will be returned to the client as a JSON response.
Of course you can set up multiple #ExceptionHandler methods as needed.

Categories