Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 24

A NEW JSON FORMAT FOR ODATA

Copyright 2011, 2012 Microsoft Corporation

CONTENTS
Introducing the New JSON Format......................................................................................3
Motivation...........................................................................................................................3
JSON Format Design............................................................................................................3
Response payload samples.................................................................................................5
Entry................................................................................................................................5
Feed.................................................................................................................................6
Property...........................................................................................................................7
Entry with expanded navigation links.............................................................................8
Service document............................................................................................................9
Entity reference links.....................................................................................................10
Top-level (streaming) collections...................................................................................11
Error...............................................................................................................................12
Request payload samples.................................................................................................13
Entry..............................................................................................................................13
Entry with deep inserts..................................................................................................13
Entry with binding operations (insert or update)..........................................................14
Property.........................................................................................................................15
Entity reference links.....................................................................................................15
Parameters....................................................................................................................15
The Metadata URL.............................................................................................................17
Relative URLs....................................................................................................................18
Null Payloads.....................................................................................................................19
Annotations.......................................................................................................................19
Well-known annotations................................................................................................20
Controlling the amount of control information in the payload..........................................20
odata=minimalmetadata...............................................................................................21
odata=fullmetadata......................................................................................................21
odata=nometadata.......................................................................................................22
Heuristically Detectable Primitive Types...........................................................................22
Content Type and Payload Ordering Constraints..............................................................23
Metadata Expressions.......................................................................................................24
1

Specifying a Convention Set..........................................................................................24


The Default Convention Set...........................................................................................25
The Azure Convention Set.............................................................................................25

INTRODUCING THE NEW JSON FORMAT


OData v3 introduces a new JSON format that is both capable of the full expressiveness of
the other OData formats and also is an order of magnitude more compact on the wire.
Throughout our early stages of thinking, we referred to this format as JSON Light. In this
document we refer to the format simply as the JSON format as we plan to eventually
deprecate JSON Verbose, meaning that there will not be any confusion when we simply
say JSON format.

MOTIVATION
Prior to OData v3, the OData protocol had two supported serialization formats a format
based on AtomPub and a different JSON format (referred to hereafter as JSON Verbose).
Each of these formats assumed the control data (that is, the metadata that powers
much of OData) must be included on the wire. This resulted in two fundamental
problems:
1. Payload size. By design, AtomPub and JSON Verbose carry a significant amount of
metadata on the wire, increasing the payload size of requests and responses.
2. Ease-of-use for JavaScript processors:
Materializing objects from an AtomPub payload is not a trivial problem to solve

from a JavaScript processor.


Although it follows the JSON standard, JSON Verbose has a set of wrapper
objects (especially around collections) that make the format hard to use in
JavaScript processors/libraries (such as jQuery) since the wrapper objects are
commingled with actual data. As a result extracting the actual data is more
difficult than it should be.

The increasing popularity of mobile devices and simple JavaScript clients has made it
more important than ever to have a serialization format that is both compact and trivial
to parse. These are the problems the new JSON format attempts to solve.

JSON FORMAT DESIGN


A few requirements guided the development of the JSON format; the most important
requirements are listed below as a frame of reference but are not discussed in detail.

Payload size should be minimized without compromising control data


Requests should be easy to create from JavaScript
Responses should be easy to consume from JavaScript
Extensibility is desirable for future OData requirements
Responses should be both streamable and bufferable
No out-of-band information should be required for clients
If out-of-band information is available, the format should not require much control
data

In order to make the new format easy to process by JavaScript clients, the only logical
conclusion is to continue to support a JSON format. Looking at current JSON Verbose and
AtomPub payloads, a significant amount of the payload is highly predictable (for
example, the edit links for all the entries in a feed might only differ in the value of the
key property of the entry but otherwise be identical). The key change in this format is to
remove all the predictable parts of the wire format from the actual payload. To
reconstitute this data on the receiving end, expressions are used to compute missing
links, type information, and other control data. These expressions (together with the
data on the wire) can be used by the client to recompute all the predictable payload
pieces as if they had been included on the wire directly.
The extensibility story of the new JSON format revolves around so-called annotations in
the payload. Annotations are used to add control information to a JSON payload. Such
annotations can refer to a JSON object or a JSON property and provide additional
information about the instance (or property). OData defines a set of annotations and
custom annotations can be adding domain-specific control information to the payload.
Annotations are used in JSON to capture control information that cannot be predicted
(e.g., the next link of a feed) as well as to provide a mechanism to provide values where
a computed value would be wrong (e.g., if the stream read link of one particular entry
points to a different server than the metadata expression for all the other entries
specifies). Computing values from metadata expressions is compute intensive and some
clients might opt for a larger payload size to avoid computational complexity; as a result
the Accept header allows the client to control the amount of control information included
on the wire.
To make JSON payloads support streaming scenarios, we put in place a few restrictions
with respect to the order in which data must appear on the wire. For details on the
ordering requirements, see Content Type and Payload Ordering Constraints

RESPONSE PAYLOAD SAMPLES


This section provides JSON samples of response payloads for the payload kinds
supported in OData. The samples are based on a fictitious Soupon domain.

Entry
http://.../Soupon.svc/Soupons(1)/?$format=json
{

"odata.metadata": "http://.../Soupon.svc/$metadata#Soupons/@Element",
"#SouponContext.Buy": {},
"ID": 1,
"Name": "Rustic Italian Tortellini Soup",
"Description": "This is my favorite soup recipe. It's quick to fix on a busy night and full
of healthy, tasty ingredients. It originally called for spicy sausage links, but I've found that
turkey sausage, or even ground turkey breast, is just as good. \u2014Tracy Fasnacht, Irwin,
Pennsylvania",
"Price": "1.85754591173378",
"DealExpiresAt": "2012-10-06T02:21:16.4908996-07:00",
"ImageUrl": "http://.../pic.jpg",
"Rating": 5.0,
"NumberOfReviews": 46,
"Ingredients": ["3 Italian turkey sausage links (4 ounces each), casings removed", "1
medium onion, chopped", "6 garlic cloves, minced", "2 cans (14-1/2 ounces each) reducedsodium chicken broth", "1-3/4 cups water", "1 can (14-1/2 ounces) diced tomatoes,
undrained", "1 package (9 ounces) refrigerated cheese tortellini", "1 package (6 ounces)
fresh baby spinach, coarsely chopped", "2-1/4 teaspoons minced fresh basil or 3/4 teaspoon
dried basil", "1/4 teaspoon pepper", "Dash crushed red pepper flakes", "Shredded Parmesan
cheese, optional"],
"Category": "Soup"
}

Comments:

The odata.metadata property is an instance annotation that describes the kind


and type of the payload. More details on the odata.metadata property can be

found in The Metadata URL.


Ingredients is a property that has a collection of strings.
#SouponContext.Buy is a hyperlink that allows invocation of an action. This
hyperlink is relative, making the absolute URL of the action http://.../Soupon.svc/
$metadata#SouponContext.Buy.

All other properties are regular data as you would expect in a JSON representation

of a customer.
Note in particular that no navigation properties are present in the payload since
they are control information (e.g., the navigation link) that can be computed from
metadata expressions.

Feed
5

http://.../Soupon.svc/Users/?$inlinecount=allpages&$format=json
{

"odata.metadata": "http://.../Soupon.svc/$metadata#Users",
"odata.count": "11",
"value": [{
"UserID": "pilack",
"DisplayName": "Pilar Ackerman",
"JoinedAt": "2010-11-30T11:51:21.2265317-07:00",
"LastSeenAt": "2012-09-11T11:51:21.2265317-07:00",
"BillingAddress": {
"Line1": "12345 Grant Street",
"Line2": null,
"City": "Taft",
"State": "Ohio",
"ZipCode": "98052"
},
"FavoriteTags": ["gazpacho", "tomato", "vegetarian"]
},
... ],
"odata.nextLink": "..."

Comments:

For non-object payloads we need a wrapper object at the top-level to store the
odata.metadata property as well as other control information (e.g. the next link or

count in the case of a feed, or the type name of an open primitive property).
o Note that when a wrapper object is used, the actual results are always
o

stored in the value of the value property.


For payloads that are represented as top-level object (e.g., entities), no

wrapper is needed.
This payload reflects some of the ordering necessary for streaming feeds:
o odata.metadata appears first in the payload.
o odata.nextLink appears last in the payload.
BillingAddress is a complex property that appears as a normal JSON object.

Property
http://.../Soupon.svc/Users('pilack')/DisplayName?$format=json
{
"odata.metadata": "http://.../Soupon.svc/$metadata#Edm.String",
"value": "Pilar Ackerman"
}

http://.../Soupon.svc/Users('pilack')/FavoriteTags?$format=json
{
"odata.metadata": "http://.../Soupon.svc/$metadata#Collection(Edm.String)",
"value": ["gazpacho", "tomato", "vegetarian"]
}

http://.../Soupon.svc/Users('pilack')/BillingAddress?$format=json
{
"odata.metadata": "http://.../Soupon.svc/$metadata#Soupon.BillingAddress",
"Line1": "12345 Grant Street",
"Line2": null,
"City": "Taft",
"State": "Ohio",
"ZipCode": "98052"
}

Comments:

The first sample shows a primitive property payload.


The second sample shows a collection property payload.
The third sample shows a complex type property payload.

Entry with expanded navigation links


http://.../Soupon.svc/Users('pilack')?$expand=PurchasedSoupons&$format=json
{
"odata.metadata": "http://.../Soupon.svc/$metadata#Users/@Element",
"UserID": "pilack",
"DisplayName": "Pilar Ackerman",
"JoinedAt": "2010-11-30T12:13:41.5334422-07:00",
"LastSeenAt": "2012-09-11T12:13:41.5334422-07:00",
"BillingAddress": {
"Line1": "12345 Grant Street",
"Line2": null,
"City": "Taft",
"State": "Ohio",
"ZipCode": "98052"
},
"FavoriteTags": ["gazpacho", "tomato", "vegetarian"],
"PurchasedSoupons": [{
"ID": 11,
"Name": "Apricot Nutmeg Bread",
...
}, {
"ID": 1,
"Name": "Rustic Italian Tortellini Soup",
...
}
],
"PurchasedSoupons@odata.nextLink": "...",
}

Comments:

The sample above shows a user with an expanded PurchasedSoupons navigation

property.
In some OData servers, expanded navigation properties tend to appear before

other properties because of how the request is processed.


The next link for the expanded navigation property must come after the property
for streaming scenarios.

Service document
http://.../Soupon.svc/?$format=json
{
"odata.metadata": "http://.../Soupon.svc/$metadata",
"value": [{
"name": "Soupons",
"url": "Soupons"
}, {
"name": "Users",
"url": "Users"
}
]

Comments:

The service document contains an array of JSON objects that represent the entity

sets.
Each JSON object contains the name of the entity set as well as its URL (either
absolute or relative to the odata.metadata URL).

Entity reference links


http://.../Soupon.svc/Users('haoche')/$links/ReferredBy?$format=json
{
"odata.metadata": "http://.../Soupon.svc/$metadata#Users/$links/ReferredBy",
"url": "Users('pilack')"
}

http://.../Soupon.svc/Users('pilack')/$links/PurchasedSoupons/
{
"odata.metadata": "http://.../Soupon.svc/$metadata
#Users/$links/PurchasedSoupons",
"value": [{
"url": "Soupons(11)"
}, {
"url": "Soupons(1)"
}
]
}

http://.../Soupon.svc/Users('pilack')/$links/PurchasedSoupons(1)/
{
"odata.metadata": "http://.../Soupon.svc/$metadata
#Users/$links/PurchasedSoupons/@Element",
"url": "Soupons(1)"

Comments:

All URLs must either be absolute or relative to the odata.metadata URL.


The first sample shows the entity reference link for the ReferredBy navigation

property, which has a cardinality of one.


The second sample shows the entity reference links for PurchasedSoupons

navigation property, which has a cardinality of many.


The third sample is similar to the first one in that it has a single entity reference
link, but this time the sample is a single entity reference link selected from the
set of PurchasedSoupons by adding a key selector. Note how the @Element item
selector in the metadata URL indicates that the payload is a single item from a
collection; more on the metadata URL and its structure can be found in The
Metadata URL.

10

Top-level (streaming) collections


http://.../Soupon.svc/GetTopFiveCustomers?$format=json
{
"odata.metadata": "http://.../Soupon.svc/$metadata#Collection(Edm.String)",
"value": ["haoche", "pilack", "garyou", "amystr", "jayham"]
}

Comments:

A top-level (streaming) collection is a streaming collection of primitive or complex

values produced by an operation (service operation, function or action).


Note that the only difference between a top-level collection property and a toplevel streaming collection is that the metadata URL for a (collection) property
points to a property while it points to a function import in the streaming collection
case.

11

Error
http://.../Soupon.svc/Users?$format=json&$badqueryoption=true
{
"error": {
"code": "",
"message": {
"lang": "en-US",
"value": "The query parameter '$badqueryoption' begins with a systemreserved '$' character but is not recognized."
}
}
}

Comments:

Note that error payloads do not have a metadata URL.


Also note that top-level error payloads and in-stream errors share the same
format on the wire.

12

REQUEST PAYLOAD SAMPLES


In OData, request payloads can be entries, entity reference links, properties and
parameters. Request payloads do not require metadata URLs (the assumption is that the
server processing a request has all the required information already via the request URL
sent to it). However, if the request does include the metadata URL, relative URLs can be
used in the request payload.
Other than the missing metadata URL, request payloads are very similar to response
payloads. The details for each request payload are described below.

Entry
{

"BillingAddress": {
"City": "Clinton",
"Line1": "23456 Cleveland St",
"Line2": null,
"State": "TX",
"ZipCode": "98052"
},
"DisplayName": "David Hamilton",
"FavoriteTags": [],
"JoinedAt": "2012-10-05T14:14:43.1229977-07:00",
"LastSeenAt": "2012-10-05T14:14:43.1269991-07:00",
"UserID": "davham"

Comments:

A typical entry can be (modified and) round-tripped to the server directly.


The odata.metadata annotation can but does not have to be removed; the server
will ignore it if it is present.

Entry with deep inserts


{

"ReferredBy": {
"BillingAddress": {
"City": "Polk",
"Line1": "23456 Taylor St",
"Line2": null,
"State": "NV",
"ZipCode": "98052"
},
"DisplayName": "Sanjay Patel",
"FavoriteTags": [],
"JoinedAt": "2012-10-03T18:14:43.1229977-07:00",
"LastSeenAt": "2012-10-03T20:14:43.1269991-07:00",
"UserID": "sanpat"
},
"BillingAddress": {
"City": "Clinton",

13

"Line1": "23456 Cleveland St",


"Line2": null,
"State": "TX",
"ZipCode": "98052"
},
"DisplayName": "David Hamilton",
"FavoriteTags": [],
"JoinedAt": "2012-10-05T14:14:43.1229977-07:00",
"LastSeenAt": "2012-10-05T14:14:43.1269991-07:00",
"UserID": "davham"
}

Comments:

The above payload can be used when inserting a new order and at the same time

inserting a customer and order details.


The format for this payload kind (again modulo the odata.metadata annotation) is
the same as for the response payload.

Entry with binding operations (insert or update)


{

"ReferredBy@odata.bind": "http://./Soupon.svc/Users('haoche')",
"BillingAddress": {
"City": "Clinton",
"Line1": "23456 Cleveland St",
"Line2": null,
"State": "TX",
"ZipCode": "98052"
},
"DisplayName": "David Hamilton",
"FavoriteTags": [],
"JoinedAt": "2012-10-05T14:14:43.1229977-07:00",
"LastSeenAt": "2012-10-05T14:14:43.1269991-07:00",
"UserID": "davham"

Comments:

When inserting or updating an entry (an order in this sample), relationships of

navigation properties can be changed via bind operations.


A bind operation is encoded as a property annotation on the property it belongs
to and has a single value (for singleton navigation properties) or an array of

values (for collection navigation properties).


Note that the above payload shows that for insert scenarios, collection navigation
property bind operations and deep insert operations can be combined. In this
case, the bind operations have to appear before the deep insert operations in the

payload.
In update scenarios, only bind operations but not deep inserts are allowed.

Property
{

14

}
{

"value": "Pilar Ackerman"

"City": "Polk",
"Line1": "23456 Taylor St",
"Line2": null,
"State": "NV",
"ZipCode": "98052"

}
{
}

"value": ["gazpacho", "tomato"]

Comments:

Property payloads in requests do not differ from property payloads in responses


(modulo the odata.metadata annotation).

Entity reference links


{

"url": "http://.../Soupon.svc/Users('pilack')"

Comments:

As with property payloads, entity reference link payloads do not differ from the
response format (modulo the odata.metadata annotation).

Parameters
{
"param1": 42,
"param2": {
"Street": "One Microsoft Way",
"Zip": 98052
},
"param3": [ 1, 42, 99 ]
}

Comments:

Parameter payloads are only supported in requests.


The values of a parameter record follow the same format rules as values for
primitive, complex and collection properties.

15

THE METADATA URL


The metadata URL (i.e., the value of the odata.metadata annotation) allows the recipient
to precisely identify the contents of the payload. For example, a recipient can
differentiate between payloads that contain a feed, entity type, collection type, complex
type or primitive type. This information (in combination with knowledge of the EDM
backing the service) allows the recipient to materialize the payload correctly.
How to read the tables below:
URL format in pseudo-routing
Category

syntax
Sample URL
Metadata URL for sample
Comments (Optional)

Metadata URL Formats


Feed

{metadata-url}#{entity-set}
http://.../Soupon.svc/Soupons
http://.../Soupon.svc/$metadata#Soupons
If the entity set is in an entity container that has the
IsDefaultEntityContainer attribute set to true, the entity set may be
unqualified. If the entity set is in an entity container that has no
IsDefaultEntityContainer attribute (or the value of the attribute is false),
the entity set must be namespace and container qualified.

Feed of
Derived
Elements

Element

{metadata-url}#{entity-set}/{type-cast}
http://.../Soupon.svc/Soupons/Soupon.FeaturedSoupon
http://.../Soupon.svc/$metadata#Soupons/Soupon.FeaturedSoupon
If a feed consists exclusively of derived elements, a type cast segment is
added to the metadata URL.
{metadata-url}#{entity-set}/@Element
http://.../Soupon.svc/Soupons(1)
http://.../Soupon.svc/$metadata#Soupons/@Element
If a response is guaranteed to contain only a single entry from a feed,
/@Element is appended to the metadata URL. This is also true for links
payloads.

Derived
Element

{metadata-url}#{entity-set}/{type-cast}/@Element
http://.../Soupon.svc/Soupons(1)/Soupon.FeaturedSoupon
http://.../Soupon.svc/
$metadata#Soupons/Soupon.FeaturedSoupon/@Element
If a response is guaranteed to contain only a single element of a derived
type, /<Type>/@Element is appended to the metadata URL.

Complex
16

{metadata-url}#{namespace}.{type-name}

or
Primitive
Type
Property
Collectio
n Type
Property

Null

http://.../Soupon.svc/Soupons(1)/Name
http://.../Soupon.svc/$metadata#Edm.String
If a response is a complex type or primitive type, the metadata URL
contains the fully qualified type of the property.
{metadata-url}#Collection({namespace}.{type-name})
http://.../Soupon.svc/Soupons(1)/Tags
http://.../Soupon.svc/$metadata#Collection(Edm.String)
If a response is a collection of complex types or primitive types, the
metadata URL names the type of the property.
{metadata-url}#Edm.Null
http://.../Soupon.svc/Soupons(1)/Description
http://.../Soupon.svc/$metadata#Edm.Null
If a response is a null collection, complex or primitive type property, the
metadata URL fragment is simply Edm.Null.

Operatio
n Result

{metadata-url}#{entity-set-or-type-name}
http://.../Soupon.svc/GetTopFiveCustomers
http://.../Soupon.svc/$metadata#Users
A response from an operation (service operation, action, function) has a
metadata URL that identifies the type returned by the operation. The
metadata URL will correspond to one of the former examples.

Service
Doc

Entity
Referenc
e Links

{metadata-url}
http://.../Soupon.svc/
http://.../Soupon.svc/$metadata
{metadata-url}#{entity-set}/$links/{nav-prop}[/@Element]
http://.../Soupon.svc/Users('pilack')/$links/PurchasedSoupons(1)
http://.../Soupon.svc/$metadata
#Users/$links/PurchasedSoupons/@Element
If a response is guaranteed to contain only a single element from a
navigation property with cardinality of many, /@Element is appended to
the metadata URL.

RELATIVE URLS
As noted previously, a significant amount of the payload for AtomPub and JSON Verbose
has to do with redundant data. This redundant data frequently manifests in the format of
very similar URLs. One benefit of the metadata URL is that, when present, the metadata
URL provides a consistent base for expanding relative URLs into absolute URLs.
As a general rule, whenever the metadata URL is present in a payload (whether request
or response), the URLs in the payload are allowed to be represented as relative URLs.

17

The processor expanding the URLs should use normal URL expansion rules and use the
metadata URL as a base.

NULL PAYLOADS
An attempt to access or update a collection, complex or primitive type property may
require a null payload. (Note: this is not true of an attempt to access an entity type
property, as there is no concept of null for entity types the result would simply be a
404 Not Found.) In all cases, the null payload is represented as follows:
{
}

"odata.metadata":"http://.../Soupon.svc/$metadata#Edm.Null"

A null payload is the only request payload that requires the metadata URL to be
included in the body of the request. This is because an empty string is not valid JSON,
and a payload that consisted merely of the object begin and end braces would indicate
that all properties on the object should be reset to their defaults.

ANNOTATIONS
Annotations are an extensibility mechanism that allow servers and clients to include
information other than the raw data in the request or response. Annotations are used to
include control information in many payloads. For example, the odata.metadata
annotation is included in almost all payloads.

Annotations are easily identifiable as properties that have a dot ('.') in the name

of the property.
There are two types of annotations:
o Instance annotations annotate the object that contains the annotation
o

(e.g., odata.metadata, odata.nextLink, etc.).


Property annotations annotate a property or an object stored in a property.
The property is always named in the annotation (e.g.,
PurchasedSoupons@odata.navigationlinkurl, etc.). The format is always

<property>@<annotation>.
Instance annotations are commonly used when annotating a value that is a JSON

object; property annotations must be used to annotate a value that is a primitive


value or an array (in both cases there is no place to put the annotation inside the
value). Property annotations are also used to provide annotations for values that
are not present in the payload (e.g., there is no JSON property for a navigation
property in the payload; instead the navigation link is specified via a property

annotation).
All annotations that start with 'odata.' are reserved for future extensions of the

protocol and format.


Custom annotations are annotations that have a non-empty prefix that is different
from 'odata.'. Custom annotations are currently ignored when reading payloads.

18

Well-known annotations
There are a number of annotations that are commonly seen in OData payloads.

odata.metadata specifies the metadata URL for the payload


odata.type specifies the type of the annotated object if the type is not a

heuristically detectable primitive type. This annotation is commonly used to


specify the type of:
o Entities derived from the type specified in the metadata URL
o Open properties (properties that exist on an open type but are not
declared in $metadata)

odata.count and odata.nextLink are used to annotate

o Feeds (at the top-level or inside an expanded collection property)


o Collections of entity reference links
The rest of the odata.* annotations are used to provide control information for an
entry. Note that the control information for an entry is usually computed and
therefore is not included in the wire format. odata.* annotations can exist in the
payload to accommodate exceptions to computed control information (e.g., a
custom edit link).
o Instance annotations are used for the ID, ETag, read link, edit link, media
read link, media edit link, media content type, media ETag, actions and
o

functions of an entry.
Property annotations are used to describe the navigation and association
links of a property, the read link, edit link, content type and ETag of a

named stream
The amount of control information in the payload can also be controlled via the

Accept header.
An example that shows all the OData instance and property annotations in the
payload, i.e., if none of the control information would be computed from
metadata expressions, is available in odata=fullmetadata.

CONTROLLING THE AMOUNT OF CONTROL


INFORMATION IN THE PAYLOAD
The amount of control information needed (or desired) in the payload depends on the
client application and device. The odata parameter can be applied to the Accept header
of an OData request to influence how much control information will be included in the
payload. For the purpose of this section, we will take the following two assumptions:
1. The media-range for the Accept header is set to application/json
2. Other Accept header parameters (e.g., streaming) are orthogonal to the odata
parameter and are therefore not mentioned in this section
If a client prefers a very small wire size and is intelligent enough to compute data using
metadata expressions, the Accept header should include odata=minimalmetadata. If
compute is more expensive than wire size or the client is incapable of computing control
19

information, odata=fullmetadata directs the server to inline the control information that
normally would be computed from metadata expressions in the payload.
odata=nometadata is an option for clients that have out-of-band knowledge of the

expected payload kind and type and thus don't need any control information.

odata=minimalmetadata
odata=minimalmetadata is the default value for the odata parameter and will be

assumed if no other value is specified in the Accept header. odata=minimalmetadata


indicates that the server should remove computable control information from the
payload wherever possible. The response payload will still contain common annotations
such as odata.metadata, odata.nextLink, and odata.count. odata.type will only appear if
the type is not heuristically detectable and one of the following is true:

The type is derived from the type specified for the feed
The type is for an open property

Note that more odata.* annotations will appear in the payload if their actual values are
not the same as the computed values (or the server is incapable of removing them).
When odata.* annotations appear in the payload, they must be treated as exceptions.

odata=fullmetadata
In cases where the client is incapable of or unwilling to compute control information,
odata=fullmetadata instructs the server to include all control information explicitly in the

payload. This, of course, will reintroduce some of the redundancies and inefficiencies of
the JSON Verbose format but is a way less capable or resource constrained clients can
work with the new JSON format.
Note that it is very important for servers to respect this value of the odata parameter. If
a client requests full metadata but only gets back minimal metadata, it is quite possible
that the client will not accurately interpret the response.
The full list of annotations that may appear in an odata=fullmetadata response are as
follows:

20

odata.metadata: the metadata URL of the payload.


odata.count: the inline count of a feed or collection of entity reference links.
odata.nextLink: the next link of a feed or collection of entity reference links.
odata.id: the ID of the entry.
odata.etag: the ETag of the entry.
odata.readLink: the link used to read the entry.
odata.editLink: the link used to edit/update the entry.
odata.mediaReadLink: the link used to read the default stream of an MR/MLE entry.
odata.mediaEditLink: the link used to edit/update the default stream of an MR/MLE

entry.
odata.mediaETag: the ETag of the default stream of an MR/MLE entry.

odata.mediaContentType: the content type of the default stream of an MR/MLE

entry.
odata.actions: the array of actions specified for the entry. * TODO: This is out of

date.
odata.functions: the array of functions specified for the entry. * TODO: This is out

of date.
odata.navigationLinkUrl: the link used to retrieve the values of a navigation

property.
odata.associationLinkUrl: the link used to describe the relationship between this

entity a related entity.


odata.type: the type name of the containing object or targeted property.

odata=nometadata
When the client specifies that no control information should be included in the payload,
it is assumed that the client has out-of-band knowledge of the payload kind and data
types in the payload (or does not care). In this case, the odata.metadata annotation is
omitted from the payload otherwise the same set of control information as in the
default option is present in the payload (including the odata.nextLink and count
annotations as well as exceptions to the values that would be computed from metadata
expressions.)

HEURISTICALLY DETECTABLE PRIMITIVE TYPES


In addition to absolute URLs, the odata.type annotation has historically been a primary
cause of payload bloat. With the new JSON format we apply a heuristic to try to prevent
the need for stating odata.type when the type is obvious.
The new JSON format contains a heuristic that allows us to identify four primitive types
without an odata.type annotation:

Integral values have a first class representation in JSON and do not need any
additional annotations. If the value of a property is represented as a number
without a . embedded, the type should be interpreted as an integral value.
(Note: Int64 values are represented as strings due to the fact that JavaScript

integers lose precision past 15 digits.)


Similarly, double values can use the same representation and do not need any
additional annotations. If the value of a property is represented as a number with

a . embedded, the type should be interpreted as a double value.


Boolean values have a first class representation in JSON and do not need any

additional annotations.
String values do have a first class representation in JSON, but there is an obvious
collision: OData also encodes a number of other primitive types as strings, e.g.
DateTime, Int64, etc. In this case, we are able to apply a simple process-of-

21

elimination heuristic: if the property appears in JSON string format, it should be


treated as a string value unless the property is known to have a different type.
TODO: Insert some examples.

CONTENT TYPE AND PAYLOAD ORDERING


CONSTRAINTS
A JSON request or response payload has a content type of
application/json;odata=minimalmetadata|fullmetadata|nometadata. Starting in V3 of the

OData protocol, the content type application/json (without any parameters) will be
interpreted as application/json;odata=minimalmetadata. In previous versions the
application/json content type meant the JSON Verbose format. The JSON Verbose format

is still supported in V3 by requesting application/json;odata=verbose.


As mentioned at the beginning of this document, one of the design goals of this format
was to support streaming scenarios. In order to achieve this, some payload ordering
constraints must be imposed. We realize, however, that some clients (and servers) will
not be able to control the order of the JSON properties in the payload or might not care
about streaming at all. As a result, the payload ordering constraints described in the rest
of this section are not mandatory for JSON. Processors can only assume streaming
support if it is explicitly indicated in the content type via the streaming=true parameter.
A payload with content type application/json;odata=minimalmetadata;streaming=true can
thus be assumed to support streaming whereas a payload with content type
application/json;odata=minimalmetadata cannot. JSON producers are encouraged to

follow the payload ordering constraints whenever possible (and include the
streaming=true content type parameter) to support the maximum set of client scenarios.

To support streaming scenarios the following payload ordering constraints have to be


met:

If present, the odata.metadata annotation has to be the first property in a

response payload
o Request payloads do not have an odata.metadata annotation
Annotation groups must come immediately after the odata.metadata annotation
The odata.type annotation must appear next in the payload.
The odata.id and odata.etag annotations must appear before any property or

property annotation.
All property annotations for property SomeProperty have to appear as a group
immediately before the property itself. Note that the one exception to this rule is
the SomeProperty@odata.nextlink annotation of an expanded collection navigation
property; the next link can oftentimes only be computed after all the entries in a
feed have been written and thus is allowed to appear after the SomeProperty
property.

22

All other odata.* annotations can appear anywhere in the payload (as long as they

are not violating any of the above rules).


Annotations for navigation properties must not appear before any of the data
properties.

METADATA EXPRESSIONS
Metadata expressions are either specified in the metadata document (returned from the
$metadata endpoint of an OData service) using CSDL annotations or are derived from
well-known convention sets. Metadata expressions represent instructions how to
compute parts of the OData control information for an entry. When reading an OData
payload, these expressions are then used to compute control information that has been
omitted from the payload. They are also used to guide a URL builder when producing
request URLs for a query. As a result, the metadata expressions give you a way to
completely customize the URL scheme you use with your service.
Fully customizable metadata expressions are a very desirable feature, however they are
not currently on the OData roadmap. There will be two sets of URL conventions initially
supported in the JSON format: the Default set and a set of conventions used for Azure.

Specifying a Convention Set


Note: This section has not been updated recently. There is a clear need to define
interaction behavior for custom convention sets, however the impact on requests and
responses has not yet been decided.
There is currently some debate about what the final declaration of convention sets will
look like, however, this section reflects our current thinking.
A convention set is currently specified at an entity container level. In the future we will
support more granular application of convention sets. A convention set is applied using a
distinct vocabulary term that is recognizable by clients. For instance, the following
example demonstrates application of the default convention set:
<EntityContainer Name="MyContainer" m:IsDefaultEntityContainer="true">
<ValueAnnotation Term="Org.OData.V1.UseDefaultUrlConventions" Boolean="true" />
</EntityContainer>

The Default Convention Set


The default convention set is assumed. If no URL convention vocabulary annotation is
applied to the entity container, clients should use the default conventions to build URLs.
It is possible to apply the Org.OData.V1.UseDefaultUrlConventions term to explicitly
declare that the entity container uses the default URL building conventions.
23

The Azure Convention Set


Azure services have a unique set of URL building conventions. In some cases, the Azure
conventions support keys as traditional slash-delimited URL segments (the default
conventions use parens to delimit key segments). There are also some other unique
characteristics of Azure URLs that can be declared by applying the
Com.Microsoft.Azure.V1.UseAzureUrlConventions vocabulary term. For instance:
<EntityContainer Name="MyContainer" m:IsDefaultEntityContainer="true">
<ValueAnnotation Term="Com.Microsoft.Azure.V1.UseAzureUrlConventions" Boolean="true" />
</EntityContainer>

24

You might also like