TMForum provides TMF630 - REST API Design Guidelines as means to provide holistic design patterns that are common across all TMForum REST APIs. This document aims to provide guidance on how Broadleaf has approached these topics and what strategies, assumptions, and opinionated interpretations have been taken in implementing the various TMForum Open APIs. Beyond the concerns outlined in TMF630, this document will also cover any other cross-cutting concepts/patterns that are part of Broadleaf’s TMF strategy.
In standard Broadleaf, the APIs normally expect certain proprietary information in order to fulfill a request. For example, we normally expect API consumers to provide a Context Request header that specifies a Broadleaf Catalog ID, a Broadleaf Application ID, a Broadleaf Tenant ID, and so forth. These concepts are important to how data is organized by the system.
However, naturally, TMForum API callers will not know about these proprietary concepts because they are not part of the TMF API specifications. To solve this problem, we have introduced a new concept called a 'TMF API Context'. The TMF API Context concept serves as an intermediary that can provide this proprietary information by default on each request. TMF API consumers are therefore not required to know about Broadleaf’s proprietary concepts and can use the standard TMF API contracts as defined by the OpenAPI specification.
Basically, an admin user can create a new TMF API Context and associate it to proprietary concepts like tenant, catalog, and application. Then, the admin user will assign an Authorized Client to have access to this TMF API Context ID. When the client goes to make API calls, it will prefix the base TMF API URL with the API Context ID. At the time a request comes in, the backend will use that ID to expand the API Context’s details to resolve the Broadleaf tenant, catalog, and application that the request should be performed in.
In the Broadleaf admin, visit the 'Tenant Management' > 'TMForum API Context' page to manage API Contexts
Create a new API context, specifying details like which catalog, application, and/or sandbox that requests made from this context should operate in. Submit.
After creation, you will also be able to specify additional custom attributes on this API Context.
There is a lot of flexibility with what you can do with this, but the main idea is to use this feature to avoid requiring TMF API callers provide custom fields in request payloads to achieve a certain goal.
For example, if this API Context will be used to manage ProductStock
, you can specify the default Broadleaf Inventory Location that ProductStock
should be created in by setting an attribute value for defaultInventoryLocationContextId
to the Inventory Location ID.
As noted in the TMF 687 implementation documentation, com.broadleafcommerce.tmforum.inventory.tmf687.service.apicontext.InventoryCommonTMFApiContextKeys
knows about the attribute key defaultInventoryLocationContextId
and will check/use it to process requests.
Once the API Context is established, select and copy the API Context ID from the admin page URL.
Navigate to the 'Security' > 'Authorization Servers' page in the admin and find the Authorized Client that you wish to grant access to this API Context.
In the Authorized Client edit form, under 'Advanced', you will see a 'Custom Attributes' field.
Create a new custom attribute called TMF_API_CONTEXTS
, and set its value to the API Context ID copied earlier.
Save the changes on the client.
The end result of this change is that the ClientTMFApiContextTokenEnhancer
will read this attribute and populate the TMF_API_CONTEXTS
claim on all access tokens issued for this client.
When a resource tier service processes a TMF API request, the TMFApiContextHandlerMethodArgumentResolver
will verify the requested API Context matches an allowed value in the access token.
This is important from a security perspective, as it ensures only clients that have been authorized to use a particular API context can do so.
It’s important to note that even after the client is assigned to an API context, they still need to be explicitly assigned the permissions for any endpoints they are trying to access.
For example, the client will not have access to the GET ProductOffering endpoint unless they have the TMF_PRODUCT_OFFERING
scope and READ_TMF_PRODUCT_OFFERING
permission explicitly granted to them.
Be sure to assign all relevant scopes/permissions that the client will need for the resources they will manage.
At this point, the admin setup is complete.
Any requests made by the AuthorizedClient to TMF APIs should be prefixed with the API Context ID (ex: /{apiContextId}/productCatalogManagement/v5/productOffering
)
The AuthorizedClient should use the standard OAuth2 flows as normal to obtain access tokens, and then provide them via Authorization
headers in each TMF API request
In each service that contains TMF API endpoints, the TMFApiContextHandlerMethodArgumentResolver
engages to resolve the API Context ID that was requested in the URL.
This involves making a REST API call to TenantServices to retrieve the API Context.
This call is performed with the tmfcoreclient
service-to-service AuthorizedClient, which each relevant service is given the authentication details for.
For performance, this API call to retrieve the API Context is cached - please see TMForumCoreCacheAutoConfiguration
and TMForumCoreCacheProperties
for more details.
id
and href
Field ValuesSupport: In compliance with TMF630 version 4.2.0 part 1 section 2.3, the id
and href
attributes (common to many schemas) will always be returned in responses.
Note that href
is not a mutable or persisted attribute, but rather a dynamically generated value on reads.
TMF630 version 4.2.0 part 1 section 4.3 discusses Query partial Resource representation or attribute selection
as the ability to select a subset of the attributes of an entity to be present in the returned representation.
This is useful if you only care about certain fields and don’t want everything in the response.
Per the guidelines:
Attribute selection MUST be enabled on all first level attributes but not on inner classes.
Attribute selection MAY optionally be enabled on all attributes and inner classes.
Selection is based on a fields
query parameter of the following form:
GET {apiRoot}/{resourceName}/{resourceID}?fields=\{attributeName*}
TMF APIs typically support this concept on GET
requests, but there are cases where POST
and PATCH
also support this behavior.
Furthermore, id
, href
, and (in the case of v5
APIs) @type
fields are required to always be immune to attribute selection and must always be returned.
Support: Broadleaf TMForum APIs currently support attribute selection on all first-level attributes only.
Details: Broadleaf TMForum APIs have introduced a few components and strategies to help facilitate this:
AttributeSelectionUtility
provides centralized methods for endpoints to quickly parse the fields request parameter and build Jackson SimpleFilterProvider
instances that filter out all but those keys in the result
JacksonAnnotatingMixinModule
provides a way to avoid directly annotating classes with Jackson-specific annotations (such as @JsonFilter
) by deferring to a bean-based mixin-applying approach, which is also much more flexible and overridable by clients.
This component delegates to JacksonAnnotationMixinMapping
beans implemented for each resource class to provide the individualized configuration.
TMF630 version 4.2.0 part 1 section 4.4 discusses Query Resources with attribute filtering
as the ability to retrieve resources using an attribute filtering mechanism.
This filtering is based on using name-value query parameters on entity attributes of the following form:
GET \{apiRoot} /\{resourceName}?[\{attributeName}=\{attributeValue}&*]
Support: Broadleaf TMForum API’s currently support simple (e.g. fieldName=someValue
) equality filters that are AND
-ed together (in the case of multiple fields).
Each resource supports filtration on different fields based on what the domain can support.
Details: Broadleaf TMForum APIs have introduced a few components to help facilitate this:
AttributeFiltersHandlerMethodArgumentResolver
: allows endpoint methods to just define an AttributeFilters
method parameter which will automatically parse and resolve attribute filtration parameter values based on the resolver provided in a @AttributeFiltersResolution
annotation
AttributeFiltersRequestResolver
: an interface to allow different implementations of resolution logic as needed
AbstractAttributeFiltersRequestResolver
: serves as a common starting point for resolver implementations that are just based on the field names of a specified entity being filtered.
This component allows whitelisting/blacklisting of certain fields as supported/unsupported for filtration.
AttributeFiltersRsqlConversionUtility
: Responsible for translating the simple equality filters from TMF into RSQL filters, which Broadleaf internally uses when there is a need to specify arbitrary additional filters on a request.
Note - often, there will be a RsqlQueryTransformer
(or equivalent) implementation registered for each TMF domain to subsequently translate filters from targeting the TMF fields to targeting the BLC-expected fields (particularly if there is a name or type mismatch).
TMF630 version 4.2.0 part 1 section 4.5 discusses Query Resources with Iterators
as the ability to return large collections in a GET
request with pagination.
For query based pagination, the following query parameters are used:
offset
: Requested index for start of resources to be provided in response requested by client
limit
: Requested number of resources to be provided in response requested by client
Support: Broadleaf TMForum APIs currently support TMForum query-based pagination using offset
and limit
query parameters.
Responses will have the 206
status code as well as an appropriate X-Total-Count
/Link
response header.
Details: Broadleaf TMForum APIs have introduced a few components to help facilitate this:
TMFPageable
: an interface and implementation that extends Spring’s default Pageable
interface. Represents a Pageable
matching the parameters specified for TMF-standard pagination.
Note
|
The default implementation is DefaultTMFPageable . As expected by TMF, this is an offset-based Pageable and therefore does not support page numbering.
Despite this, internally, the TMFPageable interface does not extend Broadleaf’s UnnumberedPageable interface.
This is because UnnumberedPageable implementations go through special flows during context narrowing which TMFPageable is expected to be excluded from.
|
TMFPageableHandlerMethodArgumentResolver
: Allows endpoint methods to just define a TMFPageable
method parameter which will automatically be resolved from paging request parameter values, including defaults for unspecified parameters.
At the framework level, Broadleaf supports 'total count' queries only on domains that are not sandbox or catalog discriminated.
If a domain is not sandbox or catalog discriminated, then the paginated response will contain an X-Total-Count
header describing the total number of available results.
This can be used by the TMF API caller to calculate the next page offset.
If a domain is sandbox or catalog discriminated, then total count will not be available.
Typically, such domains are paginated using a proprietary underlyingPageSize
concept, because the internal number of results to skip over to get to the next page may not match the 'actual' number of results in the current page.
To communicate the appropriate next offset to the API caller, requests for these domains will instead include the TMF-recommended Link
header, which will contain a 'next' URI value with pre-filled offset/limit parameters to obtain the next page (if available).
TMF630 version 4.2.0 part 1 section 4.7 discusses Sorting
as the ability to support a sort directive using query parameters.
The following parameters MUST be supported:
Sort-Query-Parameters : “sort”, “=”, (Sort-Direction), Sort-Field
Sort-Direction : “-“ | “+”
Sort-Field: The field to sort on.
Support: Broadleaf TMForum APIs currently support TMForum’s sort directives using query parameters. Each resource supports sorting on different fields based on what the domain can support.
Details: Broadleaf TMForum APIs have introduced a few components to help facilitate this:
TMFSortHandlerMethodArgumentResolver
an implementation of Spring’s HandlerMethodArgumentResolver
and extension of Spring’s default SortHandlerMethodArgumentResolverSupport
.
This component is used to resolve the TMF-standardized sort parameter syntax.
This is internally used by TMFPageableHandlerMethodArgumentResolver
during TMFPageable
resolution to resolve and set the Sort on the final TMFPageable
Note - often, there will be a SortTransformer
(or equivalent) implementation registered for each TMF domain to subsequently translate sort requests from targeting the TMF fields to targeting the BLC-expected fields (particularly if there is a name mismatch).
There are certain schemas for which Broadleaf supports out-of-box polymorphic deserialization, where the @type
field in an object can drive which specific class the object is resolved to.
CharacteristicValueSpecification
The TMF CharacteristicValueSpecification
schema has a wide variety of subtypes, such as StringCharacteristicValueSpecification
, BooleanCharacteristicValueSpecification
, etc.
The com.broadleafcommerce.tmforum.core.jackson.deserialization.characteristic.PolymorphicCharacteristicValueSpecificationDeserializer
is a Jackson JsonDeserializer
capable of deserializing an input JSON to the right concrete type.
To achieve this, it delegates to com.broadleafcommerce.tmforum.core.jackson.deserialization.characteristic.CharacteristicValueSpecificationDeserializationHandler
beans defined in the Spring context which use either @type
or valueType
to determine the target type.
Ultimately, the expectation is for mixins (registered via JacksonAnnotationMixinMapping
) to invoke this deserializer via @JsonDeserialize
if they have a field of type CharacteristicValueSpecification
.
ProductOfferingPriceRefOrValue
The TMF ProductOfferingPriceRefOrValue
schema can be either a ProductOfferingPrice
or a ProductOfferingPriceRef
.
The com.broadleafcommerce.tmforum.core.jackson.deserialization.offering.PolymorphicProductOfferingPriceRefOrValueDeserializer
is a Jackson JsonDeserializer
capable of deserializing an input JSON to the right concrete type.
It will use the @type
value from the input to determine the target type.
Ultimately, the expectation is for mixins (registered via JacksonAnnotationMixinMapping
) to invoke this deserializer via @JsonDeserialize
if they have a field of type ProductOfferingPriceRefOrValue
.