ResponseEntity return type wildcard with swagger generated interface - spring-boot

I want to know the difference between returning ResponseEntity<?> with wildcard VS ResponseEntity<ABC.class> as return type when Swagger generated API interface contains 2 different classes as return types, i.e one for an exception and another for normal flow.
My controller interface is :-
#Operation(summary = "Get user by user name", tags = { "user" })
#ApiResponses(value = {
#ApiResponse(responseCode = "200", description = "successful operation", content = #Content(schema = #Schema(implementation = User.class))),
#ApiResponse(responseCode = "400", description = "Invalid username supplied", content = #Content(schema = #Schema(implementation = Error.class)))
})
#GetMapping(value = "/user/{username}", produces = { "application/xml", "application/json" })
ResponseEntity<?> getUserByName(#PathVariable("username") String username);
the #Schema defines return type.
Can I use ResponseEntity<User> instead of the <?> for the getUserByName method ?
I have the the global exception handler #ControllerAdvice in my application which returns ResponseEntity<Error> .

Answer for your question is simply Yes. Since you are using a Controller Adviser, you can directly define the endpoint return type as User in ResponseEntity
Using a Wildcard(ResponseEntity<?>) as a return type, the symbol ? defines that the return value of the controller method can be any type of ResponseEntity.
Using as ResponseEntity<?> or simply keep it as ResponseEntity<> are considered as raw type of its usage.
But really it is not a good practice to do so. So, you have to declare the exact return type of the controller method in this format ResponseEntity<ABC>.
Let's take this example java of method returning a list of objects(List<Object>).
It is possible on this list to add a Car.class type, a Van.class type. But how ever the consumer of a method should not have to deal with such disruptive questions and we have to define an exact type.
Yes you can use ResponseEntity<User> if your method returns a User type ResponseEntity.
I hope this'll help you to solve the issue :)

Related

how to return a specific status code in Kotlin

I've set up a route that when I get a name in my post body I will search the DB and return an ID value.
What I want to do is once there is no ID present in the DB return a 204 status code.
But should that be handled in the service or in my controller?
and
How do I return my specific status code?
#ResponseStatus(HttpStatus.OK)
#PostMapping("/ID_values/")
fun getID(
#RequestBody
name: String
): ResponseEntity<String> = ResponseEntity.ok(IDLookupService.lookupIDValue(name))
}
#Service
class EmailLookupService(
private val IDRepo: IDRepo
) : Logging {
fun lookupIDValue(name: String): String {
val IDLookupResult = IDRepo.findById(name)
return if (IDLookupResult.isPresent) {
IDLookupResult.get().ID.toString()
} else {
// return status code 204
}
}
}
First, you should omit the #ResponseStatus(HttpStatus.OK) annotation if you do not wish to always return a status code of 200. Using that annotation, it would suffice to only specify the response body as return value (i.e specify return type String and then return only result in your example), and Spring would automatically wrap that into a response entity with HTTP-status OK.
Second, you need some way to tell the caller of IDLookupService.lookupIDValue (which should probably be called on an instance of IDLookupService and not the class itself) that there was nothing found. This could be done for instance by changing the return type to String? and return null if nothing was found.
Then you can change getID to return
val result = idLookupService.lookupIDValue(name)
return if(result != null) ResponseEntity.ok(result)
else ResponseEntity("not found", HttpStatus.NO_CONTENT)
If you wish to return something different than a String in the case there was nothing found (like an error object with detailed information; in the example here it is simply the text "not found"), you can change the response type of getID to ResponseEntity<*>.

How to customize model in Springfox's Swagger 2 for a string request body?

I would like to customize the model for my API documentation I am making with Springfox's Swagger (Spring REST API).
This is an example for my code:
#ApiOperation("Creating a kafka topic")
#ApiImplicitParams(
#ApiImplicitParam(name = "requestBody", value = "The body of request", required = true,
example = "{\"server\": \"localhost:9092\",\"topic\": \"test\", \"parmas\":{...}}")
)
public ResponseEntity<String> createTopic(#RequestBody String requestBody) {
TopicCreationRequest request = gson.fromJson(requestBody, TopicCreationRequest.class);
...
return ResponseEntity.ok().body(response.toString());
}
Is it possible?
Thanks to Thomas__ I switched POJO and it work

ResponseEntity returns null list of objects

I am able to consume an API who returns a json object. What I am trying to do is to get a list of objects instead. Below is my code for the same:
ResponseEntity<List<Entity>> responseEntity = restTemplate.exchange(dataUrl, HttpMethod.GET, entity,new ParameterizedTypeReference<List<Entity>>() {});
where Entity of an object of which I am expecting a list to be populated with data from json. But when I print it, all fields from Entity has null value set. What am I missing?
Thanks
Sach
Can you try with this
ResponseEntity<List<Entity>> responseEntity = restTemplate.exchange(dataUrl, HttpMethod.GET, entity, Entity.class);
p.s. sorry don't have reputation for comment :(
Why don't use restTemplate.getForEntity?
ResponseEntity<Entity[]> response = restTemplate.getForEntity(dataUrl, Entity[].class)
Entity[] entities = response.getBody();
The above case returns an object of type Entity[], which is an array.
If you want to use the List interface, you will need to create a wrapper class.
The wrapper:
public class EntityList {
private List<Entity> entities;
public EntityList() {
entities= new ArrayList<>();
}
// standard constructor and getter/setter
}
The RestTemplate call:
Here you will use restTemplate.getForObject
EntityList response = restTemplate.getForObject(dataUrl, EntityList.class);
List<Entity> entities = response.getEntities();
Even a simpler alternative is to use List.class as the return type of getForObject.
List<Entity> response= rest.getForObject(dataUrl, List.class);
It is hard to give a correct answer due to a missing json example. Could you please provide a sample of the json that will be returned.
RESOLVED
Below is the code change I did which was returning correct list of Entity objects.
ResponseEntity<Entity[]> responseEntity = restTemplate.exchange(dataUrl, HttpMethod.GET, entity, Entity[].class);
Even after making this change didnt really solved my issue. I also had to add
#JsonProperty("fieldName") on each field in Entity class which had to match Json properties.

Automatically adding #ImplicitParams with specific type of method argument of Spring Controller

Previously, I had Spring controller as below.
#RequestMapping(method = GET)
public List<TheResponse> getResponses(
#RequestParam(defaultValue = "1") int offset,
#RequestParam(defaultValue = "10") int limit) {
Pagination pagination = new Pagination(offset, limit);
...
return someResponse;
}
Swagger was generating document of this method with correct parameters information.
Later I created PaginationArgResolver by implementing HandlerMethodArgumentResolver. After that, I have to update the method as below, and apply #ApiImplicitParams to make it work with Swagger.
#ApiImplicitParams({
#ApiImplicitParam(name = "offset", dataType = "int", defaultValue = "1"),
#ApiImplicitParam(name = "limit", dataType = "int", defaultValue = "10")
})
#RequestMapping(method = GET)
public List<TheResponse> getResponses(#ApiIgnore Pagination pagination) {
...
}
Is there anyway #ImplicitParams is applied automatically whenever Pagination type argument is found?
OR
If I expose #PaginationSupported annotation, can I process it to achieve same results?
I am currently using springfox v2.4.0.
PS. I can edit source of Pagination class, in case some swagger annotation is needed there.
Why adding #ApiIgnore springfox will resolve these attributes inside the class automatically. When you want to add default values and other stuff you can add the #ApiParam annotation to the class attributes as well.
class Pagination {
#ApiParam(defaultValue = "1")
private int offset;
// [..]
}

Spring MVC - Hit to URL with RequestParam failing with 404 Not Found Error

I am using Spring MVC in my project and while mapping user request to a URI, I get the 404 error. Here is my function skeleton which I want to be invoked:
#RequestMapping(value="/inventory/discovery", method = RequestMethod.GET, params = {"discoveryType"}, produces = {"application/json"})
public String getDiscoveryByType(#RequestParam("discoveryType") String discoveryType)
{
return discoveryType;
}
I am expecting this method to be called when I give the URL
http://<some-ip>/inventory/discovery/discoveryType?=DMVPN
However, when I test the code using Chrome's Advanced Rest Client I see that the URI it is trying to access is "/inventory/DMVPN" and not the "/inventory/discovery?discoveryType=DMVPN".
Am I missing something here? I don't see anything wrong with my URL syntax
I have another function in my code (but I don't think it is causing the problem) which has same request-mapping value, but has no params attribute.
#RequestMapping(value = "/inventory/discovery", method = RequestMethod.GET, produces = { "application/json" })
public ResponseEntity<DiscoveryNIOListResult> getAllDiscovery() {
logger.trace("getAllDiscovery");
List<DiscoveryNIO> listDiscoveryNIO = discoveryDasClient.getDiscoveryList();
DiscoveryNIOListResult result = new DiscoveryNIOListResult();
result.setResponse(listDiscoveryNIO);
return new ResponseEntity<DiscoveryNIOListResult>(result, HttpStatus.OK);
}
Ok, so a second look at your URL:
http://<some-ip>/inventory/discovery/discoveryType?=DMVPN
This is NOT passing discoveryType as a request GET parameter. For that you would need to do:
http://<some-ip>/inventory/discovery&discoveryType?=DMVPN
If you want to use path variables instead, you could do something like:
http://<some-ip>/inventory/discovery/DMVPN
And change your handler to something like:
#RequestMapping(value="/inventory/discovery/{discoveryType}", method = RequestMethod.GET, produces = {"application/json"})
public String getDiscoveryByType(#PathVariable("discoveryType") String discoveryType)
{
return discoveryType;
}
It looks like you were trying to mix these two methods, and that wont work.
Try changing your URL to:
http://<some-ip>/inventory/discovery?discoveryType=DMVPN

Resources