Skip to main content

OData Version 4.0 is the current recommended version of OData. OData V4 has been standardized by OASIS and has many features not included in OData Version 2.0.

Go to OData Version 4.0

Introduction

The OData protocol exposes a uniform service interface to operate on collections of structured and unstructured data. Most of the semantics of operations in OData come from the AtomPub protocol [RFC5023], which in turn builds on top of HTTP [RFC2616].

This document describes the operation model for the protocol, specifying the interactions between clients and servers for retrieving and manipulating data in an OData service. It builds on the [OData-Core] document for core concepts, [OData-URI] for URI conventions and on the formats specifications for Atom [OData-Atom] and JSON [OData-JSON] for the description of data representations.

1. Background

1.1 Representation formats and content type negotiation

OData supports two formats for representing resources, the XML-based Atom format and the JSON format. As described in the HTTP specification [RFC2616], clients can indicate their preference of resource representation by including an accept request header with a list of MIME types it can handle.

A client that wants only JSON responses would set this header to "application/json". For example:

GET /OData/OData.svc/Products HTTP/1.1 host: services.odata.org accept: application/json

For the Atom format there is more than one MIME type involved. Atom feeds and Entries use a content type of "application/atom+xml". However, when addressing Links or properties within an element the returned resource is just XML without the Atom Entry wrapper, and its content type is "application/xml". AtomPub also introduces service documents, with a content-type of "application/atomsvc+xml". Clients can choose to support only specific content-types or all of them. To indicate it can handle all of them a client would set the accept header to "application/atom+xml, application/atomsvc+xml, application/xml". For example:

GET /OData/OData.svc/Products HTTP/1.1 host: services.odata.org 
  accept: application/atom+xml,application/atomsvc+xml,application/xml

Servers are expected to honor the client request for a format or fail with status code 406 (Not Acceptable). While HTTP 1.1 allows servers to return alternate representations when none of the requested ones are available, OData servers should return one of the requested representations or fail.

If a request does not have an accept header servers should default to the Atom representation.

Since in certain scenarios it is not possible for clients to control request headers, OData also has an optional query string option called $format that can be used to override the value of the request header (e.g. $format=json or $format=atom). This option is further described in [OData-URI].

When sending a resource as part of a request or a response body, clients and servers should set the corresponding MIME type in the content-type header.

1.2 Additional considerations on the use of HTTP

OData heavily builds on HTTP for its interaction model. In addition to content-type negotiation clients and servers should use HTTP mechanisms for aspects such as character set negotiation (through accept-charset and content-type headers), caching and redirection.

Similarly, while this specification uses specific status codes for specific outcomes for a request, clients should be prepared to handle all HTTP status codes and interpret them appropriately.

1.3 Error Conditions

Error conditions are in general exposed as HTTP responses with error status codes (4xx and 5xx). Individual descriptions of operations in this specification do not call out error conditions. Servers should map error conditions to HTTP status codes. Common examples include using 404 (Not Found) when receiving requests against a URI not defined by this server, 400 for a general error in the request and 500 for a server-side error while processing the request.

Clients should be prepared to handle HTTP error codes in all requests.

In addition to the status code, servers should include a response body for error responses that includes more information about the error condition. The level of detail and nature of the information should be appropriate for the level of exposure of the service so as not to expose sensitive information to untrusted clients. The format for error messages is described in [OData-Atom] and [OData-JSON].

1.4 Protocol Versioning

In order to provide a safe mechanism for evolution of the protocol OData has a versioning scheme. While OData is designed such that it can operate to certain extent without the use of version headers, clients and servers are strongly encouraged to follow the protocol versioning scheme. Details of OData versioning are covered in [OData-Core].

All the examples in this document assume clients and servers that use version 2.0 of the protocol.

2. Operations

The OData service interface has a fixed number of operations that have uniform meaning across all the resources it can act on. These operations are retrieve, create, update and delete and they map to the GET, POST, PUT/MERGE and DELETE HTTP methods. Each of them acts on a resource that is indicated using a URI. In addition to the uniform interface operations, OData allows servers to expose custom operations (known as Service Operations) that can be invoked through GET or POST.

2.1 Retrieving feeds, Entries and service document

Clients retrieve a feed, Entry or service document by issuing an HTTP GET request against its URI. Servers respond with the feed, Entry or service document in the response body in the proper format. For example, to request the feed of products in the Atom-based format from an example product catalog OData service and its corresponding response:

Request:

GET /OData/OData.svc/Products HTTP/1.1 Host: services.odata.org 
  accept: application/atom+xml,application/xml 
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 

Response:

HTTP/1.1 200 OK Content-Length: 5685 Date: Sat, 27 Feb 2010 20:03:28 GMT Content-Type:
  application/atom+xml;charset=utf-8 DataServiceVersion: 1.0; 
<?xml version="1.0" encoding="utf-8" standalone="yes"?> 
<feed xml:base="https://services.odata.org/OData/OData.svc
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    xmlns="https://www.w3.org/2005/Atom"> 
  <title type="text">Products</title>
  <id>https://services.odata.org/OData/OData.svc/Products</id> 
  <updated>2010-02-27T20:03:28Z</updated>
  <Link rel="self" title="Products" href="Products" /> 
  <Entry> ... </Entry>
  <Entry> ... </Entry> 
  <Entry> ... </Entry> 
</feed>

To obtain a JSON response a client would issue the same request with a different accept header:

Request:

GET /OData/OData.svc/Products HTTP/1.1 Host: services.odata.org accept: application/json
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 

Response:

HTTP/1.1 200 OK Content-Length: 2481 Date: Sat, 27 Feb 2010 20:08:33 GMT Content-Type:
  application/json;charset=utf-8 DataServiceVersion: 1.0; { "d" : [ { ... }, { ...
  }, { ... }, ] } 

When a Collection is too large to be returned in a single response, servers can return a partial list of entries as defined in AtomPub. A feed for a partial list contains subset of the entries of the Collection and a link to the next (potentially partial) list. For example:

Request:

GET /Northwind/Northwind.svc/Customers HTTP/1.1 Host: services.odata.org accept:
  application/atom+xml,application/xml DataServiceVersion: 1.0 MaxDataServiceVersion:
  2.0 

Response:

HTTP/1.1 200 OK Content-Length: 28735 Date: Fri, 12 Mar 2010 18:05:49 GMT Content-Type:
  application/atom+xml;charset=utf-8 DataServiceVersion: 2.0; 
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="https://services.odata.org/Northwind/Northwind.svc/"
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    xmlns="https://www.w3.org/2005/Atom"> 
  <title type="text">Customers</title>
  <id>https://services.odata.org/Northwind/Northwind.svc/Customers</id>
  <updated>2010-03-12T18:05:49Z</updated> 
  <link rel="self" title="Customers" href="Customers" /> 
  <entry> ... </entry> 
  <entry> ... </entry>
  <entry> ... </entry> 
  <link rel="next"  
    href="https://services.odata.org/Northwind/Northwind.svc/Customers?$skiptoken='ERNSH'"
  /> 
</feed>

There are no expectations about stability of the data across requests while traversing partial lists. Clients should be prepared to deal with missing or repeating entries.

While in many cases clients will directly follow links provided externally or found in a service document to find and retrieve a feed for a Collection, often a client will want to further control how the feed is returned. OData provide a series of optional conventions to allow clients to filter, sort and page over data in Collections, we well as to request for a subset of the properties to be sent and to expand related entries inline. All these options are discussed in [OData-URI]. An example on this would be (before escaping the URL):

https://services.odata.org/OData/OData.svc/Products?$filter=Rating gt 2&$orderby=Price&$select=Rating,Price

this requests all products with a Rating greater than 2, sorted by Price in ascending order, and asks the server to only retrieve the Rating and Price properties.

2.2 Retrieving individual properties

Servers may support retrieval of individual properties within Entries. OData provides two ways of exposing individual properties, one that follows OData formats and another one that exposes the raw value of the property.

When using the optional OData URL conventions, the former has an address that follows the containing Entry with the property name (e.g. Products(1)/Description to obtain the value of the "Description" property), and the latter uses a $value suffix (e.g. Products(1)/Description/$value). More details in the Resource Path section of the [OData-URI] document.

To retrieve a property value using one of the OData formats a client issues an HTTP request against the property URI, and uses content-type negotiation to indicate the expected format. Since sub-Entry elements such as properties aren't represented as whole Atom Entries, clients that use the Atom format should use "application/xml" as the content type and should be prepared to handle an XML response that is not an Atom feed or Entry. This is described in further detail in [OData-Atom]. An example of a request to retrieve the "Description" property in a Product resource follows.

Request:

GET /OData/OData.svc/Products(1)/Description HTTP/1.1 Host: services.odata.org
  accept: application/xml DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 

Response:

HTTP/1.1 200 OK Content-Length: 158 Date: Sat, 27 Feb 2010 21:10:15 GMT Content-Type:
  application/xml;charset=utf-8 DataServiceVersion: 1.0; 
<?xml version="1.0" encoding="utf-8" standalone="yes"?> 
<Description xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">
  Low fat milk 
</Description>

To retrieve a property value in raw form a client issues an HTTP GET request against the property's raw value URL. Typically these values have a fixed content-type and negotiation is not supported (although servers are allowed to introduce this capability). Clients not having out of band knowledge of expected content-types should use "*/*" in their accept header (or not include an accept header in the request). For example:

Request:

GET /OData/OData.svc/Products(1)/Description/$value HTTP/1.1 Host: services.odata.org
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0

Response:

HTTP/1.1 200 OK Content-Length: 12 Date: Sat, 27 Feb 2010 21:16:05 GMT Content-Type:
  text/plain;charset=utf-8 DataServiceVersion: 1.0; Low fat milk 

2.3 Retrieving the metadata document

Servers may expose a metadata document that describes the structure of the service and its resources. Conventionally this document is located at the /$metadata address relative to the service root URI of the service. OData metadata documents are discussed in [OData-Core].

Clients can obtain the metadata document by issuing an HTTP GET request against the metadata URI. Since only an XML serialization of EDM schemas exist currently, no content-type negotiation is supported for this resource. Other HTTP aspects such as caching and character set encoding still apply.

2.4 Creating new Entries

Following the AtomPub protocol, new Entries are created by executing an HTTP POST request against the URI of the Collection where the Entry is to be created. The POST request includes the new Entry in its body, in one of the supported formats. For example:

POST /OData/OData.svc/Categories HTTP/1.1 Host: services.odata.org 
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 accept: application/atom+xml 
  content-type: application/atom+xml Content-Length: 634 
<?xml version="1.0" encoding="utf-8"?> 
<Entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
    xmlns="https://www.w3.org/2005/Atom">
  <title type="text"></title> 
  <updated>2010-02-27T21:36:47Z</updated>
  <author> 
    <name /> 
  </author> 
  <category term="DataServiceProviderDemo.Category"
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
  <content type="application/xml"> 
    <m:properties> 
      <d:ID>10</d:ID> 
      <d:Name>Clothing</d:Name>
    </m:properties> 
  </content> 
</Entry>

Note that the client indicates both the content-type of the request body and the accept header to indicate the format of the response body, if any.

The server processes the request by creating the resource, assigning default values to all the properties not indicated in the request that are optional, and sending the final state of the resource back to the client in the response, including a "location" header that contains the URL of the Entry that was created. HTTP status code 201 reflects that the Entry has been created. For example:

HTTP/1.1 201 Created Content-Length: 1072 Date: Sat, 27 Feb 2010 21:39:54 GMT
  Location: https://services.odata.org/OData/OData.svc/Categories(10) Content-Type:
  application/atom+xml;charset=utf-8 DataServiceVersion: 1.0; 
<?xml version="1.0" encoding="utf-8" standalone="yes"?> 
<Entry xml:base="https://services.odata.org/OData/OData.svc/"
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    xmlns="https://www.w3.org/2005/Atom"> 
  <id>https://services.odata.org/OData/OData.svc/Categories(10)</id>
  <title type="text"></title> 
  <updated>2010-02-27T21:39:54Z</updated>
  <author> 
    <name /> 
  </author> 
  <Link rel="edit" title="Category" href="Categories(10)" /> 
  <Link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products"
      type="application/atom+xml;type=feed" title="Products" 
      href="Categories(10)/Products"/> 
  <category term="DataServiceProviderDemo.Category" 
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> 
  <content type="application/xml"> 
    <m:properties> 
      <d:ID m:type="Edm.Int32">10</d:ID>
      <d:Name>Clothing</d:Name> 
    </m:properties> 
  </content> 
</Entry>

The Entry being created may contain Links to other Entries in the service. If that is the case the server is expected to create the Entry and the appropriate Links. For example, to create a new product in the catalog that is associated with the category Entry created above a client would execute a POST request against the OData.svc/Products collection with a product Entry (similar to the Category Entry above, with the proper adjustments for type information and property names and values) containing a Link to the Category Entry using any URI that resolves to that resource:

<Link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Category"
  type="application/atom+xml;type=Entry" title="Category" href="Categories(10)" />

or the equivalent in JSON format as described in the Representing Links section of [OData-JSON].

Alternatively a client can create and Link an Entry to a related Entry by leveraging the addressing scheme if the server supports addressing related items. For example, if a server implements the OData URI conventions described in [OData-URI], the address …/Categories(10)/Products points at all the products in the specified category. When a POST request is issued against that products collection (instead of the top-level products collection) the server will create the new product Entry and automatically Link it to the parent category. Clients may combine this method and the previous one to create an Entry that is related to another one implicitly through the relationship implied in the URL, and related to other Entries by explicitly-specified Links in the request body.

When a client needs to create multiple related Entries it can do so as independent operations or -if the Links between Entries allow it structurally- they can perform a single POST with a tree of Entries. The tree is formed by using inline expansion as described in [OData-Atom] and [OData-JSON]. All expanded Entries are considered new. Servers process a request with inline Entries by creating individual Entries and then Linking them in the same way Linking would have happened in an independent request. This example creates the same product category Entry as before, but also creates two products in it. While this example shows an inline feed with multiple Entries, single Entries without a wrapping feed are also allowed when the cardinality of the relationship represented by the Link allows it.

Request:

POST /OData/OData.svc/Categories HTTP/1.1 Host: services.odata.org DataServiceVersion:
  1.0 MaxDataServiceVersion: 2.0 accept: application/atom+xml 
  content-type: application/atom+xml Content-Length: 2626 
<?xml version="1.0" encoding="utf-8"?> 
<Entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
    xmlns="https://www.w3.org/2005/Atom">
  <title type="text"></title> 
  <updated>2010-02-27T21:36:47Z</updated>
  <author> 
    <name /> 
  </author> 
  <category term="DataServiceProviderDemo.Category" 
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
  <Link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products" 
      type="application/atom+xml;type=feed" title="Products" href="Categories(1)/Products"> 
    <m:inline> 
      <feed>
        <Entry> 
          <title type="text"></title> 
          <updated>2010-02-27T21:36:47Z</updated>
          <author> 
            <name /> 
          </author> 
          <category term="DataServiceProviderDemo.Product"
              scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
          <content type="application/xml"> 
            <m:properties> 
              <d:ID m:type="Edm.Int32">10</d:ID>
              <d:Name>T-Shirt</d:Name> 
              <d:Description>Just a T-Shirt</d:Description>
              <d:ReleaseDate m:type="Edm.DateTime">2010-01-01T00:00:00</d:ReleaseDate>
              <d:DiscontinuedDate m:type="Edm.DateTime" m:null="true" /> 
              <d:Rating m:type="Edm.Int32">0</d:Rating>
              <d:Price m:type="Edm.Decimal">15.0</d:Price> 
            </m:properties> 
          </content>
        </Entry> 
        <Entry> 
          <title type="text"></title> 
          <updated>2010-02-27T21:36:47Z</updated>
          <author> 
            <name /> 
          </author> 
          <category term="DataServiceProviderDemo.Product"
              scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
          <content type="application/xml"> 
            <m:properties> 
              <d:ID m:type="Edm.Int32">11</d:ID>
              <d:Name>Shorts</d:Name> 
              <d:Description>Running shorts</d:Description>
              <d:ReleaseDate m:type="Edm.DateTime">2010-01-01T00:00:00</d:ReleaseDate>
              <d:DiscontinuedDate m:type="Edm.DateTime" m:null="true" /> 
              <d:Rating m:type="Edm.Int32">0</d:Rating>
              <d:Price m:type="Edm.Decimal">21.0</d:Price> 
            </m:properties> 
          </content>
        </Entry> 
      </feed> 
    </m:inline> 
  </Link> 
  <content type="application/xml">
    <m:properties> 
      <d:ID>10</d:ID> 
      <d:Name>Clothing</d:Name>
    </m:properties> 
  </content> 
</Entry>

Response:

HTTP/1.1 201 Created Content-Length: 1072 Date: Sun, 28 Feb 2010 08:59:57 GMT
  Location: https://services.odata.org/OData/OData.svc/Categories(10) 
  Content-Type: application/atom+xml;charset=utf-8 DataServiceVersion: 1.0; 
<?xml version="1.0" encoding="utf-8" standalone="yes"?> 
<Entry xml:base="https://services.odata.org/OData/OData.svc/"
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    xmlns="https://www.w3.org/2005/Atom"> 
  <id>https://services.odata.org/OData/OData.svc/Categories(10)</id>
  <title type="text"></title> 
  <updated>2010-02-28T08:59:57Z</updated>
  <author> 
    <name /> 
  </author> 
  <Link rel="edit" title="Category" href="Categories(10)" /> 
  <Link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Products"
      type="application/atom+xml;type=feed" title="Products" 
      href="Categories(10)/Products"/> 
  <category term="DataServiceProviderDemo.Category" 
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/> 
  <content type="application/xml"> 
    <m:properties> 
      <d:ID m:type="Edm.Int32">10</d:ID>
      <d:Name>Clothing</d:Name> 
    </m:properties> 
  </content> 
</Entry>

2.5 Creating Media Link Entries (MLEs)

Media Link Entries (MLEs) are created by issuing a POST request against the collection the MLE should be created in, with the request body containing the Media Resource (MR) and the Content-Type header indicating its media type.

As described in AtomPub, servers should create both the MR and the MLE during the execution of the POST request, and return the URI of the MLE in the Location response header.

OData servers usually initialize the structured data in the MLE by using server-generated values and information extracted from the MR. The MLE can optionally be included in the response body to update client state with server-generated information. Servers may return 201 (Created) or 200 (OK) when the MLE and MR were successfully created and a response body is returned, or 204 (No Content) if creation is successful but no response is returned.

Use of the slug header as defined in AtomPub, section 9.7 is supported and has no further semantics than those defined in that specification.

2.6 Updating Entries

To update the data in an Entry clients execute an HTTP PUT request against the Entry's URI, with a new Entry resource included in the request body.

According to the AtomPub protocol specification, the PUT request replaces the existing Entry, so all property values in the Entry either take the values indicated in the request body, or are reset to their default value if not mentioned in the request. For example, to update a product in the sample OData service:

Request:

PUT /OData/OData.svc/Products(1) HTTP/1.1 Host: services.odata.org DataServiceVersion:
  1.0 MaxDataServiceVersion: 2.0 accept: application/atom+xml 
  content-type: application/atom+xml Content-Length: 1181 
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Entry xml:base="https://services.odata.org/OData/OData.svc/" 
    xmlns:d=" http://schemas.microsoft.com/ado/2007/08/dataservices"
    xmlns:m=" http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
    xmlns="https://www.w3.org/2005/Atom"> 
  <id>https://services.odata.org/OData/OData.svc/Products(1)</id>
  <title type="text"></title> 
  <updated>2010-02-28T10:23:02Z</updated>
  <author> 
    <name /> 
  </author> 
  <Link rel="edit" title="Product" href="Products(1)" /> 
  <category term="DataServiceProviderDemo.Product" 
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
  <content type="application/xml"> 
    <m:properties> 
      <d:ID m:type="Edm.Int32">1</d:ID>
      <d:Name>Milk</d:Name> 
      <d:Description>Low fat milk</d:Description>
      <d:ReleaseDate m:type="Edm.DateTime">1995-10-21T00:00:00</d:ReleaseDate>
      <d:DiscontinuedDate m:type="Edm.DateTime" m:null="true" /> 
      <d:Rating m:type="Edm.Int32">4</d:Rating>
      <d:Price m:type="Edm.Decimal">4.5</d:Price> 
    </m:properties> 
  </content>
</Entry>

Response:

HTTP/1.1 204 No Content Date: Sun, 28 Feb 2010 11:32:26 GMT DataServiceVersion: 1.0;

When processing a PUT request servers return status 204 (No Content) to indicate success, no response body is needed.

In certain cases it is desirable to perform an incremental update without replacing all the contents of an Entry. In order to avoid overloading the meaning of PUT, OData uses the custom HTTP method MERGE for this scenario. A MERGE request updates only the properties indicated in the request body, and leaves untouched anything not mentioned in its current state. For example, to only update the price and rating of a product:

MERGE /OData/OData.svc/Products(1) HTTP/1.1 Host: services.odata.org 
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 
  accept: application/atom+xml content-type: application/atom+xml Content-Length: 1181 
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Entry xml:base="https://services.odata.org/OData/OData.svc/" 
    xmlns:d=" http://schemas.microsoft.com/ado/2007/08/dataservices"
    xmlns:m=" http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
    xmlns="https://www.w3.org/2005/Atom"> 
  <id>https://services.odata.org/OData/OData.svc/Products(1)</id>
  <title type="text"></title> 
  <updated>2010-02-28T10:23:02Z</updated>
  <author> 
    <name /> 
  </author> 
  <Link rel="edit" title="Product" href="Products(1)" /> 
  <category 
      term="DataServiceProviderDemo.Product" 
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
  <content type="application/xml"> 
    <m:properties> 
      <d:Rating m:type="Edm.Int32">4</d:Rating>
      <d:Price m:type="Edm.Decimal">4.5</d:Price> 
    </m:properties> 
  </content>
</Entry>

While there is a distinction between PUT and MERGE for properties, the Links of an Entry are not directly considered part of the structured data portion of an Entry and thus are not reset on PUT. Servers should use MERGE semantics for Links for both PUT and MERGE requests.

NOTE: there is active discussion in the community about the introduction of a PATCH method in HTTP. Once PATCH is an official part of the HTTP specification OData will support PATCH and phase out the custom MERGE method over time.

2.7 Updating individual properties

It is also possible to update individual properties using the same addresses a client can use to retrieve them. Clients may use the PUT method to update the value of a property. Similarly for the retrieve case, clients can choose to use URIs that point to the property in its OData format or in raw form.

For example, to update only the rating of a product:

PUT /OData/OData.svc/Products(1)/Rating HTTP/1.1 Host: services.odata.org DataServiceVersion:
  1.0 MaxDataServiceVersion: 2.0 accept: application/xml 
  content-type: application/xml Content-Length: 275 
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<d:Rating xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    m:type="Edm.Int32">5
</d:Rating>

Alternatively clients can use the address of the raw value of a property and send data in its native form. The example below shows updating the same "Rating" property, although more natural scenarios would include updating an image or an HTML document with a newer version without the need to encode it:

PUT /OData/OData.svc/Products(1)/Rating/$value HTTP/1.1 Host: services.odata.org
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 accept: application/xml 
  content-type: text/plain Content-Length: 1 5

In either case servers should update the property and return 204 (No Content) and no response body or 200 (OK) and an update of the property as appropriate.

Since properties are considered atomic elements (no sub-property operations exist) the MERGE method is not defined for individual properties and servers should fail requests with this method with status code 405 (Method Not Allowed).

2.8 Deleting Entries

Entries are deleted by executing an HTTP DELETE request against a URI that points at the Entry. If the operation executed successfully servers should return 200 (OK) with no response body.

If the Entry has dependent Entries such as Entries Linked to it, it is up to the server whether deletion should be cascaded, the operation should fail because of the presence of dependent Entries, or if Links are left dangling after the Entry is deleted. This largely depends on the server, storage model and the actual application the OData service is a part of.

In the case of Media Link Entries, deleting the Media Link Entry also deletes the Media Resource.

2.9 Manipulating Links

OData provides two ways to manipulate Links: through Link constructs in Entries and by operating on the Link resources directly.

While manipulating Links by updating the Entries at either end can be simpler, this mechanism is less expressive and it is sometimes required to use Link addresses directly. For example, to add or remove a Link between two existing Entries where the Link has a cardinality of "many" on both ends (modeling a many-to-many relationship) requires the use of operations on Links directly.

2.10 Creating Links between Entries

A new Link between two Entries can be established by referencing one Entry during creation or modification of another Entry (as described in Creating new Entries and Updating Entries ) or by explicitly issuing a POST request against the URL of the Link resource. The request must have the new URI in the request body following the appropriate format for stand-alone Links in XML or JSON as described in [OData-Atom] and [OData-JSON].

Servers acknowledge the creation of the Link by returning a status code of 204 (No Content) and no response body. For example, to add a Link to an existing product to the list of products (through the "products" Link) of a given product category:

Request:

POST /OData/OData.svc/Categories(1)/$links/Products HTTP/1.1 Host: services.odata.org
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 Content-Length: 159 
  Content-Type:application/xml 
<uri xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">
  https://services.odata.org/OData/OData.svc/Products(10) 
</uri>

Response:

HTTP/1.1 204 No Content Date: Tue, 02 Mar 2010 08:59:32 GMT DataServiceVersion: 1.0;

If using the OData URI conventions described in [OData-URI], the Link resource address can be derived by using the convention; otherwise it needs to be obtained from the Entry itself.

Adding a Link using POST may result in only the new Link being added or it may have further side-effects. In particular, if the other end of the Link has a cardinality of 1, then the server may remove a previously existing Link (if any) in order to create this one and still satisfy the cardinality constrain.

2.11 Removing Links between Entries

Existing Links may be removed by executing a DELETE request against the Link URI. Servers respond with the success status code of 204 (No Content) and no response body. For example, to delete the Link between a product and it's containing product category:

Request:

DELETE /OData/OData.svc/Categories(1)/$links/Products(10) HTTP/1.1 Host: services.odata.org
  Content-Length: 0

Response:

HTTP/1.1 204 No Content Date: Tue, 02 Mar 2010 09:09:02 GMT DataServiceVersion: 1.0;

Removing Links may cause further side-effects on the server. For example servers may cascade the deletion to the Entry or Entries the Link pointed to.

Besides regular failures due to request correctness or permissions, the server may fail a DELETE request against a Link if deleting the Link would put the service data set in an inconsistent state (i.e. a state that is not allowed by the service schema).

2.12 Replacing Links between Entries

Clients may replace a Link with a new Link by issuing an HTTP PUT request against the Link resource URI, with the new URI in the request body following the appropriate format for stand-alone Links in XML or JSON as described in [OData-Atom] and [OData-JSON]. Servers should update the Link if the service constraints allow it and return 204 (No Content). For example, to move a product from the product category with key "1" to the category with key "2":

Request:

PUT /OData/OData.svc/Products(1)/$links/Category HTTP/1.1 Host: services.odata.org
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 
  accept: application/xml content-type: application/xml Content-Length: 158 
<uri xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">
  https://services.odata.org/OData/OData.svc/Categories(2) 
</uri>

Response:

HTTP/1.1 204 No Content Date: Tue, 02 Mar 2010 19:54:52 GMT DataServiceVersion: 1.0;

Note that when updating the end of a Link that has a cardinality of 1 it is also possible to perform the operation through the Entry itself. For example, to switch back the product of the previous example to its original category:

Request:

MERGE /OData/OData.svc/Products(1) HTTP/1.1 Host: services.odata.org 
    DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 
    content-type: application/atom+xml Content-Length:590 
<entry xml:base="https://services.odata.org/OData/OData.svc/" 
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
    xmlns="https://www.w3.org/2005/Atom">
  <Link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Category"
      type="application/atom+xml;type=Entry" title="Category" href="Categories(1)" />
  <category term="DataServiceProviderDemo.Product" 
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
</entry>

Response:

HTTP/1.1 204 No Content Date: Tue, 02 Mar 2010 20:06:12 GMT DataServiceVersion: 1.0;

Since this is a merge operation and no actual properties are mentioned, the server should only update the Links included in the request body.

2.13 Invoking Service Operations

Service Operations expose custom behaviors that do not map to the uniform interface. Service operations can be defined to take parameters, which are simple scalar values of one of the EDM primitive types as defined in [OData-Core].

Clients may invoke a Service Operation by issuing an HTTP GET or POST request against their URI. If a particular Service Operation takes parameters they should be included as part of the query string in the request URI as described in the Addressing Service Operations section of [OData-URI]. The name of each parameter is used as the name of the query string parameter, and its value should be in OData literal form. No "$" prefix should be used in parameters ("$" is reserved for OData parameters). For example:

Request:

GET /odata/odata.svc/GetProductsByRating?rating=4 HTTP/1.1 Host: services.odata.org
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0

Response:

HTTP/1.1 200 OK Content-Length: 1957 Date: Tue, 02 Mar 2010 20:59:21 GMT 
  Content-Type: application/atom+xml;charset=utf-8 DataServiceVersion: 1.0; 
<?xml version="1.0" encoding="utf-8" standalone="yes"?> 
<feed 
    xml:base="https://services.odata.org/(S(dwaygaylwritgwuiyvfad5ln))/OData/OData.svc/"
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    xmlns="https://www.w3.org/2005/Atom"> 
  <title type="text">GetProductsByRating</title>
  <id>
https://services.odata.org/(S(dwaygaylwritgwuiyvfad5ln))/odata/odata.svc/GetProductsByRating
  </id>
  <updated>2010-03-02T20:59:21Z</updated> 
  <Link rel="self" title="GetProductsByRating" href="GetProductsByRating" /> 
  <Entry> ... </Entry> 
</feed>

Server implementations should only allow invocation of Service Operations through GET when the operations will not cause side-effects in the system.

Service authors can choose to enable query composition in Service Operations if the operation returns a Collection of Entries. When that is the case, clients may use the URI conventions defined in [OData-URI] treating the URI to the Service Operation as the URI to the initial collection, and then applying the convention from there.

3. Additional Interaction Model Considerations

3.1 Concurrency control and ETags

OData uses HTTP ETags for optimistic concurrency control. A few special considerations apply for ETags:

OData servers will use weak ETags often as a way of indicating that two resources may be semantically equivalent but a particular request may see a different representation of it. Clients should be prepared to handle weak and strong ETags.

3.2 Method Tunneling through POST

In many scenarios clients are limited to the HTTP GET and POST methods only. In order to help work-around this limitation, OData servers can support method tunneling through POST. The methods that can be executed through tunneling are MERGE, PUT and DELETE.

To issue a request with method tunneling a client sets up a request with body and headers as needed, but uses POST as the HTTP method instead of the actual required one. It then adds one more header, "X-HTTP-Method", and gives it the value MERGE, PUT or DELETE.

Servers must check if POST requests have the X-HTTP-Method header set to one of the valid values and if so execute the rest of the request as if the header value was the actual HTTP method for it.

3.3 Processing entries of open types

As discussed in [OData-Core] the OData data model supports open types for Entries. An entry of an open type may have extra properties (dynamic properties) in addition to those statically declared in metadata.

In general servers should treat dynamic properties and static properties as uniformly as possible.

For data retrieval servers should include dynamic and static properties in entries and should use the same format for both, as discussed in [OData-Atom] and [OData-JSON].

From the query semantics perspective dynamic and static properties apply equally in all contexts (projection, filter, sorting, etc.). Similarly in the addressing scheme dynamic and static properties should be handled in the same way (e.g. it is legal to address a dynamic property within an entry in servers that support the URI convention discussed in [OData-URI]). Dynamic properties may not be present in all entries within a collection; query processors should treat missing properties as if they had a null value.

During update processing, dynamic properties should be appended to entries when they appear on a POST, PUT or MERGE request. They can also be incrementally added to existing entries using a MERGE operation with the dynamic properties to be added. A PUT request resets all the properties not mentioned in the request to their default values, and removes all the dynamic properties that may have been previously added to this entry but were not mentioned in this request. When a dynamic property is explicitly mentioned in a POST/PUT/MERGE request and has a null value, the server may choose to preserve its existence as a null dynamic property or remove it from the entry, as the rest of the system should behave as if it was there but had a null value already.