Previous Page Arrow Next Page Arrow

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:

ComplianceDescription
$propertiesMUSTcontains the metadata for all the individual properties of an object
$linksMAYcontains 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.

Previous Page Arrow Next Page Arrow