Codecs implement a common interface defined by the class CommerceCodec
, with additional static information defined in CommerceCodecType
. This document will explain the data types that commerce codec methods can return, the methods that need to be implemented, and how edge cases should be dealt with.
Both ID and name are core to all types, and must be present in your converted data. The name can also be thought of as the label.
Some types also have a slug
, such as categories. This is typically present when the ID is a random string, and the resource needs a more memorable identifier. One example would be a product category - its ID could be a GUID, but its slug could be the human readable string new_arrivals
.
/**
* Base resource type with identifiable ID and Name.
*/
export type Identifiable = {
id: string
name: string
}
/**
* Commerce Object with a slug
*/
export type CommerceObject = Identifiable & {
slug: string
}
Customer groups are used for personalisation. An example use case would be setting a banner ad to appear for different age groups. Generally, we just want to return all existing group ids and names, so that they can be displayed as options in a selector.
/**
* Customer Group
*/
export type CustomerGroup = Identifiable & {
// id: string (from Identifiable)
// name: string (from Identifiable)
}
- On platforms where data we expect to be found in the variant is instead found on the product, duplicate it across all variants.
- On platforms without variants, just return one variant.
- You might have to do additional requests to fill out all required information in product variants.
- Categories and variant lists are mandatory.
parent
,products
andchildren
do not need to be fully hydrated on linked categories.
/**
* Product with descriptions, images, categories and variants.
*/
export type Product = CommerceObject & {
// id: string (from Identifiable)
// name: string (from Identifiable)
// slug: string (from CommerceObject)
shortDescription?: string
longDescription?: string
imageSetId?: string
categories: Category[]
variants: Variant[]
}
Represents a category of products, with identifiers, an image, tree structure (parent+child) and optionally products.
- Category slug is used to fetch products by category. It is intended to be a user readable ID that you might find in a URL.
products
does not need to be hydrated unless the user specifically requests the category.showInMenu
is if the commerce vendor has a visible flag for a category. If not then default to true.
/**
* Category with images, products, children and a parent.
*/
export type Category = CommerceObject & {
// id: string (from Identifiable)
// name: string (from Identifiable)
// slug: string (from CommerceObject)
parent?: Category
image?: Image
children: Category[]
products: Product[]
showInMenu: boolean
}
Variants are versions of a product with unique sku, price and image.
- ID should be uniquely identifying. Can be equal to SKU, if the platform doesn't have a separate ID.
- SKU and prices must be defined, and appropriately localized. An empty string SKU is allowed, where the ID should be used as the identifier.
- Attributes include any other generic data associated with the variant.
- Ideally a variant should include images with public URL and thumb.
/**
* Variant identified by SKU, with price, images and attributes.
*/
export type Variant = {
id: string
sku: string
listPrice: string
salePrice: string
defaultImage?: Image
images: Image[]
attributes: Dictionary<string>
}
/**
* Simple image type with an URL and thumbnail URL.
*/
export type Image = {
url: string
thumb?: string
}
Promotions are currently not used.
/**
* Promotion with description, code, an image and activity status.
*/
export type Promotion = Identifiable & {
// id: string (from Identifiable)
// name: string (from Identifiable)
description: string
promoCode?: string
isActive: boolean
image?: Image
}
Parameters for method supporting Pagination
/**
* Method arguments for pagination. These are also returned with paginated results, and should be used when requesting future pages.
*
* If the pageNum is undefined, it will be 0.
* If the cursor is undefined, the desired page number will still be fetched but this cursor will be used to fetch it faster.
* If the cursorPage is undefined, cursor cannot be used and will be treated as undefined.
* If pageSize is undefined, it will select a default value.
* If pageCount is undefined, all items will be fetched.
*
* The following fields are only returned by the request:
* Total may be undefined. It is always defined if the requested page is the last.
*/
export type PaginationArgs = {
pageNum?: number
cursor?: string
cursorPage?: number
pageSize?: number
pageCount?: number
total?: number
}
Get a single product by ID. This method calls getProducts internally.
- Product does not exist:
- It will receive undefined from getProducts, this will pass undefined as a result.
Get multiple products by ID. Returned data must be in the same order as the request. Missing products must return undefined entries in the list, so that the length of the request and response lists are identical even when assets are missing.
- One product does not exist:
- In the list of returned products, missing IDs correspond to undefined.
- All products do not exist:
- Return a list of all undefined.
Get multiple products by keyword.
This endpoint supports pagination. See pagination.ts for helpful code and Pagination for docs.
- Vendors that don't support keyword filtering should implement it by fetching all products and filtering them in the codec.
Get multiple products by category.
This endpoint supports pagination. See pagination.ts for helpful code and Pagination for docs.
- Category does not exist:
- Must return []. Only getCategory should throw.
Get products by ID, without any conversion from the source format.
- Same as GetProducts, order must be preserved.
Get a category by slug. This must hydrate all fields in the requested category, including products. For an unhydrated category, look to getCategoryTree.
- Category does not exist:
- Throw a CodecError (NotFound)
Get a list of root level categories. Sub-categories should be contained in children as a tree, should not appear at root level.
- If there is no tree of categories, just list all categories.
- If there are no categories at all, it is valid to return an empty array.
Get a list of customer groups.
- When no customer groups are present, or the backend does not support listing customer groups, it should just return [].
- API error:
- When vendors return an error that we don't understand, it should throw a CodecError with
CodecErrorType.ApiError
, and provide the status and message returned by the API as info. The helper methodcatchAxiosErrors
can provide this andNotFound
type errors automatically.
- When vendors return an error that we don't understand, it should throw a CodecError with
- Not authenticated:
- Vendors which use OAuth should throw an appropriate CodecError if authentication fails for some reason. The default oauth client does this already.
- Not supported by vendor:
- Some vendors do not support all methods. If this is the case, throw a CodecError with
CodecErrorType.NotSupported
.
- Some vendors do not support all methods. If this is the case, throw a CodecError with