Resource Identifiers
A resource identifier is a class which represents the URI for a specific resource. Resource identifiers take the <uri-part/>
element in a resource definition and convert them to Java types which are then used in prototype classes.
Resource identifier classes ensure type safety, and allow you to avoid constructing URIs manually. They provide Builder
classes to build URIs accurately as needed, and @Inject
annotations to inject those URIs into prototypes. These Builder
classes also perform runtime validation, ensuring that all required components are present.
For certain API modeling patterns, Helix programming model resources also perform validation on identifier components to ensure that, for example, the caller has access to all referenced resources.
Simple Identifiers
Consider the following resource definition:
<name>carts</name>
<description>Family for carts</description>
<uri-part>
<name>cart-id</name>
<description>The cart identifier.</description>
<string/>
</uri-part>
<resource>
<name>cart</name>
<description>A cart resource. It can have line items, orders and totals.</description>
<uri>/{base.family}/{base.scope}/{cart-id}</uri>
<entity>cart</entity>
</resource>
The URI for the cart
resource is /carts/{base.scope}/{cart-id}
. The corresponding resource identifier class is CartIdentifier
, which is actually an interface extending ResourceIdentifier
. The interface includes a getCartId()
method:
@Property(name = CART_ID)
IdentifierPart<String> getCartId();
It also contains a generated Builder which is used to construct instances of the identifier:
CartIdentifier myNewIdentifier = CartIdentifier.builder()
.withCartId(StringIdentifier.of("some-id"))
.build();
The URI-part can be injected into prototype instances using the @Inject
annotation.
To @Inject
the cart-id
URI-part, use the following method signature:
@Inject
@UriPart(CartIdentifier.CART_ID)
private IdentifierPart<String> cartId;
The entire resource identifier, including the the URI-part, can also be injected into prototype instances using the @Inject annotation in the method signature:
@Inject
@RequestIdentifier
private CartIdentifier cartIdentifier;
Composite Identifiers
Resource identifiers can also be "composed" of other resource identifiers (which, in turn, may be "composed" of other resource identifiers).
Consider the following resource definition:
<name>listcreate</name>
<description>Family for list create</description>
<uri-part>
<name>line-item-id</name>
<description>The line item identifier. </description>
<string/>
</uri-part>
<resource>
<name>line-items</name>
<description>The line items list in a cart.</description>
<uri>{cart}/lineitems</uri>
<list-of>line-item</list-of>
</resource>
<resource>
<name>line-item</name>
<description>An individual line item in a cart.</description>
<uri>{line-items}/{line-item-id}</uri>
<entity>line-item</entity>
</resource>
The URIs of both line-items
and line-item
resources are a composite identifier. The {cart}
token contained within the URI of the line-items
resource is itself the full identifier of the cart
resource, and the {line-items}
token contained within the URI of the line-item
resource is the full identifier of the line-items
resource.
note
The code-generation tooling will validate your <uri/>
elements to ensure that you are assembling your composite URIs correctly.
Examining the generated LineItemIdentifier
interface, you’ll find an accessor method for obtaining LineItemsIdentifier
:
@Property(name = LINE_ITEMS)
LineItemsIdentifier getLineItems();
There’s also an accessor method for obtaining IdentifierPart
:
@Property(name = LINE_ITEM_ID)
IdentifierPart<String> getLineItemId();
Composite resource identifiers can be constructed using the generated Builder
classes. Builder
classes are obtained by calling the static builder()
method on the generated Identifier
, just as simple identifiers can be constructed:
LineItemIdentifier lineItemIdentifier = LineItemIdentifier.builder()
.withLineItems(LineItemsIdentifier.builder().build())
.withLineItemId(StringIdentifier.of("some-id") .build();
Helix decomposes the resource URI into a composite identifier, and verifies that the caller has access to all of the referenced resources. In the case of line-items
, it verifies that the caller has access to /{base.family}/{base.scope}/{cart-id}
. If the caller does not have the necessary access, the operation is rejected.