Swagger doesn't detect request parameters correctly - spring-mvc

Given a controller like:
#RequestMapping(value = "/", method = GET)
#ApiOperation(value = "Find items")
public List<Item> find(Query query) {
...
}
class Query {
String text;
int limit;
}
Spring MVC lets me do requests like /items/?text=foo&limit=10. Unfortunately, Swagger (or SpringFox?) thinks this endpoint takes a single "query" (JSON object) parameter. What am I doing wrong?

Looks like the key is to both have getters/setters (setters alone are not sufficient) and use #ModelAttribute (which otherwise isn't necessary in Spring MVC).

Related

How to obtain request parameter from query string or request body inside ASP.NET Web API 2 Controller

In PHP, one can access request property by using the $_REQUEST 'superglobal' variable.
In Java Servlet, one can also do something similar by calling getParameter(string) or getParameterValues(string) on the incoming HttpServletRequest instance.
Both of these method do not care if the data is conveyed on the query string or on the body. They are HTTP-method-agnostic-ways of getting request properties.
How to do the same using ASP.NET 4.x (not Core) Web API 2?
As far as possible, I do not want to use model binding or route parameter. I just want to use built in Properties of the ApiController to access the request parameter directly.
Here's what I'm trying to do:
public class MyController : ApiController
{
[HttpPost]
public IHttpActionResult Index()
{
// somehow obtain 'requestParam ' either from query string OR from request body
var requestParam = Request.???
return Ok(requestParam);
}
}

Spring controller return string as pure json

I am returning a string object from spring controller like
#RequestMapping(value = "/persons.html", method = RequestMethod.GET)
public #ResponseBody String listPersonHtml(Model model) {
return "{\"abc\":\"test\"}";
}
I am getting response on ui like "{\"abc\":\"test\"}",i want this response as
{"abc":"test"}
i.e pure json object.
what type of configuration I need?
On UI side,if I set Accept */* then I face this issue,if I set Accept text/html or Accept text/plain then no issue is there,but I can't change accept header.
I found the way.Its all about spring message-converters.I added MappingJackson2HttpMessageConverter in this list and this converter tries to convert string to json and produces this result.
Just add org.springframework.http.converter.StringHttpMessageConverter before MappingJackson2HttpMessageConverter so that StringHttpMessageConverter can come into action and string can be returned as it is.
Old question, but I just had to solve the same issue and most of the answers I found resulted misleading, so here's mine:
It all starts with the Controller, and Spring trying to answer a mapped request in the format that the invoking client is expecting. The client can inform this using different HTTP features, and there is where the different HttpMessageConverter implementations are involved. Spring pick's the format to answer based on different strategies, applied by the ContentNegotiationManager.
By prioritizing StringHttpMessageConverter over MappingJackson2XmlHttpMessageConverter you are only telling Spring to answer in "text/plain" format over "application/json", and it will work until a client specifies that is expecting a json response (this is mostly done by setting the Accept header in the request, although there are other ways to do it). The important thing is that if a client sets that header to "application/json", Spring will use MappingJackson2XmlHttpMessageConverter that will translate the Java String to a Json String, ending up with something like "{\"abc\":\"test\"}" instead of {"abc":"test"}
So, the real issue that every developer faces in this case is that MappingJackson2XmlHttpMessageConverter translates a Java String to a Json String, and in some cases, you might not need that, because the string contains valid json that needs to be returned without modifications. There are some configuration classes for this MessageConverter but I did'n went that road, because I need to return Strings like "raw" Json only in some specific endpoints (performance is the key driver). Here's an expample that resumes my "approach":
#RestController
#RequestMapping(value = "test", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class TestController {
#RequestMapping(method = RequestMethod.GET, value = "endpoint")
public JsonObject getSomeJson() {
return new JsonObject("{\"abc\":\"test\"}");
}
private static class JsonObject {
private String rawJsonValue;
JsonObject(String rawJsonValue) {
this.rawJsonValue = rawJsonValue;
}
#JsonValue #JsonRawValue
public String getRawJsonValue() {
return rawJsonValue;
}
}
}
#JsonValue and #JsonRawValue are Jackson annotations that tell MappingJackson2XmlHttpMessageConverter to treat the getRawJsonValue method result as the Json representation of JsonObject, without making any modification. The response of the endpoint will be {"abc":"test"}

Forward request to spring controller

From a servlet , I am forwarding the request to a spring controller like below
RequestDispatcher rd = request.getRequestDispatcher("/myController/test?reqParam=value");
rd.forward(request, response);
In order to pass a parameter to the spring controller , I am passing it as request parameter in the forward URL.
Is there a better way of doing this ?
Instead of passing in request parameter , can I pass as a method parameter to the spring controller during forward ?
This will be called when /myController/test?reqParam=value is requested:
#RequestMapping("/myController/test")
public String myMethod(#RequestParam("reqParam") String reqParamValue) {
return "forward:/someOtherUrl?reqParam="+reqParamValue; //forward request to another controller with the param and value
}
Or you can alternatively do:
#RequestMapping("/myController/test")
public String myMethod(#RequestParam("reqParam") String reqParamValue,
HttpServletRequest request) {
request.setAttribute("reqParam", reqParamValue);
return "forward:/someOtherUrl";
}
you can use path variable such as follow without need to use query string parameter:
#RequestMapping(value="/mapping/parameter/{reqParam}", method=RequestMethod.GET)
public #ResponseBody String byParameter(#PathVariable String reqParam) {
//Perform logic with reqParam
}

What kind of datatypes should I use for the return value of a Web API method?

I have a Web API controller that returns data to my client. The code looks like this:
[HttpGet]
[ActionName("Retrieve")]
public IEnumerable<Reference> Retrieve(int subjectId)
{
return _referenceService.Retrieve(subjectId);
}
Can someone tell me is it necessary to specify the ActionName?
Also should I return an IEnumerable, an IList or something else?
I believe if your ASP.NET routing is setup correctly you don't need to specify the ActionName, for example:
protected void Application_Start()
{
RouteTable.Routes.MapHttpRoute("0", "{controller}/{action}/{arg1}");
}
Will match /YourControllerName/Retrieve/132
What you return is based entirely on your media-type formatters, of which the default is XmlFormatter and JsonFormatter. These can be found in GlobalConfiguration.Configuration.Formatters and will be chosen based on the Accept header provided by the client.
We, for example, use JSON.Net for our response formatting, configured by:
protected void Application_Start()
{
RouteTable.Routes.MapHttpRoute("0", "{controller}/{action}/{arg1}");
MediaTypeFormatterCollection formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);
var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
jsonFormatter.Formatting = Formatting.Indented;
jsonFormatter.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
This tells WebApi to disallow any XML formatting and only return JSON using the provided JSON.Net contract resolver. JSON.Net supports serializing IEnumerable.
I would, however, recommend returning a HttpResponseMessage instead. This allows you to set the status code as well (This still uses the media type formatter, it's just a cleaner wrapper). You can use this like so:
[HttpGet]
public HttpResponseMessage Retrieve(int subjectId)
{
var response _referenceService.Retrieve(subjectId);
return Request.CreateResponse(HttpStatusCode.OK, response);
}
You should return HttpStatusCode instead of data if have not requirement, like POST method should return OK or whatever.
or if want record like Get method should return type of record.
also you no need to add attribute on method like Get,Put,Delete etc because webapi automatically detect method according to action like if you are getting data then your method name should be start with Get like GetEmployee etc.

Spring Controller - Fill DTO from Servlet Request manually

In Spring controller, I want to invoke same method for different HTML - Forms submission
So, taking HttpServletRequest as a RequestBody
#RequestMapping(value = "/Search")
public String doSearch(HttpServletRequest httpServletRequest, ModelMap map) {
// Now, looking for something like this...
if(req.getType.equals("x")
//X x = SOME_SPRING_UTIL.convert(httpServletRequest,X.class)
else
// Y y = SOME_SPRING_UTIL.convert(httpServletRequest,Y.class)
}
I want to convert request parameters to bean through Spring, As it converts while I take Bean as method argument
Use the params attribute of the #RequestMapping annotation to differentiate the request mapping mapping.
#RequestMapping(value="/search", params={"actionId=Actionx"})
public String searchMethod1(X search) {}
#RequestMapping(value="/search", params={"actionId=ActionY"})
public String searchMethod2(Y search) {}
This way you can create methods for each different action and let spring do all the heavy lifting for you.

Resources