Search code examples
odataversion

Determine an OData server's version


Given a known OData endpoint, what's the best way to determine the version of the OData service? The client in this scenario can support any version (1-4) but I need to know how to format the request.

For example, the OData-Version returns "4.0" for a V4 service, but a V3 service wouldn't even have that header.

In addition, querying the service root URL could be quite expensive for a service with a large number of entities. For example, a basic Dynamics 2016 Online service with no custom objects returns 2.7KB of data, when all I really want is the version header.

So what is the lightest-weight solution for getting a reliable version number? It's ok if the solution is "check this or, if missing, then check that". What's the "this" and "that"?


I found one question (How to find OData version from metadata) which seemed to get me partly there, but there are some issues with the answer.

First, it's focused on finding min/max version numbers where I would really prefer the max.

Second, it requires querying metadata, but that's a potentially massive load. /$metadata on Dynamics CRM 2016 Online results in a 3.7MB response (that takes 30 seconds to download on my current connection). I thought about requesting a dummy entity, like /dummy__entity and then examining the headers, but that seems a bit iffy to me because it would unnecessarily trigger error logging on the server and I'm not sure that an error response is always likely to have the headers I'm looking for.


Solution

  • OData 1.0/2.0/3.0

    According to MS-ODATA 1.7 Versioning and Capability Negotiation:

    The OData protocol that is defined in this document enables limited capability negotiation using the DataServiceVersion (section 2.2.5.3) and MaxDataServiceVersion (section 2.2.5.7) version request headers and the DataServiceVersion (section 2.2.5.3) response header.

    When it says "limited", it means limited:

    In a response from the server to the client, the DataServiceVersion (section 2.2.5.3) header is specified. The value states the version of the protocol that the server used in the request to generate the response and that is used by the client to determine if it can correctly interpret the response (that is, the value is not larger than the value of the MaxDataServiceVersion (section 2.2.5.7) header sent in the associated request). The value of the header is the lowest version of the protocol the server can use to fulfill the request.

    So, basically, a conformant service capable of handling OData versions 1.0 to 3.0 would return "1.0" for features defined by OData 1.0, "2.0" for features defined by OData 2.0 and not present in OData 1.0, etc.

    OData 4.0

    According to OData Version 4.0 Part 1: Protocol, Section 8.1.5 Header OData-Version

    OData services MUST include the OData-Version header on a response to specify the version of the protocol used to generate the response. The client MUST interpret the response according to the rules defined in the specified version of the protocol.

    According to What's New in OData Version 4.0, Section 2.1.1 Improved: Protocol Versioning

    Services now respond with the maximum protocol version supported by the server and indicated acceptable by the client.

    Also "downgrade" to versions prior to 4.0 is not covered, and service publishers are advised to use new service root URLs for 4.0 services.

    So for future versions of OData, from 4.0 onward, it seems that I can reliably get the maximum version I was seeking.

    Conclusion

    There is no apparent way to get the maximum version of OData supported by a pre-4.0 service. The DataServiceVersion response header will contain the lowest possible version number based on the URL features present, the version of OData that the service supports and the client-requested version.

    However, beginning with OData 4.0, the OData-Version response header will always contain the maximum version based on what the service supports and what the client requested.

    Unfortunately, in every instance I've tried so far, passing a "DataServiceVersion" header to an OData 4.0 service results in a 500 Internal Server Error response (with no OData-Version header). So it would seem that sending both OData-Version and DataServiceVersion headers isn't guaranteed to work.

    Best bet seems to be sending OData-Version and then looking for a DataServiceVersion response header (which will likely be "1.0" even for a service that supports 3.0). If that header is present in the response, then send a second request with a DataServiceVersion header of "3.0". If you get a 4xx response, then try "2.0" etc.