API Definition
API Definition
The first step in developing resources for Cortex is to define them using the API definition language. the API definition is an XML file in your project in which you describe the various resources types, their URIs, advisors and the relationships between them. From this XML file, a set of prototype classes is generated for you to implement.
The XML schema can be found here.
For examples of fully implemented APIs and resources for common use cases, see the Helix Pattern Catalog.
Defining an Entity Resource
The most basic type of resource you can define is an Entity resource. The definition of an entity resource consists of an entity, which describes or provides access to data of some sort, a URI-part, which acts as an identifier for the resource, and the resource itself, which links the URI-part to the entity. You must define all three of these things.
Entity Resources support CREATE, READ, UPDATE, and DELETE operations. You must implement one of these operations in your generated prototype.
Defining a URI-part
URI-part is an identifier for a resource's URI, allowing us to never deal directly with the URI string. For more information, see Resource Identifiers.
To define an identifier part, use the <uri-part/> element:
<uri-part> <name>car-id</name> <description>Identifier for one car</description> </uri-part>
Defining an Entity
Entity resources are used to provide access to some form of data. An entity resource definition consists of and <entity/> definition an a corresponding <resource/> definition.
The definition of an entity itself is as follows:
<entity> <name>car</name> <description>A car.</description> <property> <name>brand</name> <description>The brand of the car</description> <string/> </property> <property> <name>model</name> <description>The model of the car</description> <string/> </property> <property> <name>year-build</name> <description>The year the car was build</description> <integer/> </property> </entity>
An entity must have a <name>, <description>, and at least one <property>. The property must have a data type: in the example above, these are defined by the <string/> and </integer> elements. Cortex provides support for a number of "primitive" property types, including string, integer, long, boolean, and decimal. See the XML schema for the full list of supported types.
Defining an Entity Resource
The resource part of an entity resource links the URI-part to the entity, and provides a name which can be used to access both.
To define the Entity Resource for a given entity:
<resource> <name>car</name> <description>A car resource.</description> <uri>/{base.family}/{car-id}</uri> <entity>car</entity> </resource>
Extending Entities
You can extend entities by using <is-a/>. There are two ways of extending an entity: inheritance and composition. You can extend an entity within its same family, or with an outside family.
In the API definition schema, entitles are defined with a <family /> element. Conceptually similar entities. For example different types of cars are defined within the 'cars' family.
Adding properties to an existing Entity
If you want to extend an existing entity by adding fields specific to a subtype, you can use <is-a/> to add properties to an entity:
<entity> <name>car-with-country</name> <description>car entity with country property</description> <is-a>car</is-a> <property> <name>country-built</name> <description>The country where the car was built</description> <string/> </property> </entity>
Composing a New Entity out of Existing Entities
If you want an entity that contains multiple entities build an entity out of existing entities:
<entity> <name>composition-same-family</name> <description>An entity with unvalidated properties</description> <property> <name>is-a-property</name> <description>A property that is a reference to another entity</description> <is-a>car</is-a> </property> <property> <name>list-of-is-a</name> <description>A list (array) of other entities</description> <array> <is-a>car</is-a> </array> </property> </entity>
Dynamic Entities
A dynamic entity resource is an entity resource which operates on an entity containing dynamic properties. These dynamic properties can be used if the properties to be contained in an entity are not known when modeling the API definition or the entity returned by the entity resource contains different properties depending on the state.
<resource> <name>truck</name> <description>A truck resource with a dynamic truck entity.</description> <uri>/{base.family}/{truck-id}</uri> <entity>truck</entity> </resource>
Note: make sure when injecting a dynamic property entity to validate if the property keys you are expecting are actually contained in the dynamic property map.
For more information on dynamic entities, see Dynamic Fields.
Types of Resources
In addition to the basic entity resource, there are a number of specialized resources that provide additional functionality and types of linking between difference resources.
Alias Resources
Alias resources are used to create a redirect to another resource. For example, given the following resource:
<resource> <name>color</name> <description>A resource that represents a color</description> <uri>/{base.family}/{base.scope}/{color-id}</uri> <entity>color</entity> </resource>
An alias resource can be defined as follows:
<resource> <name>default-color</name> <description>A resource that represents the default color, it is an alias to the color resource</description> <uri>/{base.family}/{base.scope}/default</uri> <alias>color</alias> </resource>
Alias resources only support READ operations.
List Resources
List resources represent collections or sets of other resources.
To define a list resource:
<resource> <name>countries</name> <description>A list of countries resource.</description> <uri>/{base.family}/{base.scope}</uri> <list-of>country</list-of> </resource>
Where the <list-of/> element is the name of a resource.
List resources support READ and CREATE operations.
Paginated List Resources
List resources always return all elements of a collection of other resources. Sometimes collections can contain a lot of elements and returning the whole collection might lead to poor performance. A paginated list resource returns a subset of the elements of a collection, with a defined number of items of the collection. To achieve this, a paginated list resource divides the collection into even sized buckets of elements. Each bucket can be accessed individually by accessing the paginated list resource parametrized.
To define a paginated list resource:
<resource> <name>paginated-countries</name> <description>A list of countries resource.</description> <uri>/{countries}/pages/{page-id}</uri> <paginates>country</paginates> </resource>
Where the <paginates/> element is the name of the collected resource.
Paginated list resources support the READ operation.
When creating an element that should be added to the collection, use a list resource and perform a CREATE operation on it (you don't necessarily have to implement the READ operation of the list resource for this).
Link Point Resource
A Link point resource has no representation on its own: it has a name, description and URI attributes. Link point resources exist only to provide a place for links to be attached to.
The root resource is a good example of a link point. It does not represent a particular data type itself, like a cart or an order, but provides a resource where links can be attached.
To define a link point resource:
<resource> <name>bookmarks</name> <description>bookmarks resource</description> <uri>/{base.family}/bookmarks</uri> </resource>
This snippet defines a link point resource called bookmarks. To attach links to this resource, we would define one or more <relationship/> elements with (in this case) bookmarks as the <from/> reference. See Relationships for more information.
Selector Resource
Selector Resources are used when a state of a resource is modifiable by selection of choices.
The different selection choices are either in the state choice or chosen. Choice reflects that a selection could be chosen and chosen reflects that a selection is chosen.
A selector resource definition consists of two resources. First, a selector resource to declare which resource it will act as a selector for, using the <selector-for/> element:
<resource> <name>billingaddress-info-selector</name> <description>Selects the billing address to use for an order.</description> <uri>{billingaddress-info}/selector</uri> <selector-for>billingaddress-info</selector-for> </resource>
Second, a choice resource to declare what type of resources can be chosen from, using the <choices-for/> element:
<resource> <name>billingaddress-info-selector-choice</name> <description>A choice for the billing address selector.></description> <uri>{billingaddress-info-selector}/{address}</uri> <choices-for>billingaddress-info-selector</choices-for> </resource>
In the example, a choice between different addresses is modeled. This is defined by the URI identifier-part {address}, which points to the address resource. By convention, the choice resource also to declare which selector resource it is associated with. The <choices-for> tag serves this purpose.
Form Resource
A form resource combines an entity, action-rel and result into a single resource. This provides the following functionality:
- A READ form prototype to retrieve form data
- An action link which links a POST operation from the READ operation,
- A POST form prototype which processes the form's posted data.
<resource> <name>create-order-form</name> <description>Create order form resource</description> <uri>{item}/form</uri> <form> <entity>create-order-form</entity> <action-rel>submit-action</action-rel> <result>order</result> </form> </resource>
Advisor
An advisor is used to give advice on a resource operation.
There are two types of advises with different semantics: Non-blocking Advisors and Blocking Advisors. For more information, see Advisors.
Non-blocking Advisor
A non-blocking advisor provides additional information when a READ operation is performed on a resource, but does not affect the HTTP status code emitted by the READ operation.
To define a non-blocking advisor:
<advisor> <name>terms-for-order-form</name> <description>Terms and Conditions NeedInfo</description> <linked-to>terms-and-conditions</linked-to> <advises>order</advises> </advisor>
In the provided example the <advises/> element references the resource on which the advisor should provide additional information on. In cases the advise operation provides information about an issue that can be resolved, like a warning that indicates a validation issue, the optional <linked-to/> element points to another resource which can resolve the issue.
Blocking Advisor
A blocking advisor may enrich the HTTP response of a HTTP GET request on a form in the same manner as an advisor on Read. In addition, the blocking advisor may hide the submit-action link as well as block an actual HTTP POST to the form. If a POST request is performed against a blocked form resource, the form prototype for handling the POST operation is never executed. Instead, a structured error message is returned with the HTTP status code 409.
<advisor> <name>terms-for-order-form</name> <description>Terms and Conditions NeedInfo</description> <linked-to>terms-and-conditions</linked-to> <blocks>order</blocks> </advisor>
Resource Relationships
Relationships (links) between resources are defined as follows:
<relationship> <name>profile-from-root</name> <description>User Profile from root</description> <rel>profile</rel> <from>base.root</from> <to>user-profile</to> </relationship>
Here, we've defined a link from the root resource (base.root) to the user-profile resource, with a rel of "profile".
Out of Family Resources
You may have noticed in the previous example, we referenced the root resource as base.root. This is a fully-qualified reference to a resource, which is required for referencing resources that are not in the same family as the resource you're defining.
In order to reference resources in other families, a Maven dependency needs to be added to bring in the API for the resource:
<dependency> <groupId>com.elasticpath.rest.definitions</groupId> <artifactId>ep-resource-profiles-api</artifactId> <version>${rest.definitions.version}</version> </dependency>
This would bring in the Cortex "profiles" API, which would then allow you to define additional relationships from the profiles resource:
<relationship> <name>bookings-for-profile</name> <description>Link from the profile to the list of bookings for a given user</description> <rel>bookings-for-profile</rel> <from>profiles.profile</from> <to>booking-list</to> </relationship>
Notice that the profile resource in the <from/> element is referred to in its fully-qualified form (profiles.profile).