Web Api 2 Content Negotiation not obeying Accept Header - json

Following Darrel Miller's guide I'm posting raw data to my web api controller and persisting it. The content could be application/xml or application/json.
In the corresponding get method I retrieve the posted content, parsing to either XElement for XML content or JToken for json and returning OK(json) or OK(xml).
public IHttpActionResult Get()
{
// obtain parsed JToken or XElement
return OK(parsedObject);
}
The problem is that this doesn't obey the Accept Header, for example returning the original json when Accept is "application/xml". Is this by design or am I missing something?
I'm expecting this kind of behaviour.
Edit - the Accept header is obeyed if I amend the content passed to the OK method to parsedObject.ToString(), so there seems to be an issue with converting the JToken object to XML.

Are you sure you didn't remove the XmlSerializer from your formatters list?
Anyway you can always control the formatter that will be used for serialization at response level.
For example:
//forcing xml
HttpResponseMessage resp = Request.CreateResponse(HttpStatusCode.OK, result, new XmlMediaTypeFormatter());
return resp;
You can change the new XmlMediaTypeFormatter() with the instance of your current formatter for your actual configuration.
Check this link and this link for more details.

Related

Are JSON APIs supposed to return strings or JavaScript Objects?

Let's say I ask Mailchimp for subscriber data, and they send back an http request with JSON in the body. Should I be able to go:
var thingy = body.property;
Or should I have to go:
var object = JSON.parse(body);
var thingy = object.property;
?
Also, does the node.js body parse parse JSON for me?
JSON is sent over the wire from the server as a string. That's what JSON is - a string format.
Whether or not it arrives at your code as a string or as already parsed Javascript object depends entirely upon the code you are using to make the http request and perhaps what headers the server sets and what auto-detection the code doing the Ajax call makes.
If the response header sets the type to json, then some code making the request will automatically parse it for you into Javscript. Other code will leave that to the caller to do. If the server does not set the proper headers, then some code will auto-detect it as JSON and parse it and other code will not.
So ... bottom line. It depends entirely upon what the server is doing in its response and what code is being use to make the request. You can very easily just do a console.log(body) and see whether you have a JSON string or an already parsed Javascript object.
If you really weren't sure what behavior you would get, you can test the type and act accordingly (though a given server and calling code should be consistent so you shouldn't have to vary your behavior) once you test how it behaves.
if (typeof body === "string") {
body = JSON.parse(body);
}
Depends on the API, usually you get the response header Content-type: application/json. If that is the case there's probably no need to parse the response as most of the clients will understand that it's a json object and parse it for you. Anyhow, not all clients will do this automatically.

Using RestEasy, optionally pass a parameter as JSON in the POST

I have the following REST endpoint:
#POST
#Path("/id/{id}/doSomething")
#Produces({ MediaType.APPLICATION_JSON })
#Consumes({ MediaType.APPLICATION_JSON })
public Response doSomething(#PathParam("id") final String id, MyObject foo) {
// does some stuff; checks for a null foo and handles it
}
The MyObject class has a single String field called justification.
I'd like to be able to hit this endpoint with no content at all, or with JSON that maps to the MyObject class. I'd like either way to work. In other words, foo can be instantiated, or foo can be null; I have code to handle both cases.
The problem is that the JSON content appears to be required to this endpoint, not optional. So during testing, I'm having to send JSON to the endpoint, or I receive a 500 error. Even if that JSON is just {} (I can also send { justification: "blah blah" } and that works as well). But sending no content at all results in a failed call; never even hits the endpoint.
So, my question is, how can I set this endpoint up so that I can POST to it with no content at all, or with JSON in the body that maps to foo, and have either way work?
Ultimately, I just need a way for the user to be able to send a justification to this endpoint, but not have to. And because justifications can be long, I can't have it as a query param or a path param.
Thanks!
You are not going to be able to hit the endpoint with no content at all because your endpoint says #Consumes({MediaType.APPLCIATION_JSON}). Besides there has to be some content while you're trying to POST to a class while using a web service.
Like you said, even if it is a NULL or a {}, it doesn't matter as long as it has some content coming in.
Passing no content to the service works only when you're making a GET request.
For all other HTTP methods such as POST,PUT and DELETE, you will mandatorily HAVE to send some data.
As a solution to your problem, what you possibly could do is that - check if the content you have received is a NULL or a {} and do no processing at all for them.
If you still have a confusion in the answer, depending upon whether you're using SOAP or REST, this thread should help you.
How to express 'null' value from web service as real null or empty string instead of 'null' string
Hope this helps.
I was able to accomplish what I wanted by writing a second method annotated with the same REST path. This second method does not have an #Consumes statement, and does not have the second parameter in its method declaration. Looks like this:
#POST
#Path("id/{id}/doSomething")
#Produces({ MediaType.APPLICATION_JSON })
public Response doSomethingWithoutJustification(#PathParam("id") final String id) {
doSomething(id, null);
}
This new method maps to the same path, but does not expect JSON and doesn't expose a second parameter. So when I POST with nothing in the request body at all, it hits doSomethingWithoutJustification, and when I do provide JSON in the request body, it hits doSomething. Of course, if I provide anything other than valid JSON in the request body, I receive a 500 response from the service, as I'd expect.
I'd hoped to specify an optional parameter with a single method, but this solution works perfectly.

Tell modelbinding that MVC action parameter is JSON

I am using an upload control to send a file to a JsonResult, but I am also sending up a JSON string as a second parameter. This is all getting posted with the Content-Type:multipart/form-data;
[HttpPost]
public JsonResult UploadDocument(HttpPostedFileBase file, DocumentViewModel model)
{ ... }
I know MVC is capable of binding directly to a viewmodel if the content type is set to application/json but I don't think it's possible for me to set that in this case.
Is there any way for me to get MVC to automatically bind my posted json string to model?
That's not possible out-of-the-box. You will have to manually deserialize the JSON string parameter that you would read from the request to your view model inside the controller action or write a custom model binder for it that will do the job. Ideally you shouldn't be posting the model data as a JSON string but rather respect the content type you specified : multipart/form-data. So the correct way to handle this scenario is to modify the client code that is sending the request in order to respect the content type.
As I was unable to change the content-type I found this blog to be exactly what i needed.
"... our whole request stream(data) won’t be json string. Only the guest parameter will be supplied as json string..."
http://ishwor.cyberbudsonline.com/2012/07/fun-with-aspnet-mvc-3-custom-json-model-binder.html

How do I return raw html from a WCF WebAPI WebGet

I have a self-hosted WCF service running as a windows service using the WebAPI to handle the REST stuff and it works great.
I realise that I should really use IIS or similar to dish out actual web pages, but is there ANY way to get a service call to return "just" html?
Even if I specify "BodyStye Bare", I still get the XML wrapper around the actual HTML, ie
<?xml version="1.0" encoding="UTF-8"?>
<string> html page contents .... </string>
[WebGet(UriTemplate = "/start", BodyStyle = WebMessageBodyStyle.Bare)]
public string StartPage()
{
return System.IO.File.ReadAllText(#"c:\whatever\somefile.htm");
}
Is there any way to do this or should I give up?
The bodystyle attribute has no effect on WCF Web API. The example below will work. It's not necessarily the best way of doing it, but it should work assuming I didn't make any typos :-).
[WebGet(UriTemplate = "/start")]
public HttpResponseMessage StartPage() {
var response = new HttpResponseMessage();
response.Content = new StringContent(System.IO.File.ReadAllText(#"c:\whatever\somefile.htm"));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
return response;
}
It would probably make more sense to read the file as a stream and use StreamContent instead of StringContent. Or it is easy enough to make your own FileContent class that accepts the filename as a parameter.
And, the self-host option is just as viable way to return static HTML as using IIS. Under the covers they use the same HTTP.sys kernel mode driver to deliver the bits.
You'll have to use a formatter that accepts "text/html" as content type and request the content type "text/html" in your request header.
If you don't add a formatter that handles the text/html, Web API falls back to the XML-formatter as default.
In your case the formatter doesn't need to format anything but just return your return value as you're returning formatted html already.

Rendering Views as String with Spring MVC and Apache Tiles

I am trying to reuse some of my tiles in a controller which is returning a json response to the client. I would like to return a json response similar to the following format:
{
'success': <true or false>,
'response': <the contents of an apache tile>
}
In my controller I would like to perform logic similar to this pseudocode:
boolean valid = validator.validate(modelObj)
String response = ""
if(valid){
response = successView.render() // im looking for a way to actually accomplish
// this, where the successView is the apache tiles view.
// I would also need to pass a model map to the view somehow.
}else{
response = errorView.render()
}
writeJsonResponse(httpResponse, /* a Map whose json representation looks like the one I described above. */)
I belive that you want to implement a view class that will wrap the output of a jsp in json. The class in question may be org.springframework.web.servlet.view.tiles2.TilesView.
Another option may be to extend the JSON converter. org.springframework.http.converter.json.MappingJacksonHttpMessageConverter
If you need to render the view using Apache Tiles 2, you must use
org.springframework.web.servlet.view.tiles2.TilesViewResolver
See the example tutorial here: http://krams915.blogspot.com/2010/12/spring-mvc-3-tiles-2-integration.html
If you need to render the response as JSON, you can use the #ResponseBody which requires Jackson in your classpath. See the example here http://krams915.blogspot.com/2011/01/spring-mvc-3-and-jquery-integration.html (The controller returns JSON). You can also see a similar example of the #ResponseBody at http://krams915.blogspot.com/2010/12/jqgrid-and-spring-3-mvc-integration.html