HCMS Schema - Asset Reference Features
Explains the use of asset reference features in Headless CMS schemas.
Reference features are features with the value type asset or asset_key_ref. The value type can either be hinted with the property "cs:feature.value_type" in the schema or is already defined for existing features.
There are several possible ways to map reference features to/from JSON documents that can be selected in the schema with the optional property "cs:feature.$ref_type", defaulting to the actually stored value. This means that the asset id is returned for value type asset and the resource key for asset_key_ref if no particular $ref_type is provided. Please note that asset references can be correctly mapped as inline only since version 1.7.
Reference by Asset id
Basic type of mapping: JSON document contains the asset id (feature censhare:asset.id) of the referenced asset. It can be mapped as integer, number or string. Note that the import can fail if the string does not contain proper integer value.
Mapping as a Single Value
The schema below shows the correct mapping of an asset reference feature to an integer property.
{
"type": "object",
"properties": {
"perm-groups": {
"minValue": 0,
"maxValue": 9007199254740991,
"cs:feature.key": "censhare:module.oc.permission.group-ref",
"type": "integer"
}
}
}
Example entity:
{
"perm-groups": 51706
}
Multi-value Features as Array:
The schema below shows the correct mapping of an multi-value asset reference feature to an array of integers.
{
"type": "object",
"properties": {
"perm-groups": {
"type": "array",
"items": {
"cs:feature.key": "censhare:module.oc.permission.group-ref",
"type": "integer",
"minValue": 0,
"maxValue": 9007199254740991
}
}
}
}
Example entity:
{
"perm-groups": [
51706,
51707
]
}
id as String Value
The schema below shows the correct mapping of an asset reference feature to a string property.
{
"type": "object",
"properties": {
"perm-groups": {
"type": "array",
"items": {
"cs:feature.key": "censhare:module.oc.permission.group-ref",
"type": "string"
}
}
}
}
Example entity:
{
"perm-groups": [
"51706",
"51707"
]
}
Reference by id_extern
In censhare environments it is common practice to store the external primary key prefixed with a source system identifier in the string typed feature censhare:asset.id_extern when importing data into assets. If the ref_type is set to id_extern the reference is represented by the censhare:asset.id_extern feature instead of the censhare primary key, also known as asset id.
The schema below shows the mapping:
{
"type": "object",
"properties": {
"workspace": {
"cs:feature.value_type": "asset",
"cs:feature.$ref_type": "id_extern",
"type": "string"
}
}
}
Example entity:
{
"workspace": "workspace:13136"
}
The same entity can be also be mapped to number value, suppressing the prefix "workspace:" in the JSON representation:
{
"id": 51728
}
by using cs:feature.$ref_transformation:
{
"type": "object",
"properties": {
"workspace": {
"cs:feature.value_type": "asset",
"cs:feature.$ref_transformation": {
"internal_prefix": "workspace:"
},
"cs:feature.$ref_type": "id_extern",
"type": "integer"
}
}
}
Reference by Asset Key Reference Feature
Example schema
{
"type": "object",
"properties": {
"city": {
"type": "string",
"cs:feature.value_type": "asset_key_ref",
"cs:feature.$ref_type": "asset_key"
}
}
}
Example entity:
{
"city": "censhare:city.london"
}
The property "cs:feature.$ref_type" defaults to asset_key, therefore the reference schema can be simplified:
{
"type": "object",
"properties": {
"city": {
"cs:feature.value_type": "asset_key_ref",
"type": "string"
}
}
}
This mapping is not the only possible one, all options available for asset features are available for asset_key_ref too.
For example, the mapping above can be modified to use asset ID as external value, despite using key reference internally:
{
"type": "object",
"properties": {
"city": {
"cs:feature.value_type": "asset_key_ref",
"cs:feature.$ref_type": "asset_id",
"type": "integer"
}
}
}
and the entity shown above now contains just two integers:
{
"city": 10007
}
Representation as Links
Asset references can also be represented as URLs referencing the target assets as entities in the Headless CMS REST API by setting the $ref_type to link.
{
"type": "object",
"properties": {
"perm-groups": {
"type": "array",
"items": {
"cs:feature.key": "censhare:module.oc.permission.group-ref",
"cs:feature.$ref_type": "link",
"type": "string"
}
}
}
}
Example entity:
{
"perm-groups": [
"http://localhost:8080/hcms/v2.1/entity/group/51706",
"http://localhost:8080/hcms/v2.1/entity/group/51707"
]
}
Note that the linked entity might be present in several different schemas at once and only one of them can be chosen. This is always done by checking asset type, with following rules:
Schemas specified by cs:feature.$ref_schema property are checked first, in given order. First one that exists and is applicable for the target asset type is chosen.
All known schemas are processed in order specified by their cs:$priority value (ascending, default is 0). First one that is applicable for the target asset type is chosen.
If several schemas with the same priority match, it is not specified which one is actually used.
Master File URL
Besides the $ref_type link, there is also content_link, which provides a read only URL to the first master storage items binary data of the referenced asset. The value is considered missing if the target asset has no storage item.
{
"type": "object",
"properties": {
"perm-groups": {
"type": "array",
"items": {
"cs:feature.key": "censhare:module.oc.permission.group-ref",
"cs:feature.$ref_type": "content_link",
"type": "string"
}
}
}
}
Example entity:
{
"perm-groups": [
"http://localhost:8080/hcms/v2.1/entity/group/storage/MDA2ODgyNS8xOC9wcmV2aWV3",
"http://localhost:8080/hcms/v2.1/entity/group/storage/Njg4MjUvMjcvdGh1bWJuYWls"
]
}
Inline Mapping
This mapping type allows to hide the general graph nature of the database and merge many assets into a single document, which can be utilized to reduce the number of REST calls to fetch a data structure.
When exporting the entity, the target is completely serialized as a JSON object. When importing, the target asset is overwritten (or even created, if needed) by the data from the JSON object.
For all intents and pusposes, this is exactly the same as inline mapping of relations. The only differences are:
Properties should start with prefix cs:feature. instead of cs:relation.. The schema parser, however, is lenient and accepts both variants.
There is no cs:feature.direction, because features are unidirectional.
Reference type "cs:feature.$ref_type": "INLINE" must be explicitly specified.
This is the only difference to the relation mapping, where this directive is optional.
Neither asset-type filter ("cs:relation.$filter.asset_type") nor feature value filter ("cs:relation.$filter.feature") is allowed.
"cs:asset.type" is required, but used only when new assets has to be created. Just like with relation inlined mapping, target assets are serialized regardless of their asset type.
Warning: Just like in the case of relations, inline mapping is quite dangerous when used for writing (that is, PUT or POST operations on the entities). In most cases, special directives "cs:relation.$selection_key" and "cs:relation.$inline_import" should be used (both of them). Detailed description is in the relation document and not duplicated here. Note that in the most versions of HCMS, the directive "cs:feature.$inline_import" is broken and ignored; "cs:relation.$inline_import" must be used even for features. Please check the release notes to see when this bug is fixed.
Example of schema with person objects (referenced by a feature "censhare:event.attendee") inlined to show their names:
{
"title": "Guest list",
"type": "object",
"properties": {
"members": {
"type": "array",
"items": {
"cs:feature.key": "censhare:event.attendee",
"cs:feature.value_type": "ASSET",
"cs:feature.$ref_type": "INLINE",
"cs:asset.type": "person.",
"cs:relation.$selection_key": [
"id"
],
"type": "object",
"properties": {
"name": {
"cs:feature.key": "censhare:asset.name",
"type": "string"
},
"id": {
"minValue": 0,
"maxValue": 9007199254740991,
"cs:feature.key": "censhare:asset.id",
"type": "integer"
}
}
}
},
"name": {
"cs:feature.key": "censhare:asset.name",
"type": "string"
}
}
}
Example entity:
{
"members": [
{
"name": "Karl",
"id": 14910
},
{
"name": "Jill",
"id": 14820
},
{
"name": "Jack",
"id": 14850
}
],
"name": "my guest list",
"id": 14884
}
Similar example, but with only one person:
{
"title": "Event",
"type": "object",
"properties": {
"owner": {
"cs:feature.key": "censhare:event.owner",
"cs:feature.value_type": "ASSET",
"cs:feature.$ref_type": "INLINE",
"cs:asset.type": "person.",
"type": "object",
"properties": {
"name": {
"cs:feature.key": "censhare:asset.name",
"type": "string"
},
"id": {
"minValue": 0,
"maxValue": 9007199254740991,
"cs:feature.key": "censhare:asset.id",
"type": "integer"
}
}
},
"name": {
"cs:feature.key": "censhare:asset.name",
"type": "string"
}
}
}
Example data:
{
"owner": {
"name": "Jack",
"id": 14850
},
"name": "some event",
"id": 14884
}
Enum values in descriptive schema
Asset reference features are technically not limited and can have any asset as their value, but quite often they are used to represent an "enum". In these cases, only small set of assets are offered to the user
as a possible candidates for a value (usually rendered as a dropdown list or a similar UI component). This pattern is usually used when these values are managed by users without administrative privileges,
who are not permitted to change values in the standard enumeration features (Value List in Java Admin Client).
It is possible to provide this limited list in the [descriptive schema and metadata api](HCMS censhare Server Meta Data) by using special "cs:feature.$ref_enum" directive.
It has two forms: one is very generic and can serve any list expressed as a query, the second one is specific for the standard pattern used by module.feature. or product.feature. assets.
In both cases, enum values are rendered by using standard name and description features (both localized and non-localized); there is no way (in current version) to customise the result in any way.
Generic enum list
This variant requires existing schema that can be searched. Content of this schema is not defined in any way, it can contain any properties.
The only requirement is that the entities can be searched (which excludes mixins).
Value of "cs:feature.$ref_enum" is a JSON object with following properties:
schema - name of the schema to search in; mandatory
query - query to search in the given schema; optional, but recommended (without this property, all entities in the schema are presented as enum values)
order - ordering specification, with the same syntax and semantics as the corresponding query parameter in REST API; optional
limit - maximum number of assets == maximum number of values; optional, default value is 100
Example:
{
"cs:feature.key": "demo:product.laundry.bleaching",
"cs:feature.$ref_enum": {
"schema": "internal.product.feature.item",
"order": "name",
"limit": 50,
"query": "resourceKey=^\"demo:product-feature-item.laundry.bleaching.\""
}
}
Direct lookup in feature item asset
In this variant, the value of "cs:feature.$ref_enum" is a JSON object with two mandatory properties:
asset - resource key of the feature asset
This asset is usually of type module.feature. or product.feature., but this is not a requirement - any existing asset with this resource key is accepted/
This asset is expected to have several features of the reference type that points to values themselves.
feature - feature key used to lookup feature-item assets from the feature asset
{
"cs:feature.key": "demo:product.laundry.bleaching",
"cs:feature.$ref_enum": {
"asset": "demo:product-feature.laundry.bleaching",
"feature": "censhare:product.feature-item"
}
}