Spring Rest Service Return Type - ajax

I have a rest service in spring which can return a string or a json. For this in my js code while sending the ajax request, i have specified datatype as "*". I wanted to know how can i handle this in spring service

All produces type are available in org.springframework.http.MediaType and for your requirement you can pass */*.
Constant for that is MediaType.ALL_VALUE in java code.
But if you know that your service always return JSON then I prefer to use MediaType.APPLICATION_JSON_UTF8_VALUE instead of MediaType.ALL_VALUE.

you can add attribute " produces" on your RequestMapping annotation:
#RequestMapping(value = "/yourPath", method = GET,
produces = { "application/json", "application/xml",....all what you want as type})

Related

Can I transform the input of a json inside a spring boot controller?

I have a very simple spring boot web application which consumes requests with json body.
For each json which the application will receive (from any client) I would like to manipulate it as a first step.
For example if the client sends the following body:
{
"hello": "world!!!"
}
I would like to replace each ! with a ?. In this case the result is:
{
"hello": "world???"
}
This json transformation should be valid for each controller and for any json entering the system.
Is this kind of operation possible?
Thanks.
You may use string.replace to do the same.
Or also you can add custom annotation to manipulate the values of any keys.
You can use any replacement methods or regex in your classes.
#GetMapping
public String replace(RequestItem item){
// item = item.regex/replacement method
// call your service or whatever
return item;
}
When you got the data, you can do whatever you want to do.

How to get Swagger UI to display similar Spring Boot REST endpoints?

I have a controller class with two endpoints
#RestController
#RequestMapping
public class TestController {
#RequestMapping(
value= "/test",
method = RequestMethod.GET)
#ResponseBody
public String getTest() {
return "test without params";
}
#RequestMapping(
value= "/test",
params = {"param"},
method = RequestMethod.GET)
#ResponseBody
public String getTest(#PathParam("param") int param) {
return "test with param";
}
}
One has a parameter, one doesn't, and the both work.
If I use curl or a web browser to hit the endpoints
http://localhost:8081/test
returns
test without params
and
http://localhost:8081/test?param=1
returns
test with param
but the swagger ui only shows the one without a parameter.
If I change the value in the request mapping for the request with a parameter to
#RequestMapping(
value= "/testbyparam",
params = {"param"},
method = RequestMethod.GET)
Swagger UI displays both endpoints correctly, but I'd rather not define my endpoints based on what swagger will or won't display.
Is there any way for me to get swagger ui to properly display endpoints with matching values, but different parameters?
Edit for Clarification:
The endpoints work perfectly fine; /test and /test?param=1 both work perfectly, the issue is that swagger-ui won't display them.
I would like for swagger ui to display the endpoints I have defined, but if it can't, then I'll just have to live with swagger-ui missing some of my endpoints.
Edit with reference:
The people answering here: Proper REST formatted URL with date ranges
explicitly say not to seperate the query string with a slash
They also said "There shouldn't be a slash before the query string."
The issue is in your Request Mapping, The second method declaration is overriding the first method. As Resource Mapping value is same.
Try changing the second method to below. As you want to give input in QueryParam rather than path variable, you should use #RequestParam not #PathParam.
Note that you have to give /test/, In order to tell Spring that your mapping is not ambiguous. Hope it helps.
#RequestMapping(
value= "/test/",
method = RequestMethod.GET)
#ResponseBody
public String getTest (#RequestParam("param") int param) {
return "test with param"+param;
}
Upon reading clarifications, the issue here is that swagger-ui is doing the correct thing.
You have two controller endpoints, but they are for the same RESOURCE /test that takes a set of optional query parameters.
Effectively, all mapped controller endpoints that have the same method (GET) and request mapping (/test) represent a single logical resource. GET operation on the test resource, and a set of optional parameters which may affect the results of invoking that operation.
The fact that you've implemented this as two separate controller endpoints is an implementation detail and does not change the fact that there is a single /test resource that can be operated upon.
What would be the benefit to consumers of your API by listing this as two separate endpoints in swagger UI vs a single endpoint with optional parameters? Perhaps it could constrain the set of allowed valid query parameters (if you set ?foo you MUST set &bar) but this can also be done in descriptive text, and is a much more standard approach. Personally, I am unfamiliar with any publicly documented api that distinguishes multiple operations for the same resource differentiated by query params.
As per Open API Specification 3
OpenAPI defines a unique operation as a combination of a path and an
HTTP method. This means that two GET or two POST methods for the same
path are not allowed – even if they have different parameters
(parameters have no effect on uniqueness).
Reference - https://swagger.io/docs/specification/paths-and-operations/
This was also raised as an issue but it was closed because OAS3 doesn't allow that -
https://github.com/springdoc/springdoc-openapi/issues/859
Try including the param in the path as below.
#GetMapping("/test/{param}")
public String getTest(#PathVariable final int param) {
return "test with param";
}
I'm unclear exactly what you're attempting to do, but I'll give two solutions:
If you want to have PATH parameters e.g. GET /test & GET /test/123 you can do:
#GetMapping("/test")
public String getTest() {
return "test without params";
}
#GetMapping("test/{param}")
public String getTest(#PathVariable("param") int param) {
return "test with param";
}
If you want query parameters (GET /test and GET /test?param=123) then you need a single endpoint that takes an optional parameter:
#GetMapping("test")
public String getTest(#RequestParam("param") Integer param) {
if(param == null) {
return "test without params";
} else {
return "test with param";
}
}

Multiple Content-type in Spring MVC

Can we have multiple content-type in Spring MVC request header?
I'm passing:
{Content-type = application/json, text/plain}
through Postman to my API. Currently, I'm getting org.springframework.web.HttpMediaTypeNotSupportedException: Invalid mime type ....
I wanted to know, is there something with my input values, or we can't have multiple content-type in our header.
Controller:
#RequestMapping(value = "/addressees", produces = APPLICATION_JSON_UTF8_VALUE, method = GET)
Yes, spring mvc request mapping supports multiple consumes MIME type , sample looks like
#RequestMapping(value = "/something", method = PUT,
consumes = {APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE},
produces = {APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE})
public SomeObject updateSomeObject(SomeObject acct) {
return doStuff(acct);
}
Add consumes part in requestmapping like - consumes = {APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE}
For know more, refer this link -
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html
Your request header can have one content-type per request. You specify to the server what type of data are actually being sent.
Your server/API endpoint can support multiple.
So if your request specifies both application/json and text/plain at the same time, I believe it is a problem with your request.
Yes, RequestMapping.consumes accepts an array of Mime types
String[] consumes() default {};
Note that you have to use consumes to define the incoming MIME types. produces is for the outgoing type.

Using postman raw testing spring-boot controller failed

Here is the controller:
Here is the postman:
Via form-data, I can get caseId in my controller.
But raw with header, I can't.
I don't know why... Is there anything wrong with my controller ?
Please help, thanks.
edit 1:
Yeah. Add something more
We know, springMVC will bind data for us, but when we use POST request and put data in body via raw and Content-Type:application/json, spring will still bind data? request.getInputStream() will only call once.
edit 2:
I found a way to get the raw.
get the json string.
edit in 11/29/2017
I found that:
Post with raw, I need to use #RequestBody to recive the value.
Here are the example of how to retrieve data using POSTMAN and bind with SpringMVC
#RequestMapping(value = "/user/", method = RequestMethod.GET)
public ResponseEntity<List<User>> listAllUsers() {
List<User> users = userService.findAllUsers();
if (users.isEmpty()) {
return new ResponseEntity(HttpStatus.NO_CONTENT);
// You many decide to return HttpStatus.NOT_FOUND
}
return new ResponseEntity<List<User>>(users, HttpStatus.OK);
}
You may refer to this article : Spring Boot Rest API Example
Can u bind request param as below and check :
public Object getTcaseByCaseId(#RequestParam("caseId") String caseId) {

Spring #JsonView how can use request parameter or header

#JsonView
how can use like parameter from request:
#JsonView(header="range")
when response value,read request header range to exclude/include some field
JsonView provides "static" view mapping. so for your dynamic behaviour you can do like this:
// actual request handling is happened here
private ResponseEntity<SomeObject> processRequest();
// request handling with view limit in result
#JsonView(YourDefinedView.class)
#RequestMapping(value = "/request", headers={"range=include"})
public ResponseEntity<SomeObject> processWithView() {
return processRequest();
}
// request handling without view (no headers specified)
#RequestMapping(value = "/request")
public ResponseEntity<SomeObject> processWithoutView() {
return processRequest();
}
this will map your client to same request url, but depending on header it will provide view or not. Than you can create a set of methods, that will be using different #JsonView depending on headers information.
But with this you will limit only the data transfered to client, and the whole data load will happen on server. For example with database and JPA, if you would like not to fetch from database all that data you will end with javax.persistence.NamedEntityGraphs, which will change the general logic of your application - and will at the end of the day produce 2 different methods.
And if you would like to expose custom header with list of fields, to be serialized - custom DTO object, or Map<String, Object> (ugly-ugly-ugly) or custom HandlerMethodReturnValueHandler comes to your help.

Resources