SData prototypes
Prototypes play a role roughly corresponding to schemas in SData v1.1; the advantage is that they are expressed as SData JSON objects and are more flexible and compact than XML Schema Definition documents. Prototypes define the native and metadata properties of a resource kind, specifying the corresponding types and, for metadata, the default values.
The following subsections introduce the SData prototypes by:
- describing the format and function of the $prototype object,
- indicating how a $prototype object can surface in a response,
- showing how prototypes can be retrieved individually.
A prototype is a resource that bundles the metadata of a resource kind representation. If metadata is provided, the usage of prototypes in the JSON context is strongly RECOMMENDED but not mandatory.
$prototype object
A prototype is a JSON object and is formed according to the rules laid out in the document “JSON formatting of SData responses”. Metadata elements that appear in a prototype are:
| Compliance | Description | |
|---|---|---|
| $properties | MUST | contains the metadata for all the individual properties of an object |
| $links | MAY | contains the elements describing the possible operations for an element (see Section Links of this document) |
Example:
Consider the following Address resource kind with metadata enclosed in square brackets:
- ID: [integer, Mandatory]
- Street: [string, title=”Street”, Mandatory]
- StreetNumber: [integer, title=”Number”]
- City: [string, title=”City”, Mandatory]
- PostalCode: [string, title=”ZipCode”, Mandatory]
- Country: [referenceToCountryResourceKind, Mandatory]
- Name: [string]
- ISOCode: [string]
- [url=”http://www.example.com/sdata/MyApp/-/-/countries(‘{ISOCode}’)”]
The prototype describing this resource is shown below:
{
"$baseURL" : "http://www.example.com/sdata/MyApp/-/-",
"$properties": {
"ID": {
"$title": "AddressId",
"$type": "sdata/integer",
"$isMandatory": true
},
"Street": {
"$title": "Street",
"$type": "sdata/string",
"$isMandatory": true
},
"StreetNumber": {
"$title": "Number",
"$type": "sdata/integer"
},
"City": {
"$title": "City",
"$type": "sdata/string",
"$isMandatory": true
},
"PostalCode": {
"$title": "ZipCode",
"$type": "sdata/string",
"$isMandatory": true
},
"Country": {
"$title": "Country",
"$type": "sdata/reference",
"$links": {
"$prototype": {
"$title": "Country list prototype",
"$id" : "lookup",
"$url": "{$baseUrl}/$prototypes/countries('{$id}')"
}
},
"$isMandatory": true,
"$item": {
"$url": "http://www.example.com/sdata/MyApp/-/-/countries('{ISOCode}')",
"$properties": {
"Name": {
"$title": "Country name",
"$type": "sdata/string",
"$isMandatory": true
},
"ISOCode": {
"$title": "Country code",
"$type": "sdata/string",
"$format": "country",
"$isMandatory": true
}
}
}
}
},
"$links": {
"$updateFull": {
"$title": "Update the resource",
"$type": "application/json;vnd.sage=sdata",
"$url": "{$url}",
"$method": "PUT"
},
"$prototype": {
"$title" : "Customer address prototype",
Page 24
"$id" : "detail",
"$url" : "{$baseURL}/prototypes/addresses('{$id}')"
}
}
}
Prototypes exposed by an application: the $prototypes URL segment
The prototypes of an application are SData JSON resources retrievable by a GET operation. The URL segments of a prototype are formed according to the pattern:
…/$prototypes/[<resourceKindName>[(‘<prototypeId>’)]] where:
- $prototypes: is a reserved segment located at the resource kind level 8. This MUST be supported if prototype resources are present.
- resourceKindName: is the name of the resource whose prototype it is. This SHOULD be supported if at least one prototype is available for a resource kind.
- prototypeId: MAY be present. It is the identifier for the prototype and relates to the representation of a resource 9.
Retrieving the prototype of a resource kind
The prototype of a resource kind is intimately related to the representation of a resource. This means that it is possible to have several prototypes, each describing individual representations of a resource. This is easy to see when looking at the differences between a feed of resources and an individual resource: in the first case the information is succinct, while in the second it would be rather extensive. Another example is the prototype for a representation of a resource in a mobile context (where bandwidth and screen area are prime assets) compared with that for a desktop or full-browser client.
Prototypes are reasonably static. This means that they should be retrieved once, cached and then applied many times. Consequently, a versioning mechanism (eTag or modifiedDate) would greatly benefit the client-side handling of prototype and therefore providers SHOULD support such a mechanism.
Requesting metadata Section of this document described the means for retrieving prototypes. The remainder of this section provides more details on retrieving multiple prototypes via links.
For example:
GET http://www.example.com/sdata/MyApp/myContract/-/$prototypes/addresses
would provide a response similar to:
{
"$baseURL" : "http://www.example.com/sdata/MyApp/-/-",
"$url" : "{$baseURL}/prototypes/addresses",
"$title" : "all Address prototypes",
"$resources" : [
{
"$id": "detail",
"$prototype": {
"$url" : "{$baseURL}/addresses('{$ID}')",
"$properties": {
"ID": {
"$title": "AddressId",
"$type": "sdata/integer",
"$isMandatory": true
}
},
"...": "...",
"$links": {
"$prototype": {
"$id": "detail",
"$url": "{$baseURL}/prototypes/addresses('{$id}')",
"$title": "Customer address prototype"
}
}
}
},
{
"$id": "list",
"$prototype": {
"$url" : "{$baseURL}/addresses('{$ID}')",
"$properties": {
"ID": {
"$title": "AddressId",
"$type": "sdata/integer",
"$isMandatory": true
}
},
"...": "...",
"$links": {
"$prototype": {
"$id": "list",
"$url": "{$baseURL}/prototypes/addresses('{$id}')",
"$title": "Customer address feed"
}
}
}
}
]
}
The GET operation on the reserved $prototypes segment will return links to all the prototypes exposed by the application. The returned payload contains:
- One array property for every resource kind where prototypes are available;
- The array element contains at least the following properties pertaining to the prototype:
- $url
- $resourceKind
- $id
- $title
Example:
GET http://www.example.com/sdata/MyApp/-/-/$prototypes
Would return a payload similar to:
{
"$baseURL" : "http://www.example.com/sdata/MyApp/-/-",
"$title" : "Links to all prototypes",
"$totalResults" : 32,
"$startIndex" : 1,
"$itemsPerPage" : 10,
"$resources" : [
{
"$title" : "Address entry prototype",
"$resourceKind" : "address",
"$url" : "{$baseURL}/prototypes/addresses('detail')",
"$id" : "detail"
},
{
"$title" : "Address feed prototype",
"$resourceKind" : "addresses",
"$url" : "{$baseURL}/prototypes/addresses('list')",
"$id" : "list"
},
{
"$title" : "Customer entry prototype",
"$resourceKind" : "customer",
"$url" : "{$baseURL}/prototypes/customers('detail')",
"$id" : "detail"
},
{
"$title" : "Customer feed prototype",
"$resourceKind" : "customers",
"$url" : "{$baseURL}/prototypes/customers('list')",
"$id" : "list"
}
]
}
Merge process
For the consumer of a JSON formatted response that leverages metadata, objects are obtained in their entirety by merging the prototype with the payload information. The information in the payload has precedence and overlays/overrides the prototype definitions. 11
The interplay between prototype and payload has several key attributes:
- Metadata is expressed in JSON.
- Metadata is available at the resource kind level and ideally even finer-granular levels.
- Ability to override metadata at any level (feed/entry/property).
- Reduce verbosity of transferred information.
The merge process is a conceptual process, meaning that a consumer will likely use a variety of local techniques to efficiently implement it while maintaining the same overall effect.
Example: Consider the following prototype:
{
"$baseUrl": "http://www.example.com/sdata/MyApp/-/-",
"$url": "{$baseUrl}/addresses",
"$title": "Address list",
"$properties": {
"ID": {
"$title": "AddressId",
"$type": "sdata/integer",
"$isMandatory": true
},
"Street": {
"$title": "Street",
"$type": "sdata/string",
"$isMandatory": true
},
"StreetNumber": {
"$title": "Number",
"$type": "sdata/integer"
},
"City": {
"$title": "City",
"$type": "sdata/string",
"$isMandatory": true
},
"PostalCode": {
"$title": "ZipCode",
"$type": "sdata/string",
"$isMandatory": true
},
"Country": {
"$title": "Country",
"$type": "sdata/reference",
"$links": {
"$prototype": {
"$id": "lookup",
"$url": "{$baseUrl}/$prototypes/countries('{$id}')",
"$title": "Country lookup prototype"
}
},
"$url": "http://www.example.com/sdata/MyApp/-/-/countries('{ISOCode}')",
"$isMandatory": true,
"$item": {
"$properties": {
"Name": {
"$title": "Country name",
"$type": "sdata/string",
"$isMandatory": true
},
"ISOCode": {
"$title": "Country code",
"$type": "sdata/string",
"$isMandatory": true
}
}
}
},
"$links": {
"$prototype": {
"$id": "list",
"$url": "{$baseUrl}/$prototypes/addresses('{$id}')",
"$title": "Address feed prototype"
}
}
}
}
Matching the previous prototype is the following JSON formatted payload:
{
"$baseUrl": "http://www.example.com/sdata/MyApp/-/-",
"$url": "{$baseUrl}/addresses?creditLimitExceeded=true" ,
"$title": "Addresses of accounts with exceeded credit limit" ,
"$resources": [
{
"ID": "7123a",
"Street": "Lerchenweg",
"StreetNumber": 11,
"PostalCode": 71711,
"City": "Marbach am Neckar",
"Country": {
"Name": "Germany",
"ISOCode": "DE"
},
"$properties": {
"PostalCode": {
"$isMandatory": false
}
}
},
{
"ID": "hw7631",
"Street": "Fleet Street",
"StreetNumber": 31,
"City": "London",
"PostalCode": "EC4Y 8EQ",
"Country": {
"Name": "United Kingdom",
"ISOCode": "GB"
}
}
]
}
The above payload provides, in addition to the payload (in blue) a series of specific metadata (in yellow background) for:
- The URL of the feed ($url)
- The title of the feed ($title)
- The type of the first - German - address, that must be numeric according to German rules
After the merge process, the logical JSON object will contain the following:
{
"$baseUrl": "http://www.example.com/sdata/MyApp/-/-",
"$url": "{$baseUrl}/addresses?creditLimitExceeded=true",
"$title": "Addresses of accounts with exceeded credit limit",
"$resources": [
{
"ID": "7123a",
"Street": "Lerchenweg",
"StreetNumber": 11,
"PostalCode": 71711,
"City": "Marbach am Neckar",
"Country": {
"Name": "Germany",
"ISOCode": "DE"
},
"$properties": {
"ID": {
"$title": "AddressId",
"$type": "sdata/integer",
"$isMandatory": true
},
"Street": {
"$title": "Street",
"$type": "sdata/string",
"$isMandatory": true
},
"StreetNumber": {
"$title": "Number",
"$type": "sdata/integer"
},
"City": {
"$title": "City",
"$type": "sdata/string",
"$isMandatory": true
},
"PostalCode": {
"$title": "ZipCode",
"$type": "sdata/string",
"$isMandatory": false
},
"Country": {
"$title": "Country",
"$type": "sdata/reference",
"$links": {
"$prototype": {
"$id": "lookup",
"$url": "{$baseUrl}/$prototypes/countries('{$id}')",
"$title": "Country lookup prototype"
}
},
"$url": "http://www.example.com/sdata/MyApp/-/-/countries('{ISOCode}')",
"$prototype": "{$baseUrl}/$prototypes/countries('lookup')",
"$isMandatory": true,
"Name": {
"$title": "Country name",
"$type": "sdata/string",
"$isMandatory": true
},
"ISOCode": {
"$title": "Country code",
"$type": "sdata/string",
"$isMandatory": true
}
}
},
"$links": {
"$prototype": {
"$id": "list",
"$url": "{$baseUrl}/$prototypes/addresses('{$id}')",
"$title": "Address feed prototype"
}
}
},
{
"ID": "hw7631",
"Street": "Fleet Street",
"StreetNumber": 31,
"City": "London",
"PostalCode": "EC4Y 8EQ",
"Country": {
"Name": "United Kingdom",
"ISOCode": "GB"
},
"$properties": {
"...": "...",
"PostalCode": {
"$title": "ZipCode",
"$type": "sdata/string",
"$isMandatory": true
}
},
"$links": {
"$prototype": {
"$id": "list",
"$url": "{$baseUrl}/$prototypes/addresses('{$id}')",
"$title": "Address feed prototype"
}
}
}
]
}
Please note that the $type of the PostalCode property of the first address object is ‘sdata/integer’ as overridden by the provider.
8. For more information, see the discussion in the SData URL chapter of the “SData 2.0 - Core” document
9. It is important to note that there may be several prototypes associated with a single resource kind. For example, an application could distinguish between information delivered for a feed of a resource kind, that of an individual entry and yet again to that of a resource at creation.
11. To remove a metadata element defined in the prototype, the payload defines the property with null value.


