Documenting possible values for Map in Swagger - jersey

I have a JAX-RS method which takes a Map to facilitate a partial update.
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/{id}/edit")
public Response edit(HashMap<String, Object> data)
I can't use Patch, long story.
I need to document what parameters are possible for client to send up so they can see them in swagger UI. One way to do this is to use #ApiImplicitParam
#ApiImplicitParams({
#ApiImplicitParam(name = "payload", value = "payload", required = true, dataType = "com.me.PartialUpdatePerson", paramType = "body"),
})
This is a nice work around. PartialUpdatePerson is a class which contains the various parameters allowed to be sent up.
The problem is in the swagger UI, it still shows me the body with the map. Sample value is:
{
"additionalProp1": {},
"additionalProp2": {},
"additionalProp3": {}
}
as well as the payload.
Is there anyway, I can tell swagger, not to show this? i.e. to ignore the HashMap data from a doc perspective? I am not using Spring so #ApiIgnore is not possible.
Thanks

public Response edit(#ApiParam(hidden = true) HashMap<String, Object> data)

Related

How to make Feign POST request without a request body and with query params?

I am using Feign with the Apache Http Client and I would like to support the following jax-rs interface:
#POST
#Path("/do_something")
void doSomething(#QueryParam("arg") String arg);
But, ApacheHttpClient uses a RequestBuilder, which converts query parameters for requests without a body/entity into a UrlEncodedFormEntity.
I am converting my APIs to jax-rs, and I do not want to break backwards compatibility. Is there a way to use Feign without adjusting my API? Will the OkHttp or Ribbon clients support POSTs with query params and no body/entity? Is there another java jax-rs client that will support this?
Also, is there a reason why RequestBuilder turns query params into a UrlEncodedFormEntity? Is there an alternative HttpUriRequest builder within the apache-httpclient library that doesn't do this? RequestBuilder's build method has the following lines of code:
if (entity == null && (HttpPost.METHOD_NAME.equalsIgnoreCase(method) || HttpPut.METHOD_NAME.equalsIgnoreCase(method))) {
entity = new UrlEncodedFormEntity(parameters, HTTP.DEF_CONTENT_CHARSET);
} else {
// omitted expected behavior
}
Before switching to Feign, my code constructed a HttpUriRequest with something similar to the following:
URI uri = new URIBuilder()
.setScheme("https")
.setHost("localhost")
.setPath("service/do_something")
.addParameter("arg", "value")
.build();
HttpUriRequest request = new HttpPost(uri);
If you are willing to break the API slightly and maintain support for the #QueryParam, then you could define a request interceptor on the feign client that adds a plain text entity/body to the request:
.requestInterceptor(template -> {
if (template.method().equals(HttpPost.METHOD_NAME) && template.queries().keySet().size() > 0 && template.body() == null) {
template.body(" ");
}
})
Then, your API would change with the following:
#POST
#Consumes(MediaType.TEXT_PLAIN)
#Path("/do_something")
void doSomething(#QueryParam("arg") String arg);
But, this breaks the API since the server now expects/consumes a POST message with a plain text entity/body.
I think the same could be accomplished without the requestInterceptor and with Feign's #Body template:
#POST
#Consumes(MediaType.TEXT_PLAIN)
#Body(" ")
#Path("/do_something")
void doSomething(#QueryParam("arg") String arg);
But, this means that your API would have to include Feign rather than pure jax-rs annotations.

Spring Multipart File with #RequestBody

I am trying to upload data from an app to a spring backend service.
Things to upload are a DataModel containing data of the object to create and several images linked to the data.
Therefore I am using this method signature:
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public Survey createSurvey(#RequestBody SurveyPostHelper helper, #RequestParam(value="file", required = true) MultipartFile[] images)
I tried to play with the annotations, but either I get a blank images array or my helper is empty.
How would you solve this?
Thanks in advance.
I found out, that this method signature could do the job:
#ResponseBody
public Survey createSurvey(#RequestPart(required=true) SurveyPostHelper helper, #RequestPart(value="file", required = true) final MultipartFile[] images)
Important in my case was to set the MimeType in the client app. The files MimeType should be image/jpg and the SurveyPostHelpers to application/json to allow Spring to parse the json and bind it to my Object.
see an example of the client code working for me images is the list of files I want to save
var formData = new FormData();
for (var i = 0; i < images.length ; i++) {
formData.append('images', images[i]);
}
formData.append('adData', new Blob([JSON.stringify(adData)], {
type: "application/json"
}));

Set JSON CamelCase per Web API request

Web API uses the Json.Net formatter to serialise its JSON responses which allows you to customise the format of the generated JSON very easily for the entire application at startup using:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
This allows you resolve the issues between C# syntax preferring PascalCase and javascript based clients preferring camelCase. However setting this globally on the API without taking into consideration who the client request is actually coming from seems to assume that an API will only have 1 type of client and whatever you set for your API is just the way it has to be.
With multiple client types for my API's (javascript, iOS, Android, C#), I'm looking for a way to set the Json.Net SerializerSettings per request such that the client can request their preferred format by some means (perhaps a custom header or queryString param) to override the default.
What would be the best way to set per-request Json.Net SerializerSettings in Web API?
With a bit of help from Rick Strahl's blog post on creating a JSONP media type formatter, I have come up with a solution that allows the API to dynamically switch from camelCase to PascalCase based on the client request.
Create a MediaTypeFormatter that derives from the default JsonMediaTypeFormatter and overrides the GetPerRequestFormatterInstance method. This is where you can implement your logic to set your serializer settings based on the request.
public class JsonPropertyCaseFormatter : JsonMediaTypeFormatter
{
private readonly JsonSerializerSettings globalSerializerSettings;
public JsonPropertyCaseFormatter(JsonSerializerSettings globalSerializerSettings)
{
this.globalSerializerSettings = globalSerializerSettings;
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
}
public override MediaTypeFormatter GetPerRequestFormatterInstance(
Type type,
HttpRequestMessage request,
MediaTypeHeaderValue mediaType)
{
var formatter = new JsonMediaTypeFormatter
{
SerializerSettings = globalSerializerSettings
};
IEnumerable<string> values;
var result = request.Headers.TryGetValues("X-JsonResponseCase", out values)
? values.First()
: "Pascal";
formatter.SerializerSettings.ContractResolver =
result.Equals("Camel", StringComparison.InvariantCultureIgnoreCase)
? new CamelCasePropertyNamesContractResolver()
: new DefaultContractResolver();
return formatter;
}
}
Note that I take a JsonSerializerSettings argument as a constructor param so that we can continue to use WebApiConfig to set up whatever other json settings we want to use and have them still applied here.
To then register this formatter, in your WebApiConfig:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new StringEnumConverter());
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
config.Formatters.Insert(0,
new JsonPropertyCaseFormatter(config.Formatters.JsonFormatter.SerializerSettings));
Now requests that have a header value of X-JsonResponseCase: Camel will receive camel case property names in the response. Obviously you could change that logic to use any header or query string param you like.

Spring 3 RESTful return on POST (create)

I am new to RESTful services and their implementation on Spring 3. I would like your opinion on the best practices for returning type when a client creates a new resource in my server.
#RequestMapping(method = RequestMethod.POST,
value = "/organisation",
headers = "content-type=application/xml")
#ResponseStatus(HttpStatus.CREATED)
public ??? createOrganisation(#RequestBody String xml)
{
StreamSource source = new StreamSource(new StringReader(xml));
Organisation organisation = (Organisation) castorMarshaller.unmarshal(source);
// save
return ???;
}
A simple choice would be javax.ws.rs.core.Response, found in the Java EE's own restful services package. It - simply - tells what the web server should answer to the HTTP request.
For instance:
if (organisation != null)
return Response.ok().build();
else
return Response.serverError().build();
Custom response headers and other exotic things like that are possible with that return type too, but I don't think that would match with "best practices".
uh, I missed that #ResponseStatus(HttpStatus.CREATED)... I guess my answer was not much of help.
Maybe this will help instead: How to return generated ID in RESTful POST?
I would go for a ResponseEntity<byte[]> and you would have take care of the marshalling of your response on your controller method. Notice that you are basically scrapping the V in MVC, there is a MarshallingView on Spring but from experience I consider the previous solution much more flexible and easier to understand.
It is a good idea to return the newly created entity(with the generated id) wrapped in ResponseEntity. You can also set the HttpStatus in ResponseEntity based on the result of the operation.
#RequestMapping(method = RequestMethod.POST,
value = "/organization",
headers = "content-type=application/xml")
public ResponseEntity<Organization> createOrganisation(#RequestBody String xml) {
StreamSource source = new StreamSource(new StringReader(xml));
Organization organisation = (Organization) castorMarshaller.unmarshal(source);
// save
return new ResponseEntity<Organization>(organization, HttpStatus.OK);
}

Jersey:Returning a Response with a Map containing Image Files and JSON String values

I am using Jersey JAX-RS.
I want to return a Response with a Map containing Image Files and JSON String values.
Is this the right way to do this:
Map<String,Object> map = new HashMap........
GenericEntity entity = new GenericEntity<Map<String,Object>>(map) {};
return Response.ok(entity).build();
Or is this better.I plan to use JAX-RS with Jersey only.
JResponse.ok(map).build();
I am basing this on this article:
http://aruld.info/handling-generified-collections-in-jersey-jax-rs/
I am not sure what to specify for #Produces too(planning to leave it out).
TIA,
Vijay
You better produce a multipart response:
import static com.sun.jersey.multipart.MultiPartMediaTypes.MULTIPART_MIXED_TYPE;
import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE
#GET
#Produces(MULTIPART_MIXED_TYPE)
public Response get()
{
FileDataSource image = ... (gets the image file)
String info = ... (gets the xml structured information)
MultiPart multiPart = new MultiPart().
bodyPart(new BodyPart(info, APPLICATION_XML_TYPE)).
bodyPart(new BodyPart(image, new MediaType("image", "png")));
return Response.ok(multiPart, MULTIPART_MIXED_TYPE).build();
}
This example was taken from there.

Resources