Show TOC

OData V4 Metadata JSON FormatLocate this document in the navigation structure

The OData V4 model provides access to metadata in a streamlined JSON format which is described in the section below.

It is different to the $metadata service's JSON format (see OData JSON Format Version 4.0Information published on non-SAP site) and the OData JSON Format for Common Schema Definition Language (CSDL) Version 4.0 (see corresponding specificationInformation published on non-SAP site), intended to simplify client-side processing.

In the sections below, angled brackets indicate variable parts. The numbers next to each expression correspond to the numbered sections in the official specification, see OData Version 4.0 Part 3: Common Schema Definition Language (CSDL) Plus Errata 02Information published on non-SAP site. Comments highlight optional properties, especially those that have certain default values.

Design Rationale

We have prefixed constant property names with "$" as this is a legal first character for JavaScript identifiers, but not for OData simple identifiers. This way, inline annotations can be added via "@<14.3.1 Annotation Term>#<14.3.2 Annotation Qualifier>" : <value> everywhere without resulting in any naming conflicts. This is shown as "@..." : <value> below.

We assume that schema aliases have been resolved. We add a trailing dot after a schema's namespace, meaning qualified name "A.B" cannot clash with schema namespace "A.B.", for example. This trailing dot is also present for "$Include", "$TermNamespace" and "$TargetNamespace" values.

$kind has been added to each object with a (qualified) OData name and to almost each object which can be annotated via external targeting, but not to enum members. Actions and functions are arrays of overloads and $kind has been added to each overload.

We assume each enum member has a value via the fallback rule "If no values are specified, the members are assigned consecutive integer values in the order of their appearance, starting with zero for the first member."

Facets like MaxLength, Precision and Scale are represented as numbers if possible ("$Scale" : "variable" is the only exception). DefaultValue is represented as a string for lack of type information in the general case. "$MaxLength" : "max" is omitted and will be treated the same as an unspecified length on the client-side.

A "17.5 TargetPath" used as "13.4.1 Attribute Path" or "13.5.3/13.6.3 Attribute EntitySet" is normalized in the following sense: a simple identifier is used instead of a target path for entity sets (or singletons) within the same container.

Each annotation specifies a value. Accordingly, $DefaultValue has been omitted for the time being.

Normalization: For all EDM elements which allow both inline annotations and external targeting, only external targeting is used. This affects edm:ActionImport, edm:ComplexType, edm:EntityContainer, edm:EntitySet, edm:EntityType, edm:EnumType, edm:FunctionImport, edm:Member, edm:Singleton, edm:Term, edm:TypeDefinition, edm:NavigationProperty, edm:Property. This cannot be done for edm:Action, edm:Function, edm:Parameter because external targeting applies to all overloads while inline annotations apply to individual overloads. The goal is to reduce cases that contain a mixture of inline annotations and external targeting to the bare minimum.

We use the "<key>@<14.3.1 Annotation Term>#<14.3.2 Annotation Qualifier>" : <value> syntax for inline annotations in the following cases to avoid explicit object representations:
  • "7.2 Element ReferentialConstraint" with key "<7.2.1 ReferentialConstraint Property>"

  • "7.3 Element OnDelete" with key "$OnDelete"

  • "14.3 Annotation" with key "@<14.3.1 Annotation Term>#<14.3.2 Annotation Qualifier>" (yes, this does lead to a double at-sign "@...#...@...#...")

  • "14.5.14.2 Element PropertyValue" with key "<14.5.14.2.1 PropertyValue Property>"

Metadata JSON Structure

The following JSON file represents the metadata document which corresponds to GET <serviceRoot>/$metadata:

{
  "$Version" : "<3.1.1 Edmx Version>",
  "$EntityContainer" : "<5.1.1 Schema Namespace>.<13.1.1 EntityContainer Name>", // root entity container for this $metadata document
  "$Reference" : {
    // server-relative, dereferencable URLs (to $metadata) only!
    "<3.3.1 Reference Uri>" : { "@..." : <value>,
      "$Include" : ["<3.4.1 Include Namespace>.", ...], // optional
      "$IncludeAnnotations" : [{
        "$TermNamespace" : "<3.5.1 IncludeAnnotations TermNamespace>.",
        "$Qualifier" : "<3.5.2 IncludeAnnotations Qualifier>", // optional
        "$TargetNamespace" : "<3.5.3 IncludeAnnotations TargetNamespace>." // optional
      }, ...] // optional
    }
  }, // optional
  "<5.1.1 Schema Namespace>" : {
    "$kind" : "Schema",
    "$Annotations" : {
      "<14.2.1 Annotations Target>" : {
        // Note: "<14.3.2 Annotation Qualifier>" defaults to "<14.2.2 Annotations Qualifier>",
        // qualifiers are optional, "#" is omitted then
        "@<14.3.1 Annotation Term>#<14.3.2 Annotation Qualifier>" : <value> // constant or dynamic expression
        "@<14.3.1 Annotation Term>#<14.3.2 Annotation Qualifier>@..." : <value> // annotation of an annotation
      }
    }, // optional
    "@..." : <value> // place inline annotations for schema itself here!
  },
  "<5.1.1 Schema Namespace>.<8.1.1 EntityType Name>" : {
    "$kind" : "EntityType",
    "$BaseType" : "<8.1.2 EntityType BaseType>", // optional
    "$Abstract" : true, // omit in case of default value: false
    "$OpenType" : true, // omit in case of default value: false
    "$HasStream" : true, // omit in case of default value: false
    "$Key" : [
      "<8.3.1 PropertyRef Name>", // in case no Alias is given
      {"<8.3.1 PropertyRef Alias>" : "<8.3.1 PropertyRef Name>"},
      ...
    ], // optional
    "<6.1.1 Property Name>" : {
      "$kind" : "Property",
      "$Type" : "<6.1.2 Property Type>",
      "$isCollection" : true, // omit in case of default value: false
      "$Nullable" : false, // omit in case of default value: true
      "$MaxLength" : <6.2.2 MaxLength>, // optional, number
      "$Precision" : <6.2.3 Precision>, // optional, number
      "$Scale" : <6.2.4 Scale> | "variable", // optional, number or fixed string
      "$Unicode" : false, // omit in case of default value: true
      "$SRID" : "<6.2.6 SRID>", // optional
      "$DefaultValue" : "<6.2.7 DefaultValue>" // optional
    },
    "<7.1.1 NavigationProperty Name>" : {
      "$kind" : "NavigationProperty",
      "$isCollection" : true, // omit in case of default value: false
      "$Type" : "<7.1.2 NavigationProperty Type>",
      "$Nullable" : false, // omit in case of default value: true
      "$Partner" : "<7.1.4 NavigationProperty Partner>", // optional
      "$ContainsTarget" : true, // omit in case of default value: false
      "$ReferentialConstraint" : {
        "<7.2.1 ReferentialConstraint Property>" : "<7.2.2 ReferentialConstraint ReferencedProperty>"
      }, // optional
      "$OnDelete" : "<7.3.1. OnDelete Action>" // optional
    },
  },
  "<5.1.1 Schema Namespace>.<9.1.1 ComplexType Name>" : {
    "$kind" : "ComplexType",
    "$BaseType" : "<9.1.2 ComplexType BaseType>", // optional
    "$Abstract" : true, // omit in case of default value: false
    "$OpenType" : true, // omit in case of default value: false
    "<6.1.1 Property Name>" : {
      // see above
    },
    "<7.1.1 NavigationProperty Name>" : {
      // see above
    }
  },
  "<5.1.1 Schema Namespace>.<10.1.1 EnumType Name>" : {
    "$kind" : "EnumType",
    "$UnderlyingType" : "<10.1.2 EnumType UnderlyingType>", // omit in case of default value: Edm.Int32
    "$IsFlags" : true, // omit in case of default value: false
    "<10.2.1 Member Name>" : "<10.2.2 Member Value>" // use string value in case of base type Edm.Int64, else number
  },
  "<5.1.1 Schema Namespace>.<11.1.1 TypeDefinition Name>" : {
    "$kind" : "TypeDefinition",
    "$UnderlyingType" : "<11.1.2 TypeDefinition UnderlyingType>",
    "$MaxLength" : <11.1.3 MaxLength>, // optional, number
    "$Precision" : <11.1.3 Precision>, // optional, number
    "$Scale" : <11.1.3 Scale> | "variable", // optional, number or fixed string
    "$Unicode" : false, // omit in case of default value: true
    "$SRID" : "<11.1.3 SRID>" // optional
  },
  "<5.1.1 Schema Namespace>.<12.1.1 Action Name>" : [{ "@..." : <value>,
    "$kind" : "Action",
    "$IsBound" : true, // omit in case of default value: false
    "$EntitySetPath" : "<12.1.3 Action EntitySetPath>", // optional
    "$Parameter" : [{ "@..." : <value>
      "$Name" : "<12.4.1 Parameter Name>",
      "$isCollection" : true, // omit in case of default value: false
      "$Type" : "<12.4.2 Parameter Type>",
      "$Nullable" : false, // omit in case of default value: true
      "$MaxLength" : <12.4.4 MaxLength>, // optional, number
      "$Precision" : <12.4.4 Precision>, // optional, number
      "$Scale" : <12.4.4 Scale> | "variable", // optional, number or fixed string
      "$SRID" : "<12.4.4 SRID>" // optional
    }, ...], // optional
    "$ReturnType" : { "@..." : <value>,
      "$isCollection" : true, // omit in case of default value: false
      "$Type" : "<12.3.1 ReturnType Type>",
      "$Nullable" : false, // omit in case of default value: true
      "$MaxLength" : <11.1.3 MaxLength>, // optional, number
      "$Precision" : <11.1.3 Precision>, // optional, number
      "$Scale" : <11.1.3 Scale> | "variable", // optional, number or fixed string
      "$SRID" : "<11.1.3 SRID>" // optional
    } // optional
  }, ...],
  "<5.1.1 Schema Namespace>.<12.2.1 Function Name>" : [{ "@..." : <value>,
    "$kind" : "Function",
    "$IsBound" : true, // omit in case of default value: false
    "$IsComposable" : true, // omit in case of default value: false
    "$EntitySetPath" : "<12.2.4 Function EntitySetPath>", // optional
    "$Parameter" : [{
      // see above
    }, ...], // optional
    "$ReturnType" : {
      // see above
    }
  }, ...],
  "<5.1.1 Schema Namespace>.<13.1.1 EntityContainer Name>" : {
    "$kind" : "EntityContainer"
//      "$Extends" : "<13.1.2 EntityContainer Extends>", // not in the 1st step
    "<13.2.1 EntitySet Name>" : {
      "$kind" : "EntitySet",
      "$Type" : "<13.2.2 EntitySet EntityType>", // Note: renamed for consistency!
      "$IncludeInServiceDocument" : false, // omit in case of default value: true
      "$NavigationPropertyBinding" : {
        "<13.4.1 NavigationPropertyBinding Path>" : "<13.4.2 NavigationPropertyBinding Target>" // normalized
      } // optional
    },
    "<13.3.1 Singleton Name>" : {
      "$kind" : "Singleton",
      "$Type" : "<13.3.2 Singleton Type>",
      "$NavigationPropertyBinding" : {
        "<13.4.1 NavigationPropertyBinding Path>" : "<13.4.2 NavigationPropertyBinding Target>" // normalized
      } // optional
    },
    "<13.5.1 ActionImport Name>" : {
      "$kind" : "ActionImport",
      "$Action" : "<13.5.2 ActionImport Action>",
      "$EntitySet" : "<13.5.3 ActionImport EntitySet>" // optional, normalized
    },
    "<13.6.1 FunctionImport Name>" : {
      "$kind" : "FunctionImport",
      "$Function" : "<13.6.2 FunctionImport Function>",
      "$EntitySet" : "<13.6.3 FunctionImport EntitySet>", // optional, normalized
      "$IncludeInServiceDocument" : true // omit in case of default value: false
    }
  },
  "<5.1.1 Schema Namespace>.<14.1.1 Term Name>" : {
    "$kind" : "Term",
    "$isCollection" : true, // omit in case of default value: false
    "$Type" : "<14.1.2 Term Type>",
    "$BaseTerm" : "<14.1.3 Term BaseTerm>", // optional
//    "$DefaultValue" : "<14.1.4 Term DefaultValue>", // omit in case of default value: null
//    "$AppliesTo" : "<14.1.5 Term AppliesTo>", // JSON clients need not validate
    "$Nullable" : false, // omit in case of default value: true
    "$MaxLength" : <14.1.6 MaxLength>, // optional, number
    "$Precision" : <14.1.6 Precision>, // optional, number
    "$Scale" : <14.1.6 Scale> | "variable", // optional, number or fixed string
    "$SRID" : "<14.1.6 SRID>" // optional
  }
}
Constant and Dynamic Expressions

Constant and dynamic expressions are used as values for annotations. Their JSON representation is shown in the following two tables.

Table 1: Constant Expressions

Expression

Options

Additional Information

14.4 Constant Expressions

{"$Binary" : "T0RhdGE"}

{"$Date" : "2000-01-01"}

{"$DateTimeOffset" : "2000-01-01T16:00:00.000-09:00"}

{"$Decimal" : "3.14"}

{"$Duration" : "P11D23H59M59.999999999999S"}

{"$Guid" : "21EC2020-3AEA-1069-A2DD-08002B30309D"}

{"$TimeOfDay" : "21:45:00"}

"Binary", "Date", "DateTimeOffset", "Decimal", "Duration", "Guid", "TimeOfDay" are objects with a single property that has a string value.

14.4.2 Expression Bool

false

true

Is represented by the JavaScript boolean literals.

14.4.7 Expression EnumMember

{"$EnumMember" : 42}

{"$EnumMember" : "1234567890123456789"}

Is represented like above object notation, but with a JavaScript number literal as long as the value is a safe integer, else with a string value.

14.4.8 Expression Float

3.1415926535

{"$Float" : "-INF"}

{"$Float" : "INF"}

{"$Float" : "NaN"}

Is represented by a JavaScript number literal (except for the nanInfinity ABNF rule which needs an object notation with a string value).

14.4.10 Expression Int

42

{"$Int" : "1234567890123456789"}

Is represented by a JavaScript number literal as long as the value is a safe integer. Else the above object notation is used.

14.4.11 Expression String

"Product Catalog"

Is represented by a JavaScript string literal.

Table 2: Dynamic Expressions

Expression

Options and Additional Information

14.5.1 Comparison and Logical Operators

edm:Not is written as {"$Not" : <value>, "@..." : <value>}. All others are written like {"$And" : [<value>, <value>], "@..." : <value>} because they require two child expressions.

14.5.2 Expression AnnotationPath

{"$AnnotationPath" : "..."}

14.5.3 Expression Apply

{"$Apply" : [<value>, ...], "$Function" : "<14.5.3.1 Apply Function>", "@..." : <value>}

14.5.4 Expression Cast

{
"$Cast" : <value>,
"$isCollection" : true, // omit in case of default value: false
"$Type" : "<14.5.4.1 Cast Type>",
"$MaxLength" : <6.2.2 MaxLength>, // optional, number
"$Precision" : <6.2.3 Precision>, // optional, number
"$Scale" : <6.2.4 Scale> | "variable", // optional, number or fixed string
"$SRID" : "<6.2.6 SRID>", // optional
"@..." : <value>
}

14.5.5 Expression Collection

[<value>, ...]

Simply an array. No additional properties, no annotations possible.

14.5.6 Expression If

{"$If" : [<value>, <value>, <value>], "@..." : <value>}

Condition, then, else (which is optional inside a "14.5.5 Expression Collection" only).

14.5.7 Expression IsOf

{
"$IsOf" : <value>,
"$isCollection" : true, // omit in case of default value: false
"$Type" : "<14.5.7.1 IsOf Type>",
"$MaxLength" : <6.2.2 MaxLength>, // optional, number
"$Precision" : <6.2.3 Precision>, // optional, number
"$Scale" : <6.2.4 Scale> | "variable", // optional, number or fixed string
"$SRID" : "<6.2.6 SRID>", // optional
"@..." : <value>
}

14.5.8 Expression LabeledElement

{"$LabeledElement" : <value>, "$Name" : "<5.1.1 Schema Namespace>.<14.5.8.1 LabeledElement Name>", "@..." : <value>}

14.5.9 Expression LabeledElementReference

{"$LabeledElementReference" : "<QualifiedName name of a labeled element expression in scope>"}

14.5.10 Expression Null

null

{"$Null" : null, "@..." : <value>}

The object notation is needed in case of inline annotations.

14.5.11 Expression NavigationPropertyPath

{"$NavigationPropertyPath" : "..."}

14.5.12 Expression Path

{"$Path" : "..."}

14.5.13 Expression PropertyPath

{"$PropertyPath" : "..."}

14.5.14 Expression Record

The record itself is a map:

{
  "$Type" : "<14.5.14.1 Record Type>",
  "<14.5.14.2.1 PropertyValue Property>" : <value>,
  "@..." : <value>
}

14.5.15 Expression UrlRef

{"$UrlRef" : <value>, "@..." : <value>}