I'm returning an ODataResult from the new Web API OData package as follows:
public ODataResult<Product> Get(ODataQueryOptions options)
{
var results = (options.ApplyTo(_db.Products) as IQueryable<Product>);
var count = results.Count;
var limitedResults = results.Take(100).ToArray();
return new ODataResult<Product>(results,null,count);
}
The above works great but it always returns an Atom response regardless of the query type. How can I return JSON?
I can see that Atom is the first supported media type within the ODataMediaTypeFormatter collection. I'd be happy just completely removing Atom support as I don't need it. Even better would be to have the content type correctly negotiated.
Have you tried setting the accept header, like this:
Accept=application/json;odata=verbose.
That should return JSON.
The OData protocol has supported JSON for a while but in V3 of the protocol application/json is mapped to something called JSON light (which is not yet implemented). So to until JSON light is supported to get JSON you have to be a little more specific, and request the more verbose version of JSON that has been in OData since V1.
I am currently also experimenting with OData support using the Beta Package you linked. We should keep in mind that it is a beta package and things might change until release. I have hit the same issue. Right now, it seems Microsoft is planning to provide OData v3 support in Web Api, looking at ODataMediaTypeFormatter reveals this.
In OData v3, there will be three formats:
Atom (application/atom+xml)
JSON Verbose (application/json;odata=verbose)
JSON Light (application/json;odata=light)
Atom is the only and thereby default XML format of OData. The default JSON Format in OData v3 is JSON light. The old OData v2 JSON Format is what has become JSON Verbose in OData v3.
This is supported by the Spec (v20120705) section 2.2.5.1 which lists Accept and corresponding Response Headers:
application/json;odata=verbose ->  application/json;odata=verbose
application/json;odata=light  -> application/json;odata=light
application/json -> For version 1.0 and version 2.0 responses: application/json;odata=verbose. For version 3.0 responses: application/json;odata=light
Unfortunately, they haven't specified JSON light yet (section 2.2.5.1.3, emphasis mine):
The JSON light format is a new format, defined only in the OData 3.0
protocol, that optimizes for small size by not including metadata
information in the representations. The verbose format represents the
existing JSON-based format, defined by the OData 1.0, 2.0 and 3.0
protocol, that includes metadata information along with the
representation of an instance. The format for the JSON light
content-type is not defined by this version of document.
I do expect however that the JSON Light format will be a proper subset of the JSON Verbose format. The current implementation of ODataMediaTypeFormatter will only respond to application/json;odata=verbose and application/atom+xml headers or fallback to ATOM. Interestingly enough, it seems specifying $format=json returns a 406.
If you want an interim solution that assumes the light format will be a proper subset of the verbose format, you can instruct the MediaTypeFormatter to respond to application/json requests, making it a lot easier to work with OData from jQuery because we can ommit specifying the accept header:
ODataMediaTypeFormatter odataFormatter = new ODataMediaTypeFormatter(model);
odataFormatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json"));
Related
Is there an easy way to ask the google api ruby client to just give you back the stock HTTP response, rather than to perform the lovely, but slightly limiting translation into one of their ruby representable objects?
e.g.
response = Gmail.client.get_user_message("me", id)
=> #<Google::Apis::GmailV1::Message
response = Gmail.client.list_user_messages("me")
=> #<Google::Apis::GmailV1::ListMessagesResponse
but
response = Gmail.client.delete_user_message("me", id)
=>nil #successfully deleted
Now that's all fine and dandy, except that sometimes I just want to know what sort of response is going to come back. i.e. an HTTP response with maybe some JSON in the body. And then I'll worry about what I do with it...
I can take the response and use the
response.to_json
to get the body of the json that would have come back (though I still won't have the response code, and I need to KNOW that it's one of those objects first).
The client library is definitely getting that, it's just converting it into these objects before it lets me see it. And if I don't know that it's a google object (and not nil) I can't run that to_json consistently....
Any ideas other than second guess what google is going to send me back?
(I should note that this has come about when trying to move a library from dealing with their 0.8 api to their 0.9 api, so call me a cynic if you must but my faith that google won't make breaking changes to those objects returned is at a low ebb...
As far as I know, it is possible to ask the server to send only the fields you really need and get a partial response instead of the default full response as mentioned in Performance Tips.
However, I suggest that you please check the documentation for the specific API you are using to see if the field you're looking for is currently supported. For the Gmail API, you may go through Working with partial resources.
Here are the two types of partial requests that you can use:
Partial response: A request where you specify which fields to include in the response (use the fields request parameter).
Patch: An update request where you send only the fields you want to change (use the PATCH HTTP verb).
Hope that helps!
We are using WebAPI to mimic the handling of a legacy system. As a result, we would like the default response formatter to be the XmlFormatter and not the JsonFormatter. The reason is that some of the existing calls to the service do not supply the Accept: HTTP header field.
I can achieve this by removing the JsonFormatter from the Formatters collection and then re-adding it, forcing it to be at the end of the chain.
This then result in the default format response using the XmlFormatter. Although it works, it just doesn't feel correct, and although I am moving Json to the back of the collection, there is no guarantee that the XmlFormatter is at the front of the collection.
Ideas/thoughts?
Just add formatters in the right order. If ASP.NET Web API finds two formatters for the same content type, it will pick the first one, so it is very important to add formatters in the right order.
//somewhere in Web Api config
config.Formatters.Clear();
config.Formatters.Add(new XmlMediaTypeFormatter());
config.Formatters.Add(new JsonMediaTypeFormatter());
So the default will be XML, the first formatter, but the API still supports JSON if the request asks for it (with appropriate HTTP header).
Finally, another different approach, is to use a custom IContentNegotiator. It will allow you to select the most appropriate MediaTypeFormatter for a given request.
//somewhere in Web Api config
config.Services.Replace(typeof(IContentNegotiator), new MyCustomContentNegotiator());
An example is available here.
This is returned to automatically serialise and return json when content type is json.
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
((DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;
I know OData supports responding in JSON format when it's given the appropriate Accept header:
Accept: application/json
Some articles say you'll need to specify odata verbosity otherwise you'll get the default xml format, but I have not seen this to be actually true. But let me mention it anyway:
Accept: application/json;odata=verbose
But (how) can I make my request using JSON instead of a querystring?
OData doesn't provide a way to specify the query in a request body, it only supports the query in the URL. So the answer is that there's no way to do that in JSON. Note that it applies to GET requests. Modification requests (POST/PUT/...) do accept JSON as the payload (typically representing an entity for example), in which case simply specify the content type of the request in its Content-Type header.
There are java script libraries which let you build the query string using more structured code (as compared to just strings). For example the datajs http://datajs.codeplex.com/.
My rest service uses ISO 8601 as the date format for all requests and responses. Is there a way to set this on the RestClient or do I need to set it on each individual RestRequest?
It doesn't look like there's any built in ability to do so. Newtonsoft.Json provides an IsoDateTimeConverter that can do the serialization you are looking for. In order to use it for serialization, I think you would need to mostly duplicate the RestSharp.Serializers.JsonSerializer in your own ISerializer that does almost exactly what the RestSharp version does, but tweaksthe NewtonSoft.Json.JsonSerializer.Converters property in the instance created here and adds/replaces the date/time converter.
As far as deserialization, you should be able to set the IDeserializer.DateFormat property on a new JsonDeserializer and setting that as your handler:
client.AddHandler ("application/json", new JsonDeserializer() { DateFormat = "yyyy-MM-ddTHH\:mm\:ss.fffffffzzz" });
I've a set of services hosted with WCF Web Api and I communicate with them in JSON from javascript. In most cases I'm okay modifying the accepts bit of the header to require a JSON response but there are some cases arising where I can't do this. This is due the the javascript framework that I'm using (Ext JS). For some things it only lets me specify a URL and not the proxy defaults such as headers.
This isn't an Ext JS question however. Web Api seems to default to returning XML, and I'd like to know whether it's possible to change this default so that it can return JSON instead. Thanks in advance!
A bit of experimentation seems to indicate that the order of the configured formatters matter (which is quite intuitive).
By default, when you create an instance of HttpConfiguration, its Formatters collection contains these formatters:
XmlMediaTypeFormatter
JsonValueMediaTypeFormatter
JsonMediaTypeFormatter
FormUrlEncodedMediaTypeFormatter
The reason why XML is the default formatting is because it's the first formatter. To make JSON the default value, you can reorder the collection to look like this:
JsonValueMediaTypeFormatter
JsonMediaTypeFormatter
XmlMediaTypeFormatter
FormUrlEncodedMediaTypeFormatter
Given an instance config of HttpConfiguration, here's one way to reorder the collection:
var jsonIndex = Math.Max(
config.Formatters.IndexOf(config.Formatters.JsonFormatter),
config.Formatters.IndexOf(config.Formatters.JsonValueFormatter));
var xmlIndex = config.Formatters.IndexOf(
config.Formatters.XmlFormatter);
config.Formatters.Insert(jsonIndex + 1, config.Formatters.XmlFormatter);
config.Formatters.RemoveAt(xmlIndex);
Whether or not this is supported I don't know, but it seems to work on WebApi 0.6.0.
I actually found a simple way of dealing with this. First make sure that the default JSON formatter is first. And then set its type to text/html. This will insure that the browser gets JSON even if it does not set the header. Nice aspect of the below is that you never have to remember to set the accept header in client code. It just works and always default to JSON.
var jsonformatter = config.Formatters.Where(t => t.GetType() == typeof(JsonMediaTypeFormatter)).FirstOrDefault());
config.Formatters.Remove(jsonformatter );
config.Formatters.Insert(0, jsonformatter);
config.Formatters[0].SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
You could use the a delegating channel as described here http://blog.alexonasp.net/post/2011/07/26/Look-Ma-I-can-handle-JSONP-(aka-Cross-Domain-JSON)-with-WCF-Web-API-and-jQuery!.aspx which maps URIs like http://myserver/myresource/1/json to http://myserver/myresource/1 and sets accept header to application/json.
The delegating channel is part of the ContactManager_Advanced sample when you're downloading WCF Web API from http://wcf.codeplex.com.
It is contained in the UriFormatExtensionMessageChannel.cs file.
Look at the global.asax.cs of the sample on how to get it running.
According to the code the WCF Web API will always default to the XmlFormatter if it is in the collection of usable formatters. If it isn't the JsonFormatter is used instead if this is present. There is also a DefaultFormatter property but that is internal so you can't set that. Maybe a useful feature request to add?