Resource Classes and Annotations
Resource Classes and Annotations
This section provides an overview of general Cortex concepts, including what the core resource operations are used for and what an api developer might want to achieve using these tools.
Further information on Cortex packages and classes can be found in the javadocs.
Resources
ResourceOperator
REST services are defined in Cortex by implementing the marker interface ResourceOperator
ResourceOperator methods handling a REST request must be annotated with both @Path and @OperationType and must return an OperationResult.
Cortex injects values into the parameters of each ResourceOperator method based on the type of the parameter and the method's annotations. An exhaustive list of annotations is available in the javadocs for the annotation package.
An example resource operator:
import com.elasticpath.rest.OperationResult; import com.elasticpath.rest.resource.dispatch.operator.ResourceOperator; import com.elasticpath.rest.resource.dispatch.operator.annotation.OperationType; import com.elasticpath.rest.resource.dispatch.operator.annotation.Path; @Path("/commerce-legacy/examples") public class SimpleResourceExample implements ResourceOperator { @Path @OperationType(Operation.READ) public OperationResult processRead() { return OperationResult.Builder.builder() .build(); } }
Operation Type
The @OperationType annotation indicates which of the CRUD verbs (CREATE, READ, UPDATE, DELETE) a ResourceOperator method responds to.
READ
Use READ to retrieve a resource from the requested uri. The OperationResult returned by READ includes a ResourceState that contains the resource entity to retrieve.
In the following READ method, a resource, which is identified by @ResourceId, is retrieved from a persistence engine (represented by exampleLookup).
@Path({"/commerce-legacy/examples", ResourceId.PATH_PART}) @OperationType(Operation.READ) public OperationResult processRead(@ResourceId String exampleId) { // Retrieve data from some backend service ExampleEntity exampleEntity = exampleLookup.getExample(exampleId); // Create the resource state ResourceState<ExampleEntity> exampleState = ResourceState.Builder.create() .withEntity(exampleEntity) .build(); // Create the operation result return OperationResult.Builder.builder() .withRepresentation(exampleState) //Setting the resourceState response .withResourceStatus(ResourceStatus.READ_OK) //The operation was successful (200) .build(); }
CREATE
Use CREATE to create a new resource on the server at the requested uri. The ResourceOperation parameter given to a CREATE method contains the Java representation of the entity to be created, as in the following example.
@Path("/commerce-legacy/examples/") @OperationType(Operation.CREATE) public OperationResult processCreate(ResourceOperation operation) { // Get the resource state from the request, and adapt its embedded entity to the type expected from the request ExampleEntity exampleEntity = TypeBuilderFactory.adaptResourceEntity( ((ResourceState) operation.getRepresentation()).getEntity(), ExampleEntity.class ); //Presently there is no auto-injection of POSTed entities so this must be done manually // persist exampleEntity // Create the operation result return OperationResult.Builder.builder() //No resourceState was added to this result .withResourceStatus(ResourceStatus.CREATE_OK) .build(); }
OperationResult
OperationResults indicate to Cortex what ResourceState is being returned and whether the operation was successful or not. In addition to the HTTP status code, OperationResults can also return an error message describing why the operation was unsuccessful.
Create OperationResults with the builder method OperationResult.Builder.builder().
Path
The @Path annotation specifies the uri that each method responds to. The uri for a specific method is derived from the @Path annotation of the class combined with the @Path of the method. For more details on @Path, see the @Path JavaDoc.
ResourceState
The ResourceState wraps a resource entity and provides readonly access to the entity's metadata such as the Self uri.
Create ResourceStates with the builder method ResourceState.Builder.create()
Id Encoding
Cortex identifies entities such as orders, customers, items, searches, slots, navigations, and so on with IDs. To uniquely identify each domain object, the Elastic Path Commerce Engine assigns each object a Globally Unique IDentifier (GUID). Cortex provides a Base32Util utility for converting the GUIDs used by the Elastic Path Commerce Engine and to the encoded ids used in Cortex.
- GUIDs may contain uri incompatible characters
- GUIDs are tightly coupled with Elastic Path Commerce Engine domain objects
Linking Resources
ResourceStateLinkHandler
Create links between resources by implementing a ResourceStateLinkHandler. ResourceStateLinkHandler is a generic interface which should be typed to the resource you wish to link to. ResourceStateLinkHandler has one method, getLinks(). The getLinks() method receives a ResourceState that provides the meta data required to build the desired links, such as an item's id, and returns 0-many ResourceLinks in an iterable collection.
For example, to add links to item resources:
/** * Adds a link to all ItemEntity objects returned by READ requests. */ public class CartToItemLinkHandler implements ResourceStateLinkHandler<ItemEntity> { public Iterable<ResourceLink> getLinks(ResourceState<ItemEntity>) { //method content returning links } }
ResourceLink
A ResourceLink represents a link to another resource. ResourceLinks are contained in ResourceStateLinkHandlers.
A resource being linked to does not need to know about the resource linking to it. For instance, in Writing Your First Resource, the Orders resource does not know about the Terms resource linking to it. This rule simplifies Cortex extension. When you add a new resource, you don't need to update all the existing resources to b aware of the new resource.
Create ResourceLinks with the builder method ResourceLink.Builder.builder(), similar to the following example:
ResourceLink.Builder.builder() .withRel("item") .withType(ItemMediaTypes.ITEM.id()) .withUri("/commerce-legacy/sampleCartUri") .build();
The MediaType is required by the link to define the type of the resource being linked to.
MediaType
A MediaType identifies each resource by type and helps in deserializing a resource back into an object. Media types are also used when defining a link between resources, as seen in ResourceLink and ResourceStateLinkHandler. Media types are created by the api-generator-maven-plugin and take the form elasticpath.ResourceFamilyName.ResourceEntityName. For example, an items resource will have the MediaType elasticpath.items.item.
Reading from Another Resource
To read an entity from another resource, use the @ResourceUri annotation on a parameter of a resource operator method.
For example, a LineItem might need information about its enclosing Cart, so the LineItem would perform a READ operation on the Cart to retrieve Cart information. When reading from another resource, the uri of the other resource must be appended to the end of the resource's uri. In this example, a separate READ request will retrieve the resource at /other/uri, and inject the retrieved entity into the annotated otherState parameter.
@Path({"/commerce-legacy/example", "/commerce-legacy/other/uri}) @OperationType(READ) public void exampleReadMethod(@ResourceUri ResourceState<OtherEntity> otherState) { //method body }
Generating Resource API Projects Using the API Generator Maven Plugin
The generate-sources plugin goal of the api-generator-maven-plugin generates the java source corresponding to entity definitions. The following example demonstrates the api-generator-maven-plugin configuration required for producing a resource API definitions jar in the process-resources phase of the Maven life cycle.
<plugin> <groupId>com.elasticpath.rest.definitions</groupId> <artifactId>api-generator-maven-plugin</artifactId> <executions> <execution> <phase>process-resources</phase> <goals> <goal>generate-sources</goal> </goals> </execution> </executions> </plugin>