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.
Related
I have already created Rest Endpoint in Java spring boot. It returns appropriate response when I request it via Postman. But when I use react fetch it does not show any response in browser if return is Json.
Spring boot controller:
#RestController
#RequestMapping(path = "/v1/test")
#AllArgsConstructor(onConstructor_ = {#Autowired})
public class TestController {
...
}
Below endpoint is returning appropriate response.
#GetMapping(value = "/helloWorld", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public String getHelloWorld() {
return "Hello, World1!";
}
But when I try to hit below endpoint it returns null when I make fetch request. But it returns appropriate response when I hit it via postman.
#GetMapping(value = "/testEndpoint", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public String returnTestResponse() {
HashMap<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", "value2");
return "{\"a\":1, \"b\":\"foo\"}";
}
Also tried returning POJO object. But still no response.
#GetMapping(value = "/testModel", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public SearchResultsModel testModel() {
this.myService.getSearchResult();
}
React fetch call:
await fetch(ALL_ARTICLES_ENDPOINT, {
mode: 'no-cors',
method: 'GET',
redirect: 'follow',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
}).then(response => {
console.log(response);
})
.then(data => {
console.log('Success:', data);
}).catch((error) => {
console.error('Error:', error);
});
Postman have couple hidden headers which are being sent with all requests.
Check Hide auto-generated headers
What you are missing in react call is is Accept header with application/json value
EDIT:
Just saw that you are returning string as json. You need to wrap it in POJO object and return it in returnTestResponse class
SECOND EDIT:
This will work. Try to implement your POJO
#GetMapping(value = "/testEndpoint", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public YourObject returnTestResponse() {
HashMap<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", "value2");
return new YourObject(map);
}
Issue was caused by adding mode: 'no-cors' option in fetch request. This option helped me to get rid of cors error but it means that in return I won't be able to see body and headers in chrome.
To resolve the issue I removed mode: 'no-cors' and added #CrossOrigin annotation on my spring boot controller.
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);
}
I am trying to return response as JSON. After searching I found solution to add headers = "Accept=application/json" in RequestMapping. But still it is not working .
It is throwing error HTTP Status 406 "The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers."
Here is my controller code :
#RestController
public class EmployeeController {
private EmployeeService employeeService;
#Autowired(required = true)
#Qualifier(value = "employeeService")
public void setEmployeeService(EmployeeService employeeService){
this.employeeService = employeeService;
}
#RequestMapping(value = "/test",method = RequestMethod.GET)
public String test(){
return "{\"name\":\"xyz\"}";
}
#RequestMapping(value = "/employees",method = RequestMethod.GET,headers = "Accept=application/json")
public List<Employee> listEmployees(){
List<Employee> employees = this.employeeService.getEmployees();
return employees;
}
}
Where am I doing wrong?
The simple way to generate JSON, XML response is #ResponseBody annotation.
#RequestMapping(value =" /jsonPostSingle", method = RequestMethod.GET)
#ResponseBody
public PostModel generateJSONPostsingle(#ModelAttribute("postModel") PostModel postModel) {
if(postModel.getPostId() == 1) {
postModel.setTitle("post title for id 1");
} else {
postModel.setTitle("default post title");
}
return postModel;
}
This way you will be able to map your request to model class using #ModelAttribute.
Follow the complete tutorial Spring MVC : JSON response using #ResponseBody
I understand that you're trying to send a response from GET request of /employees.
if you are using Spring 3.1, try to use
#RequestMapping(value = "/employees",method = RequestMethod.GET, produces = "application/json")
instead of adding headers = "Accept=application/json"
More info:
if you want to specify type of data that will send with a request, you can use consumes attribute
example:
#RequestMapping(value="/foo", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
this will consumes and response with JSON type only
check this link about spring update http://spring.io/blog/2011/06/13/spring-3-1-m2-spring-mvc-enhancements/
Hope it helps
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
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.