Announcement: You can find the guides for Commerce 7.5 and later on the new Elastic Path Documentation site. The Developer Center continues to support Commerce 6.13.0 through 7.4.1.Visit new site

Tutorial 8 - Cortex API Implementation Patterns

Tutorial 8 - Cortex API Implementation Patterns

The patterns below are solutions for common problems our customers experience when implementing/customizing their Cortex API. Most resources use a mixture of these patterns, but we have separated them in this document for simplicity.

How can these patterns help you?
  • Takes the guesswork of when/why/where/how to create new resources.
  • Pair your business needs to an established pattern.
  • Get building implementations using existing patterns rather than spending time designing/discovering your own patterns.
  • Understand how the JSON representations and URIs connect to the pattern.

Cortex API Implementation Patterns:

  • Resource Lookup (GET) - Retrieve a related set of data from your backend system through Cortex API.
  • Read From Other (RFO) - Read data from another resource.
  • Link Strategy - Add a link to a resource on another resources' representation.
  • Resource Update - Update a resource's status with data from a client application.
  • Form - Provide customers with the ability to create something from information entered into a form. For example, creating an address for a profile, adding a cart to an order, adding an order to a purchase, searching for items, and so on.
  • Selector - Provide customers with the ability to make selections, such as selecting a billing address to use for an order, the options for an item, the paymentmeans to use for an order, and so on.

Resource Lookup (GET)

The Problem

You need to surface up a related set of data to a client application through the Cortex API.
How do I surface up a single set of related data through Cortex API?
This is the most common customization problem for Cortex API. You have a set of related data you want to surface up to client applications through Cortex API. For example, you have in-store promotions that alternate each day. Your store marketers change the promotions in their backend system and client developers need to display these promotions through their client applications.

If you were customizing another API, you would likely modify an existing resource that's related to promotions in order to surface up this data. However, this is a bad way to go about customizing a product. Elastic Path is continually updating the Cortex API, so if you modify the OOTB source code your Cortex API will break when you upgrade. Also—and this is the main reason—modifying the OOTB code to add some additional functionality to a resource defeats the purpose of Cortex API's design. Cortex API is designed as a set of small independent resources to promote design qualities like cohesion (single responsibility) and to promote extension by composition. These designs help to maintain a clean/clear/consistent design over time as well as minimize the need to make breaking changes to OOTB code.

The Solution: Resource Lookup (GET)

Create a new resource with the Resource Lookup (GET) pattern to retrieve a set of related data from your backend system and surface it through a single resource in Cortex API.

resourceLookup

Resource URI

URIpatternResourceLookUp

Resource JSON Representation

Below is a JSON representation for a resource that uses the Resource Lookup (GET) pattern. The data is sparse in this example, but the idea is that this type of pattern returns a single set of related data. For example, the cart resource uses the Resource Lookup (GET) pattern to surface up cart data in a JSON representation.

Hello World Resource output JSON representation, showing the self, links, and a JSON value. For more information on Cortex API JSON representations, see JSON Objects.
{
  "self": {
    "type": "application/vnd.mycompany.helloworld",
    "uri": "/helloworld",
    "href": "https://localhost:8443/cortex/helloworld",
    "max-age": 0
  },
  "message": "Hello World"
  "links": [],
}

When to Use

You want to surface a related set of data to a client application through a single resource.

Cortex API Resources using this Pattern

* Nearly every resource uses this pattern

Reference Examples

Tutorial 1 - Hello World - Resource returns the string, "Hello World", to the client application using the Resource Lookup (GET) pattern.

Tutorial 3 - CoreLookup - Resource returns the customer's email address from the Commerce Engine using the Resource Lookup

Read From Other (RFO)

The Problem

  • You want to reuse another resource's functionality in your resource.
  • You want a resource to depend on another resource.
  • You want to keep your resources' functionality granular.
How do I reuse an existing resource's functionality in the resource I'm building?

Cortex API's extension design methodology is to create new resources that augments existing behavior, not modify OOTB source code to get the desired behavior. This extension design helps maintain a clean/clear/consistent design over time as well as minimize the need to make breaking changes to OOTB code. OK, you say, but then how do you create a new resource that augments another resource's functionality without changing OOTB code? Skip to the solution below to see.

Another problem you may experience is that you're creating a resource that needs to depend on another resource. Take for instance, the totals resource. Alone, this resource doesn't do anything. It depends on other resources to function. For example, totals uses an RFO to read a carts's lineitems, then calculates the total cost of the items in the cart. How do you build out a resource like this that depends on other resources?

Another common problem you may be facing is how to keep your resource functionality granular. Good API design recommends you create a resource to do one thing, not a hundred different things. But how can you separate functionality when your building resources? Admittedly, it's easier to build out one resource that does everything. Take a look at Digital River's Shopping API: Product Offers Resource. This one resource does it all: add to cart, images, pricing, special product pricing, and product descriptions. Compare it to Cortex API and you see that we have a number of different resource to provide this functionality: items, itemdefinitions, assests, prices, and taxes. How do we keep our resource functionality granular and at the same time utilize all the components together?

The Solution: Read From Other (RFO)

Create a new resource with the RFO pattern to read data from another resource.

readFromOther

With a RFO, you don't need to reinvent the wheel with your resources. The RFO can retrieve data from another resource, so you don't have to build out that functionality.

The RFO pattern can also help keep your resource functionality granular. Take for instance the assets and items resources. The assets resource uses an RFO to read an item, get its ID and scope, then uses those details to retrieve the item's assets (media files) from the back end system. This is apposed to having one resource that does these two separate responsibilities. With granularity like this you can switch out the assets resource for some other system without it affecting the items resource.

Resource URI

URIpatternResourceLookUp

The resource URI, identified at the end of the URI, gets the profiles representation. The extensionprofile resource consumes the profiles representation and then surfaces its representation.

Resource JSON Representation

Below is the JSON representation for the extensionprofile, which uses the RFO pattern. The extensionprofile resource (found in Tutorial 2 - ExtensionProfile) reads the profiles resource's representation and then creates its own representation from the data. In the example below, the family-name and given-name have been read from the profiles resource, added to the extensionprofile's representation, and then surfaced up to the client application along with the profileId. In this way, the profiles' resources functionality has been extending without changing the OOTB code for profiles.

{
    "self": {
         "type": "application/vnd.mycompany.extensionprofile",
         "href": "https://localhost:8443/cortex/extensionprofile/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq",
         "uri": "/extensionprofile/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq","max-age": 0,
    },
    "familyName": "Harris",
    "name": "Oliver",
    "profileId": "gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq",
    "links": [
        {
            "type": "application/vnd.elasticpath.profile",
            "rel": "profile",
            "rev": "extensionprofile",
            "href": "https://localhost:8443/cortex/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq,
            "uri": "/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq"
        }
    ]
}

When to Use

  • Reuse an existing resource's data in your resource - For example, the rates resource uses an RFO to read the items resource's ID and scope to retrieve in order to retrieve the item's cost and billing frequency.

Cortex API Resources using this Pattern

  • assets - Uses and RFO to read an itemdefinition and then surface up the itemdefinition's assets.
  • availabilities - Uses an RFO to read a cart's lineitems and then surface up the lineitems' availability.
  • totals - Uses an RFO to read the items in a carts lineitems and then surfaces up the total cost of the items in the cart.

Reference Example

Tutorial 2 - ExtensionProfile - Read the profiles representation and uses that data to create the ExtenionProfile's representation.

Link Strategy

The Problem

You want to connect the resource you're building with another resource, but using an RFO doesn't make sense.
How do I link the resources I'm building to related OOTB resources or even to my other customized resources?
Say for instance you're building a resource that provides crosscutting functionality to a number of other resources. Using the RFO pattern to read data from other resources and then serving that data up through your single custom resource would ruin Cortex API's single responsibility design. Also, this code would be hard to maintain and upgrade. So how can you add your custom resource's functionality to other resources—both OOTB Resources and custom resources—in a sensible way?

The Solution: Link Strategy

Create a resource that adds a link to itself on another resource's representation.

resourceLookup

Cortex API recommendations resource is a crosscutting resource that provides functionality to the items and navigations resources. The recommendations resource uses a Link Strategy to attach links to the items and navigation resources. Using these links, client applications can follow them to see recommended products for specific items and navigations.

The best part about using a link strategy is that you don't have to modify the resource you're linking to. The links are attached dynamically so the resource being linked to doesn't even know it has a link. This is Cortex API's secret admirer rule. This way you can build out relationships without having to worry about code upgrade paths.

Resource URI

URIpatternLinkStrategy

You'll notice that this looks just like a regular URI to access profiles...and it is! Link strategies don't affect the resource's JSON representation, not the URI.

Resource JSON Representation

Below is the JSON representation for the profiles representation. The extensionprofile resource, found in Tutorial 2 - ExtensionProfile, attaches a link strategy to the profiles resource.
{
    "self": {
        "type": "application/vnd.elasticpath.profile",
        "href": "https://localhost:8443/cortex/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq",
        "uri": "/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq",
    	"max-age": 0
    },
	"family-name": "Harris",
	"given-name": "Oliver",	
	"links": [
        {
            "type": "application/vnd.elasticpath.links",
            "rel": "addresses",
            "rev": "profile",
            "href": "https://localhost:8443/cortex/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq/addresses",
            "uri": "/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq/addresses"
        },
        {
            "type": "application/vnd.elasticpath.links",
            "rel": "paymentmethods",
            "rev": "profile",
            "href": "https://localhost:8443/cortex/paymentmethods/mobee",
            "uri": "/paymentmethods/mobee"
        },
        {
            "type": "application/vnd.mycompany.extensionprofile",
            "rel": "extensionprofile",
            "rev": "profile",
            "href": "https://localhost:8443/cortex/extensionprofile/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq",
            "uri": "/extensionprofile/profiles/mobee/gy3ukmrygbaugljxiu4dmljtgjatgljvhfbdeljwgeyemrrsinatgoceiq"
        },        {
            "type": "application/vnd.elasticpath.links",
            "rel": "purchases",
            "href": "https://localhost:8443/cortex/purchases/mobee",
            "uri": "/purchases/mobee"
    	}
    ]
}

Cortex API Resources using this Pattern

  • lineitems - Uses a link strategy to create a link to the carts' representation.
  • orders - Uses a link strategy to create links to the purchase, carts, deliveries, and billinginfo representations.
  • redommendations - Uses link strategies to attach links to items and navigations.
  • addresses - Uses a link strategy to attach a link to a profile.

When to Use

  • Link resources to other related resources.

Reference Example

Tutorial 2 - ExtensionProfile - Adds a link to the profiles representation and include that data as well as the ExtensionProfile's data in the response representation.

Resource Update

The Problem

You need to update a resource with data from a client application.
How do I update a resource with data from a client application?
Often, client applications need to update a resource's data based on information provided by the client application. Changing an address, password, profile, and so on, are all examples of updating data.

The Solution: Resource Update

Create a resource that updates its state with data from a client application.

Resources can accept PUT requests from client applications and execute write requests to update the data in the backend system.

Resource URI

URIpatternResourceUpdate

The addresses resource accepts the body of the PUT request, a JSON object shown below, and updates the address in the backend system. Notice the <addressid> portion of the URI specifies which address to update.

Resource JSON Representation

Below is the address JSON object that will be sent to the addresses resource.
{
    "address": {
        "country-name": "CA",
        "extended-address": "",
        "locality": "Richmond",
        "postal-code": "V6qE4s",
        "region": "BC",
        "street-address": "14300 Riverport"
    },
    "name": {
        "family-name": "Tiger",
        "given-name": "Tom"
    }
}

Cortex API Resources using this Pattern

  • lineitems - accepts a PUT request to update the quantity of items in the lineitem.
  • profiles - accepts a PUT request to update the customer's profile data.
  • addresses - accepts a PUT request to update an address's details.

When to Use

You want to update a resources state with data from the client application.

Reference Example

Look at lineitems, profiles, and the addresses resources.

Form

The Problem

You need a way for client applications to create data in Cortex API.

How do I create data in the Cortex API?
A common problem is enabling client applications to create data in Cortex API. For example, creating a new customer, a new address, a new paymentmethod, and so on. Also, when you expose a capability like creating data in the API, how do you define what data is necessary for your resource to create it? For example, say you want to expose the ability to create a new user in your system. How do you identify what data customers need to fill out in order to create this new customer? Or, say for example you want to expose the ability to create a new address for a customer. How do you identify what the address requirements are?

The Solution: Form

Create a resource with a form to provide customers with the ability to create something in the Cortex API from the data they've entered in a form.

resourceLookup

Cortex API uses forms to create data. For example, creating an address for a profile, creating a new customer, adding a cart to an order, adding an order to a purchase, searching for items, and so on all use forms. Client Applications GET the form, fill out the form's details based of customer input, and then POST the filled out form to the form's actionlink to create the data. See Forms for more information on OOTB forms.

Resource URI

URIpatternResourceUpdate

The form identifier is a Cortex API standard used to indicate a form returns from the request.

Resource JSON Representation

Below is the addresses form JSON representation, containing the action link to POST the form to.
{
    "self": {
        "type": "application/vnd.elasticpath.address",
        "uri": "/profiles/<scope>/<profileid>/addresses/form",
        "href": "http://www.onlinestore.com/profiles/<scope>/<profileid>/addresses/form",       
        "max-age": 0
    },
    "links" [
        {
            "rel": "createddressaction",
            "href": "http://www.onlinestore.com/profiles/<scope>/<profileid>/addresses",
            "uri": "/profiles/<scope>/<profileid>/addresses"
        }
    ],
    "address": {
        "country-name": "",
        "extended-address": "",
        "locality": "",
        "postal-code": "",
        "region": "",
        "street-address": ""
    },
    "name": {
        "family-name": "",
        "given-name": ""
    }
}

Cortex API Resources using this Pattern

  • address - returns a form to create a new address for a customer.
  • orders - returns a form to submit the order to a purchase
  • search - returns a form to submit the search keyword to the search resource.
  • registration - returns a form to submit to the registration resource to create a new customer.
  • profiles - returns an email form allowing customers to create emails for their profile.

When to Use

You need a customer's input to perform an action such as creating a new customer, making a purchase, creating a billing address, adding a credit card to their payment, performing a search, and so on.

Reference Example

Tutorial 4 - Stop Condition - Returns a form with an action link to enable the client application to "agree" to the terms and conditions.

Selector

The Problem

You need to provide a way for customers to make selections in the Cortex API. For example, say you have an item in your storefront, such as an iPhone that comes in red, blue, or green, and you want to allow customers to pick the color. Or, say you have a number of shipping options, like FedEx, Canada Post, or Purolator, and you want to allow a customer to select one to use for an order.
How do I allow customers to make choices through the Cortex API?  

The Solution: Selector

Create a resource with a Selector to provide customers with the ability to make selections, such as choosing a billing address, shipping option, a payment method, item options, and so on.

resourceLookup

Cortex API uses selectors

Resource URI

URIpatternResourceUpdate

The selector identifier is a Cortex API standard used to indicate a selector returns from the request.

Resource JSON Representation

Below is the JSON destinationinfo selector. Customers GET their choice, then post to the choice's selectaction rel to make the selection.
{
	"self": {
	"type": "application/vnd.elasticpath.selector",
	"uri": "/orders/<scope>/<orderID>/deliveries/<deliveryID>/destinationinfo/selector",
	"href": "www.onlinstore.com/orders/<scope>/<orderID>/deliveries/<deliveryID>/destinationinfo/selector",
	"max-age": 0
  },
	"links": [ {
	"type": "application/vnd.elasticpath.links",
	"rel": "chosen",
	"rev": "selector",
	"href": "www.onlinstore.com/orders/<scope>/<orderID>/deliveries/<deliveryID>/destinationinfo/selector/profiles/<scope>/<profileID>/addresses/<addresseID>",
	"uri": "/orders/<scope>/<orderID>/deliveries/<deliveryID>/destinationinfo/selector/profiles/<scope>/<profileID>/addresses/<addresseID>"
}, {
	"type": "application/vnd.elasticpath.links",
	"rel": "choice",
	"rev": "selector",
	"href": "www.onlinstore.com/orders/<scope>/<orderID>/deliveries/<deliveryID>/destinationinfo/selector/profiles/<scope>/<profileID>/addresses/<addresseID>",
	"uri": "/orders/<scope>/<orderID>/deliveries/<deliveryID>/destinationinfo/selector/profiles/<scope>/<profileID>/addresses/<addresseID>"
}, {
	"type": "application/vnd.elasticpath.info",
	"rel": "destinationinfo",
	"rev": "selector",
	"href": "www.onlinstore.com/orders/<scope>/<orderID>/deliveries/<deliveryID>/destinationinfo",
	"uri": "/orders/<scope>/<orderID>/deliveries/<deliveryID>/destinationinfo"
} ],
	"name": "destination-selector",
	"selection-rule": "1"
}

Cortex API Resources using this Pattern

  • itemselections - provides a selector to select item options.
  • shipmentdetails - provides a selector to select the orders' shipping option (i.e. Canada Post, FedEx, and so on) and a selector to select the destination address.
  • orders - provides a selector to select the order's billing address.
  • paymentmethods - provides a selector to select the payment method to use for the purchase.

When to Use

You want to provide customers with the ability to make selections, such as select an item's options, the orders' billing addresses, shipping addresses, and paymentmeans.

Reference Example

shipmentdetails resource - provides two selectors: one to select the orders' shipping option and another to select the destination address.