skip to content

Metadata Document

The service document lists entity sets and singletons, and $metadata serves the whole model as CSDL with vocabulary annotations. Interviewers ask because runtime discovery is OData's main pitch.

part ofAPI stylesoverview, primer and where to startread it →
on this pageshow

questions

5

In OData, how does the service document at the service root differ from the $metadata document, and what does a client use each one for?

level: juniorimportance: must knowfreq 30%

answer

  1. two fixed resources, two jobs
  2. a short list of entry points
  3. the whole model as CSDL
  4. XML unless the client asks otherwise

basics

~20 s

The OData service document at the service root lists entry points: entity sets, singletons and opted-in function imports, each with a name and URL. The $metadata document describes the whole model in CSDL: types, keys, relationships, operations and annotations.

solid answer

~40 s

An OData service exposes two fixed resources that describe it. The **service document** is what `GET` on the service root returns: in JSON, an object whose `value` array has one entry per entity set, singleton and opted-in function import, each with a `name`, a `url` and usually a `kind`; its context URL is the `$metadata` URL. The **metadata document**, at the service root plus `$metadata`, is the full data model in CSDL: entity and complex types, keys, navigation properties, actions, functions, the entity container and vocabulary annotations. With no format preference it MUST come back as CSDL XML; OData 4.01 adds a CSDL JSON form requested as `application/json`. A hypermedia client browses from the service document; a code generator or a generic UI needs `$metadata`.

code

json · 9 lines
json
{
  "@context": "https://api.example.com/sales/$metadata",
  "value": [
    { "name": "Orders", "kind": "EntitySet", "url": "Orders" },
    { "name": "Customers", "url": "Customers" },
    { "name": "Company", "kind": "Singleton", "url": "Company" },
    { "name": "TopProducts", "title": "Best sellers", "kind": "FunctionImport", "url": "TopProducts" }
  ]
}

go deeper

for a junior

Recall the two URLs, the service root and $metadata, and say in one line what each returns: a list of entry points versus the full CSDL model.

for a middle

Explain what the service document lists and leaves out (action imports never, function imports only if parameterless and opted in) and that $metadata defaults to CSDL XML.

for a senior

Show how a generic client uses both documents, the service document for navigation and $metadata for types, keys and annotations, and why a service without $metadata cripples tooling.

for a principal

Frame runtime discovery as OData's main promise and weigh what a service owner commits to by publishing a complete, stable $metadata document to every consumer.

## Two fixed resources describe every OData service The OData protocol says a service exposes two well-defined resources that describe its data model: a **service document** and a **metadata document**. Everything else (entity collections, single entities, property values, operation results) is a dynamic resource whose URL a client either receives in a payload or computes from the model. The two fixed documents answer different questions: *where can I start?* and *what does everything look like?* ## The service document: a list of entry points The service document is what a client receives from `GET` on the **service root**, the base URL of the service. Every OData service MUST return one there; it is the first item of the minimal conformance level. In the JSON format it is a single object with: - a **context** control information whose value MUST be the metadata document URL without a fragment, the link from the short list to the full model; - a `value` array with one object per entry point, each carrying `name` and `url` (absolute or relative), optionally a human-readable `title`, and a `kind` of `EntitySet`, `Singleton`, `FunctionImport` or `ServiceDocument` (an object without `kind` is an entity set). What appears is governed by the model: | Entity container child | Listed in the service document? | |---|---| | Entity set | Yes, unless `IncludeInServiceDocument="false"`; sets that cannot be queried without extra query options SHOULD NOT be listed | | Singleton | Yes, with `kind` `Singleton` | | Function import | Only for a parameterless function, and only when `IncludeInServiceDocument="true"` (absence means false) | | Action import | Never | The JSON shape is deliberately closed: services MUST NOT add other name/value pairs, clients MUST ignore unknown ones, and a client that meets an unknown `kind` MUST NOT stop processing or signal an error. Annotations MAY appear in any of its objects. ## The metadata document: the whole model The metadata document lives at the service root with `$metadata` appended and is fetched with a plain `GET`. It is the model written in the **Common Schema Definition Language (CSDL)**: entity types with their keys, complex and enumeration types, navigation properties, actions and functions, the entity container with its entity sets, singletons and imports, and the **vocabulary annotations** that add meaning such as descriptions, computed properties or capability restrictions. Two representations exist: 1. **CSDL XML**, rooted at `edmx:Edmx`, media type `application/xml`, the only form OData 4.0 defined. 2. **CSDL JSON**, a single JSON object, media type `application/json`, added by OData 4.01. If the request states no format preference (no `Accept` header, no `$format`), the service MUST return the XML representation. The 4.01 conformance rules make publishing `$metadata` a SHOULD at the minimal level (in both representations for a 4.01 service) and a MUST at the 4.0 advanced level. ## Side by side | | Service document | Metadata document | |---|---|---| | URL | service root | service root + `$metadata` | | Content | names and URLs of entry points | full CSDL model plus annotations | | Format | follows the format selected for the request | CSDL XML by default; CSDL JSON on request in 4.01 | | Obligation | MUST | SHOULD at minimal, MUST at advanced | | Typical reader | a hypermedia-driven browser of the service | a code generator, a generic UI, a validator | ## What a client does with each 1. A **hypermedia client** reads the service document, lets a user pick `Orders`, follows its `url`, and from then on follows links in responses. 2. A **code generator** fetches `$metadata` and turns types, sets and operations into typed client code. 3. A **generic runtime client** fetches `$metadata` at start-up to learn property names and types, to build `$filter` and `$select` expressions, and to read annotations telling it what the service permits. The service document alone cannot tell a client which properties an order has, what its key is, or which operations exist: it names the doors, not the rooms behind them. ## Common confusions - `$metadata` is not the `odata.metadata` format parameter, which controls how much control information a *data* response carries. - The service document is not a reduced CSDL file; it holds no types at all. - An entity set missing from the service document can still be declared in `$metadata` and addressed by URL.

  • Why might an OData entity set be missing from the service document although $metadata declares it?
    The entity set can carry `IncludeInServiceDocument="false"`, and sets that cannot be queried without extra query options SHOULD NOT be listed at all. Leaving a set out of the service document does not hide it: it is still declared in `$metadata` and can be addressed by its URL.
  • What must an OData client do when a JSON service document contains a kind value it does not recognise?
    It MUST NOT stop processing and MUST NOT signal an error; it skips or tolerates the entry. The same tolerance applies to unknown name/value pairs, which clients MUST ignore, while services MUST NOT emit pairs beyond those the JSON format defines.

The service document is a building's lobby directory: it lists the offices you can walk to and where they are. The $metadata document is the architect's full set of plans, showing every room, wall and connection, which you need before you can work inside the building.

saying these in an interview costs you the question

  • The service document and $metadata are the same model in two formats.
  • The service document lists every entity type with its properties.
  • In OData 4.01, $metadata returns JSON when no format is requested.
  • Action imports are listed in the service document beside function imports.
  • Leaving an entity set out of the service document makes it unreachable.
open as a page

In an OData metadata document, how does a vocabulary annotation apply a term to a model element, and what does Core.Computed tell a client?

level: middleimportance: should knowfreq 12%

basics

~20 s

An OData annotation applies a vocabulary term to a model element, nested inside it or targeted from an Annotations block, with an optional qualifier. Core.Computed marks a property the service generates on insert and update; a value the client sends is ignored.

open as a page

A generic OData client is building a grid for an unfamiliar entity set; how does it learn from $metadata which filtering, sorting, paging and inserts the service allows?

level: seniorimportance: should knowfreq 9%

basics

~20 s

An OData client reads Capabilities vocabulary annotations on the entity set in $metadata: FilterRestrictions, SortRestrictions, TopSupported, InsertRestrictions and others. Absence means paging, counting and expand are assumed, inserts are not, and the service may still refuse a request.

open as a page

Should an OData client generate typed proxies from $metadata at build time or discover the model at runtime, and how does each cope with model changes?

level: seniorimportance: should knowfreq 11%

basics

~20 s

Typed OData proxies generated from $metadata give compile-time checks but freeze the model; runtime discovery adapts but gives up types. Either way, clients must tolerate OData's safe additive changes and can detect drift through the metadata ETag and, in 4.01, $schemaversion.

open as a page

In OData 4.01, how does a CSDL JSON metadata document differ from CSDL XML for the same model, and how does a client request each?

level: middleimportance: nice to knowfreq 7%

basics

~20 s

In OData 4.01, CSDL XML (root edmx:Edmx) and CSDL JSON (one object with $Version and $EntityContainer) describe the same model; JSON omits defaults, and some defaults differ, such as nullability. A plain GET $metadata returns XML; application/json asks for JSON.

open as a page