The Open Data Protocol (OData) is a data access protocol built on core protocols like HTTP and commonly accepted methodologies like REST for the web. There are various kinds of libraries and tools can be used to consume OData services. But for beginners and those who want to write their own libraries, the pure HTTP requests and responses are also very important. This documentation will not cover every feature details for OData V4 services but will try to cover various typical scenarios. If you want to have a more detailed understanding, please refer to OData Documentation.

Pleae be noted

  • This is the advanced section. For topics like requesting data, query options, basic data modification, operations and etc, please refer to Basic Section.
  • All these are based on OData V4 sample service TripPin, please just replace the serviceRoot below with the URL http://services.odata.org/V4/TripPinServiceRW. TripPin now supports ETag, so for data modification topics, you should first using GET on TripPin (eg. GET serviceRoot/People) to get the section information in the payload then use the URL with section for data modification examples. (something looks like http://services.odata.org/V4/(S(flat4rgegiueineatspfdku1))/TripPinServiceRW)
  • You may use Fiddler to run the request (especially the complex ones of data modification) and get the JSON response.
  • In TripPin service, ETag is currently enabled on entity Person. We omit the ETag related headers in request headers for short, please go to the ETag Section for detailed information.
  • We will keep improving this by adding contents and fixing bugs. You can provide your feedbacks and ask questions using OData Mailling List.

Singletons are single entities which are accessed as children of the entity container.

Requesting singleton

The request below returns the singleton Me
GET serviceRoot/Me

Response Payload

{
    "@odata.context": "serviceRoot/$metadata#Me",
    "@odata.id": "serviceRoot/Me",
  "@odata.etag": "W/"08D1694EFF498B20"",
    "@odata.editLink": "serviceRoot/Me",
    "UserName": "aprilcline",
    "FirstName": "April",
    "LastName": "Cline",
    "EmailAddress": [
        "April@example.com",
        "April@contoso.com"
    ],
    "AddressInfo": [
        {
            "Address": "P.O. Box 555",
            "City": {
                "CountryRegion": "United States",
                "Name": "Lander",
                "Region": "WY"
            }
        }
    ],
    "Gender": "Female",
  "Concurrency": 635404810447326000
}

Requesting property of Singleton

The request below returns the property AddressInfo of singleton Me.
GET serviceRoot/Me/AddressInfo

Response Payload

{
    "@odata.context": "serviceRoot/$metadata#Me/AddressInfo",
    "value": [
        {
            "Address": "P.O. Box 555",
            "City": {
                "CountryRegion": "United States",
                "Name": "Lander",
                "Region": "WY"
            }
        }
    ]
}

}

Update Singleton

The request below updates the UserName of Single Me.

PATCH serviceRoot/Me
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json
{
"@odata.type" : "Microsoft.OData.SampleService.Models.TripPin.Person",
"UserName": "AprilTripPin"
}


Response Payload

HTTP/1.1 204 No Content
OData-Version: 4.0

OData now supports derived entity type. Entity types may derived by single inheritance from other entity types. In the sample TripPin service, the entity type Event and Flight both derive from entity type PlanItem.

Requesting a Derived Entity

The request below returns the flight of with PlanItemId 21.

GET serviceRoot/People('russellwhyte')/Trips(1003)/PlanItems(21)/Microsoft.OData.SampleService.Models.TripPin.Flight


Response Payload

{
    "@odata.context": "serviceRoot/$metadata#People('russellwhyte')/Trips(1003)/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight/$entity",
    "PlanItemId": 21,
    "ConfirmationCode": "JH58494",
    "StartsAt": "2014-02-01T08:00:00+08:00",
    "EndsAt": "2014-02-01T09:20:00+08:00",
    "Duration": "PT0S",
    "SeatNumber": "B11",
    "FlightNumber": "FM1930"
}

Requesting a Derived Entity Collection

The request below shows how to get the derived enity set Flights.
GET serviceRoot/People('russellwhyte')/Trips(1001)/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight

Response Payload

{
    "@odata.context": "serviceRoot/$metadata#People('russellwhyte')/Trips(1001)/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight",
    "value": [
        {
            "PlanItemId": 11,
            "ConfirmationCode": "JH58493",
            "StartsAt": "2014-01-01T08:00:00+08:00",
            "EndsAt": "2014-01-01T09:20:00+08:00",
            "Duration": "PT0S",
            "SeatNumber": null,
            "FlightNumber": "VA1930"
        },
        {
            "PlanItemId": 13,
            "ConfirmationCode": "JH58493",
            "StartsAt": "2014-01-04T13:00:00+08:00",
            "EndsAt": "2014-01-04T14:20:00+08:00",
            "Duration": "PT0S",
            "SeatNumber": null,
            "FlightNumber": "VA1930"
        }
    ]
}

Filter on Derived Type

The two request below shows how to filter on derived entities. These requests return all Flight deriving from PlanItem which has FlightNumber as 'VA1930'.

serviceRoot/People('russellwhyte')/Trips(1001)/PlanItems?$filter=Microsoft.OData.SampleService.Models.TripPin.Flight/FlightNumber eq 'VA1930'
serviceRoot/People('russellwhyte')/Trips(1001)/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight?$filter=FlightNumber eq 'VA1930'

Response Payload

{
    "@odata.context": "serviceRoot/$metadata#People('russellwhyte')/Trips(1001)/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight",
    "value": [
        {
            "PlanItemId": 11,
            "ConfirmationCode": "JH58493",
            "StartsAt": "2014-01-01T08:00:00+08:00",
            "EndsAt": "2014-01-01T09:20:00+08:00",
            "Duration": "PT0S",
            "SeatNumber": null,
            "FlightNumber": "VA1930"
        },
        {
            "PlanItemId": 13,
            "ConfirmationCode": "JH58493",
            "StartsAt": "2014-01-04T13:00:00+08:00",
            "EndsAt": "2014-01-04T14:20:00+08:00",
            "Duration": "PT0S",
            "SeatNumber": null,
            "FlightNumber": "VA1930"
        }
    ]
}

Create a Derived Entity

The request below creates an event entity in trips. Event derives from PlanItem.

POST serviceRoot/People("russellwhyte")/Trips(1003)/PlanItems
OData-Version: 4.0
Content-Type: application/json ; odata.metadata=minimal
Accept: application/json

{
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Event",
"ConfirmationCode": "4372899DD",
"Description": "Client Meeting",
"Duration": "PT3H",
"EndsAt": "2014-06-01T23:11:17.5479185-07:00",
"OccursAt": {
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.EventLocation",
"Address": "100 Church Street, 8th Floor, Manhattan, 10007",
"BuildingInfo": "Regus Business Center",
"City": {
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.City",
"CountryRegion": "United States",
"Name": "New York City",
"Region": "New York"
}
},
"PlanItemId": 33,
"StartsAt": "2014-05-25T23:11:17.5459178-07:00"
}


Response Payload

 Response HTTP/1.1 201 Created
{
"@odata.context": "serviceRoot/$metadata#People('russellwhyte')/Trips(1003)/PlanItems/$entity",
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Event",
"PlanItemId": 33,
"ConfirmationCode": "4372899DD",
"StartsAt": "2014-05-25T23:11:17.5459178-07:00",
"EndsAt": "2014-06-01T23:11:17.5479185-07:00",
"Duration": "PT3H",
"Description": "Client Meeting",
"OccursAt": {
  "Address": "100 Church Street, 8th Floor, Manhattan, 10007",
  "City": {
    "CountryRegion": "United States",
    "Name": "New York City",
    "Region": "New York"
    },
"BuildingInfo": "Regus Business Center"
  }
}

Update a Derived Entity

The request below updates an event. Event derives from PlanItem.

PATCH serviceRoot/People('russellwhyte')/Trips(1003)/PlanItems(5)/Microsoft.OData.SampleService.Models.TripPin.Event
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json

{
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Event",
"Description": "This is a new description"
}


Response Payload

HTTP/1.1 204 No Content

Delete a Derived Entity

The request below deletes the flight plan item with Id '21' from a trip of person. Flight derives from PlanItem.

DELETE serviceRoot/People('russellwhyte')/Trips(1003)/PlanItems(21)/Microsoft.OData.SampleService.Models.TripPin.Flight

Response Payload

HTTP/1.1 204 No Content

Containment navigation properties define an implicit entity set for each instance of its declaring entity type. This implicit entity set if identified by the read URL of the navigation property for that entity. The request below returns the contained navigation property Trips of entity set People.

Requesting a Contained Entity Set

The request below returns Trips for a person where Trips is a containment navigation property for Person.
GET serviceRoot/People('russellwhyte')/Trips

Response Payload

{
    "@odata.context": "http://services.odata.org/V4/(S(mmobft3g4aut3krzqrxxip4w))/TripPinServiceRW/$metadata#People('russellwhyte')/Trips",
    "value": [
        {
            "TripId": 1001,
            "ShareId": "9d9b2fa0-efbf-490e-a5e3-bac8f7d47354",
            "Description": "Trip from San Francisco to New York City",
            "Name": "Trip in US",
            "Budget": 3000,
            "StartsAt": "2014-01-01T00:00:00Z",
            "EndsAt": "2014-01-04T00:00:00Z",
            "Tags": [
                "business",
                "New York meeting"
            ]
        },
        ......
        ,
        {
            "TripId": 1007,
            "ShareId": "9ce142c3-5fd6-4a71-848e-5220ebf1e9f3",
            "Description": "Happy honeymoon trip",
            "Name": "Honeymoon",
            "Budget": 2650,
            "StartsAt": "2014-02-01T00:00:00Z",
            "EndsAt": "2014-02-04T00:00:00Z",
            "Tags": [
                "Travel",
                "honeymoon"
            ]
        }
    ]
}

Create a Contained Entity

The request below creates a Trip for Person with UserName 'russellwhyte'. Trips is a contained navigation property for Person.

POST serviceRoot/People('russellwhyte')/Trips
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json
{
"@odata.type" : "Microsoft.OData.SampleService.Models.TripPin.Trip",
"TripId" : 3,
"ShareId" : null,
"Description" : "Create Containment",
"Name" : "Test Trip",
"StartsAt" : "2014-01-01T00:00:00+08:00",
"EndsAt" : "2014-02-01T00:00:00+08:00",
"Budget" : 1000,
"Tags" : [
"Test Tag 1",
"Test Tag 2"
]
}


Response Payload

HTTP/1.1 201 Created
Content-Length: 344
Content-Type: application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8
Location: serviceRoot/People('russellwhyte')/Trips(3)
OData-Version: 4.0
{
    "@odata.context":"serviceRoot/$metadata#People('russellwhyte')/Trips/$entity",
    "TripId":3,
    "ShareId":"00000000-0000-0000-0000-000000000000",
    "Description":"Create Containment",
    "Name":"Test Trip",
    "Budget":1000,
    "StartsAt":"2014-01-01T00:00:00+08:00",
    "EndsAt":"2014-02-01T00:00:00+08:00",
    "Tags":["Test Tag 1","Test Tag 2"]
}

Filter on a Contained Entity Set

The request below returns Trips that contains 'New York' in its description of Person with UserName 'russellwhyte'.
GET serviceRoot/People('russellwhyte')/Trips?$filter=contains(Description, 'New York')

Response Payload

{
    "@odata.context": "serviceRoot/$metadata#People('russellwhyte')/Trips",
    "value": [
        {
            "TripId": 1001,
            "ShareId": "9d9b2fa0-efbf-490e-a5e3-bac8f7d47354",
            "Description": "Trip from San Francisco to New York City",
            "Name": "Trip in US",
            "Budget": 3000,
            "StartsAt": "2014-01-01T00:00:00+08:00",
            "EndsAt": "2014-01-04T00:00:00+08:00",
            "Tags": [
                "business",
                "New York meeting"
            ]
        }
    ]
}

Update Contained Entity

The request below updates the contained Entity Trip.

PATCH serviceRoot/People('russellwhyte')/Trips(1001)
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json

{
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Trip",
"Description": "This is a new description"
}

Response Payload

HTTP/1.1 204 No Content

Delete Contained Entity

The request below deletes a contained Entity Trip.

DELETE serviceRoot/People('russellwhyte')/Trips(1001)

Response Payload

HTTP/1.1 204 No Content

OData V4 supports entity or complex types which allow clients to persist additional undeclared properties. Such entities and complex types are called open types.

Open Entity Type

When create or update an open entity, undeclared properties can be added.
The request below shows how to add an undeclared property Description when create the open entity Person.

POST serviceRoot/People
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json
ETag: W/"08D15F3DD9126D84"

{
"@odata.type" : "Microsoft.OData.SampleService.Models.TripPin.Person",
"UserName": "teresa",
"FirstName" : "Teresa",
"LastName" : "Gilbert",
"Gender" : "Female",
"Description": "Big fan for travelling",
"Emails" : ["teresa@example.com", "teresa@contoso.com"],
"AddressInfo" : [
{
"Address" : "1 Suffolk Ln.",
"City" :
{
"CountryRegion" : "United States",
"Name" : "Boise",
"Region" : "ID"
}
}]
}


Response Payload

HTTP/1.1 201 Created
{
   "@odata.context":"serviceRoot/$metadata#People/$entity",
   "@odata.id":"serviceRoot/People('teresa')",
   "@odata.editLink":"serviceRoot/People('teresa')",
   "UserName":"teresa",
   "FirstName":"Teresa",
   "LastName":"Gilbert",
   "Description": "Big fan for travelling",
   "Emails":["teresa@example.com","teresa@contoso.com"],
   "AddressInfo":[{"Address":"1 Suffolk Ln.","City":{"CountryRegion":"United States","Name":"Boise","Region":"ID"}}],
   "Gender":"Female"
}

The request below shows how to add an undeclared property Description when update the open entity Person.

PATCH serviceRoot/People('keithpinckney')
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json

{
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Person",
"Description": "Big fan for travelling"
}

Response Payload

HTTP/1.1 204 No Content

Open Complex Type

OData V4 also supports open type for complex types.
The request below show how to add undeclared property Description when create new instance with AddressInfo of open complex type Location.


PATCH serviceRoot/People('russellwhyte')
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json

{
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Person",
"AddressInfo@odata.type": "#Collection(Microsoft.OData.SampleService.Models.TripPin.Location)",
"AddressInfo": [
{
"Address": "187 Suffolk Ln.",
"City": {
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.City",
"CountryRegion": "United States",
"Name": "Boise",
"Region": "ID"
},
"Description": null
},
{
"Address": "XuanWu Load 555",
"City": {
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.City",
"CountryRegion": "China",
"Name": "NanJing",
"Region": "JiangSu"
},
"Description": "Nice Location"
}
],
"Concurrency": 635393824693486800,
"Description": null,
"Emails@odata.type": "#Collection(String)",
"Emails": [
"Russell@example.com",
"Russell@contoso.com"
],
"FirstName": "Russell",
"Gender@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.PersonGender",
"Gender": "Male",
"LastName": "Whyte",
"UserName": "russellwhyte"
}


Response Payload

HTTP/1.1 204 No Content

The request below show how to add undeclared property Description when update an instance with OccursAt of open complex type EventLocation.

PATCH serviceRoot/People('russellwhyte')/Trips(1003)/PlanItems(5)/Microsoft.OData.SampleService.Models.TripPin.Event

OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json

{
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Event",
"OccursAt": {
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.EventLocation",
"Address": "10 Beijing Street, 100000",
"BuildingInfo": "Beijing Restaurant",
"City": {
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.City",
"CountryRegion": "China",
"Name": "Beijing",
"Region": "Beijing"
},
"Description": "Beautiful City."
}
}


Response Payload

HTTP/1.1 204 No Content

Batch requests allow grouping multiple operations into a single HTTP request payload. The Batch request below contains the following operations in order listed:
    1. A query request, returns all Airlines.
    2. Create an entity, a new Airline.
    3. A second query request Airlines.


POST serviceRoot/$batch
OData-Version: 4.0
Content-Type: multipart/mixed;boundary=batch_36522ad7-fc75-4b56-8c71-56071383e77b


--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-Transfer-Encoding:binary

GET serviceRoot/Airlines HTTP/1.1
Accept: application/json;odata.metadata=minimal

--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-Transfer-Encoding:binary
Content-ID: 1

POST serviceRoot/Airlines HTTP/1.1
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json;odata.metadata=minimal

{
"@odata.type" : "Microsoft.OData.SampleService.Models.TripPin.Airline",
"AirlineCode" : "EK",
"Name" : "Emirates Airline"
}

--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-Transfer-Encoding:binary

GET serviceRoot/Airlines HTTP/1.1
Accept: application/json;odata.metadata=minimal

--batch_36522ad7-fc75-4b56-8c71-56071383e77b--



Response Payload

HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Length: 3100
Content-Type: multipart/mixed; boundary=batchresponse_3e4cf86f-ab02-46e1-9631-b08a787abc35
OData-Version: 4.0
--batchresponse_3e4cf86f-ab02-46e1-9631-b08a787abc35
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8
{
"@odata.context":"serviceRoot/$metadata#Airlines",
"value":
[{
"AirlineCode":"AA",
"Name":"American Airlines"
},
{
"AirlineCode":"FM",
"Name":"Shanghai Airline"
},
{
"AirlineCode":"MU",
"Name":"China Eastern Airlines"
}
]}
--batchresponse_3e4cf86f-ab02-46e1-9631-b08a787abc35
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 201 Created
Location: serviceRoot/Airlines('EK')
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8
{
"@odata.context":"serviceRoot/$metadata#Airlines/$entity",
"@odata.id":"serviceRoot/Airlines('EK')",
"@odata.editLink":"serviceRoot/Airlines('EK')",
"AirlineCode":"EK","Name":"Emirates Airline"
}
--batchresponse_3e4cf86f-ab02-46e1-9631-b08a787abc35
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8
{
"@odata.context":"serviceRoot/$metadata#Airlines",
"value":
[{
"AirlineCode":"AA",
"Name":"American Airlines"},
{
"AirlineCode":"FM",
"Name":"Shanghai Airline"
},
{
"AirlineCode":"MU",
"Name":"China Eastern Airlines"
},
{
"AirlineCode":"EK",
"Name":"Emirates Airline"
}]
}
--batchresponse_3e4cf86f-ab02-46e1-9631-b08a787abc35--