Spring REST API with swagger - map of values in request param - spring-boot

I have a Spring Boot based REST API application with the following endpoint (Written in Kotlin)
#RequestMapping(value = ["/search"], method = [RequestMethod.GET])
#ApiOperation("Check whether any of the map values exists. Returns string 'true' if stamp exists, else 'false'")
fun checkExists(
#ApiParam("information about the stamp as key-value pairs (example: ds=2017-11-34&hh=05)", required = true)
#RequestParam searchValues: Map<String, String>
): Boolean {
return service.checkExists(searchValues)
}
And I know Spring supports sending a dynamic map of key value pairs as documented here.
I am also using Swagger to document the API definitions, and further more, I am using swagger-codegen-cli to generate the client library using which someone can connect with this REST API.
Now, the issue is, I am not able to send a map of values from the swagger generated client to the Spring REST API (even though Spring supports it). Starting from Swagger OpenAPI 3, they've added support for Object types in the specification. But this works in a different way than I need. For example with just Spring and RequestParam of type Map
http://localhost:8080/search?foo=A&bar=B
is parsed as a map of key value pairs
key="foo",value="A"
key="bar",value="B"
But, When I send a Map Object from the swagger client with the same key-value pairs
Map<String, String> values = new HashMap<>();
values.put("foo","A");
values.put("bar","B");
return out = clientApi.checkExistsUsingGET(values);
This sends a request to the REST API in form of
http://localhost:8080/search?searchValues={foo=A,bar=B}
and the map in Spring side ends up as
key="searchValues",value="{foo=A,bar=B}"
I've been struggling to get the swagger client api to send the request in a way the Spring API is intended to work with Map of values, but I am not able to figure a solution.
Am I doing using the client API in a wrong way?, or this just can't be done with swagger?
Any suggestions/opinions appreciated!

This is not yet supported by swagger-ui. See this issue https://github.com/swagger-api/swagger-ui/issues/2241

Related

Dynamic metric tagging with Spring WebClient

Trying to migrate some code from a RestTemplate to Webclient. The old code was wrapping a timer for metric collection around the RestTemplate call, and was adding two additional custom tags that are based on the request input.
We're creating a WebClient and adding the MetricsWebCLientFilterFunction to the builder as a filter. I've also seen the DefaultWebClientExchangeTagsProvider. The issue is that the only mechanism I've seen to apply tags is on that builder. We don't want to create a new WebClient on every request from the builder, and I'm not seeing a way to add tags to an individual webclient get/options/post.
Is there a mechanism to add tagging to individual metrics on the actual webclient get or are we limited to creating a builder every single time?
For context, we're trying to log client id and another custom identifier that isn't part of the URL pattern for the call.
The only idea I've had so far was adding an HTTP header and then creating a custom WebClientExchangeTagsProvider that would add the tag as the request comes in. The problem is that we don't want these headers going out to the external vendor services we're calling.
We're using Spring Boot 2.5.4 and it's a spring MVC app we'd like to migrate to webflux eventually.
There isn't a mechanism to post custom tags per request once a WebClient is created. However, one can do a pattern like this
val metricFilter = MetricWebClientFilterFunction(meterRegistry), CustomTagProvider(customValString), "metric-name", AutoTimer.ENABLED)
webClient.mutate().filter(metricFilter).build().get() ...
Then create a custom metric class
class CustomTagProvider(private val customValString: String) : DefaultWebClientExchangeTagProvider() {
override fun tags(request: ClientRequest, response: ClientRespose, throwable: Throwable): Iterable<Tag> {
val custom: Tag.of("custom", customValString)
val tags: MutableList<Tag> = mutableListOf(custom)
tags.addAll(super.tags(request, response, throwable))
return tags
}
}

violation : Number of parameters should be limited - spring boot

I'm working in a spring boot application, where i'm getting violation as, "number of parameters should be less than 8"
i,m passing all the parameters through request param
I'm passing exactly 8 parameters all are mandatory
any other way to overcome this ?
In general, it looks like bad API design that you have so many request params. Request params are normally only used for things like filter and sorting options, but not to provide any actual data. Instead, use the request body.
Nevertheless, you can also get all parameters as a HashMap using:
#PostMapping("/api/example")
#ResponseBody
public String examplePost(#RequestParam Map<String,String> allParams) {
return "Parameters are " + allParams.entrySet();
}

Swagger 2.0 Not working with spring boot when we have Map in requestParams

I am using swagger 2.0 version 2.9.2 with spring boot.
When I have #RequestParam Map<String, String> requestParams in REST API swagger UI stops working.
When I log requestParams it shows {requestParams={code=1}} which should be like {code=1}
Downgrading to swagger 2.8.0 did not work for me.
I am not expecting requestParams attached with my Map of parameters like this {requestParams={code=1}}
Workaround:
alternative to Map<String,String> #requestparam , where you can accept n number of request parameters.
You can get get the request param map by:
Map params = request.getParameterMap();
(if you add the HttpServletRequest request into the function)
and then you can get your parameters from there.
Not sure if Map is supported as per this link
You can try these
If your Map is not Dynamic, create a DTO and use it instead of Map
Try suggestion given in the above link
You can get get the request param map by:
Map params = request.getParameterMap();
(if you add the HttpServletRequest request into the function)
and then you can get your parameters from there.

How to define the return type of #RestControllerAdvice in Spring Boot 1.5

We are building a RESTful API with several #RestControllers which return all kinds of objects including byte arrays (actually application/pdf).
When an exception occurs we handle those with #RestControllerAdvices which return a custom ErrorView object. Still spring insists of rendering those as application/pdf which of course is not possible. The client is sending application/json in the accept header but this does not seem to help. Any pointers how to fix this?
Ok, I made a mistake which I think I should share.
Basically most of the time the content type negotiation between Spring and the client works like a charm. If the client accepts (as is the case for our app) "application/pdf, application/json" then spring will try to work it our for all responses AKA return values from #RestController functions. Except, of course, when you explicitly tell Spring to only produce a certain type of response e.g. with
#GetMapping(value = "render/document/{docId}", produces = arrayOf(MediaType.APPLICATION_PDF_VALUE))
After changing this to
#GetMapping(value = "render/document/{docId}", produces = arrayOf(MediaType.APPLICATION_PDF_VALUE, MediaType.APPLICATION_JSON_VALUE))
the ErrorView gets rendered as JSON as intended.

How to send MultiPart HTTP request using Spring RestTemplate

I am new to Spring framework and i am learning.
My web applicaiton based out of Spring MVC needs to call a vendor service through RESTful interface.
I have current implementation for POST / GET for non multipart.
However i have a requirement to POST multipart form data consisting of JSON and Bytes
I am trying to see some smaple implementation online for reference but could not get one.
I need some idea about possible approach i can take to implement this using RestTemplate.
Thanks for reading.
if we want to send multipart form data in post request and with that if you also want some information in json format then you can create your REST call according to this. here #Consumes will say that this call will accept only MULTIPART_FORM_DATA, #Transactional is for starting new transaction.
Here i am accepting three path parameters which are
1) String jsonObj, this is a string or you can say json, in this JSON you can ask UI for required information like some tags, labels, etc
2) FormDataContentDisposition fileDetail, This will contain very basic detail of file, like fileName, contentType, etc
3) InputStream uploadedInputStream, this will contain some binary data, like image, videos, or any kind of files in byte format.
* Example *
#POST
#Path("/xyz")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public VObject postMultiPartFormData(
#FormDataParam("jsonObj") String jsonObj,
#FormDataParam("mmFile") FormDataContentDisposition fileDetail,
#FormDataParam("mmFile") InputStream uploadedInputStream) {
return new VObject();
}
I hope this will help you.

Resources