Best practices

Learn how to implement advanced features like public sharing, specific user sharing, and lifecycle management using Custom Fields and API actions.

After completing this page, you should be able to:

  • Define Custom Types with appropriate resourceTypeIds (such as shopping-list, line-item) and add Custom Fields (such as Boolean or Set of String) to extend Shopping List data models.
  • Implement a secure public sharing mechanism using a shareable identifier (slug or key) and an explicit Custom Field of type Boolean (for example, isPublic) for access control.
  • Implement sharing with specific users by using a Set Custom Field (for example, sharedWith).
  • Configure automatic list deletion using the setDeleteDaysAfterLastModification setting.

Let’s explore how to leverage Composable Commerce Shopping Lists, particularly Custom Fields, to build advanced functionality like public sharing (for wishlists or gift registries), manage list lifecycles, and implement related features.

While Composable Commerce provides flexible base Shopping List functionality, features like publicly sharing a list or building a full gift registry require custom implementation. We'll focus on the core mechanisms using Custom Fields.

Foundation: Understanding Custom Fields and Types

Before extending Shopping Lists, it's essential to understand Custom Fields and Types in Composable Commerce.

  • Custom Fields: Allow you to add your project-specific data to standard Composable Commerce resources.
  • Types: Define the structure (schema) of your Custom Fields. A Type specifies the field names, data types (String, Boolean, or Set), labels, and the resources it applies to.
  • Resource Association (resourceTypeIds): When creating a Type, the resourceTypeIds property determines which Composable Commerce resources can use the custom fields defined in that Type. To add custom fields directly to a Shopping List, the Type must include "shopping-list" in its resourceTypeIds. Similarly, "line-item" or "text-line-item" can be used for fields on items within the list.
You must define a Type before applying custom fields. This involves specifying a key, name, the resourceTypeIds, and the definitions of the fields you want to add (like the isPublic field discussed next). This is typically done via the Composable Commerce API or SDKs.

Implementing public sharing for Shopping Lists

To allow users to share their Shopping Lists via a public URL (like a wishlist or gift registry), you need two main components: a public identifier and an access control mechanism.

The shareable identifier: slug or key

  • Each Shopping List has unique identifiers:
    • key: Developer-defined, unique string.
    • slug: Localized, potentially more user-friendly string often derived from the list name.
  • Use either the slug or key in your application's URL structure.
  • Recommendation: Use the slug for cleaner, more readable URLs (for example, yourshop.com/wishlist/john-doe-birthday-wishlist).
  • Example URL Structure:
    • https://yourshop.com/shared-list/{slug}
    • https://yourshop.com/shared-list/{key}

Access control: The isPublic Custom Field

Crucially, you need explicit control over which lists are public. Never assume a list is public by default.
  • Mechanism: Define a Boolean Custom Field (for example, named isPublic) on the shopping-list resource type using a Custom Type (as described in Section 1).
  • Purpose: This field acts as a flag. Only lists where this flag is explicitly set to true should be considered publicly accessible via the shareable URL.
  • Default State: If the isPublic field is absent or false, the list remains private (accessible only to the owner). This secure default prevents accidental exposure.

Custom Field definition draft example (Type definition):

This is the structure you'd use when defining the Type to create the isPublic field.
// Type Draft Snippet for shopping-list-settings Type
{
  "key": "shopping-list-settings", // Choose a meaningful key
  "name": { "en": "Shopping List Settings" },
  "description": { "en": "Custom settings including visibility." },
  "resourceTypeIds": ["shopping-list"], // Applies to Shopping Lists
  "fieldDefinitions": [
    {
      "name": "isPublic", // The custom field name
      "label": { "en": "Is Publicly Shareable" },
      "type": { "name": "Boolean" }, // Data type is Boolean
      "required": false, // Not required; absence means private
      "inputHint": "SingleLine"
    }
    // Add other settings fields here later if needed
  ]
}

Setting the isPublic field value

Once the Type and field are defined, you update a specific Shopping List instance to set its isPublic field value (to true or false). This is done using the setCustomField update action via the API, providing the list ID, its current version, the field name (isPublic), and the desired boolean value.

Backend logic: Fetching and displaying the public list

Your backend (for example, a Backend-for-Frontend or microservice) needs logic to handle requests for shared lists (for example, GET /shared-list/{slug}).
  • Approach A: Fetch by Identifier, then Verify isPublic
    • Query: Fetch the Shopping List using only its slug or key.
    • Verify (in your code): Check if the list was found and if its custom.fields.isPublic is true. Handle 404 Not Found and 403 Forbidden (or 404 for private lists) appropriately.
    • Pros: Clear distinction between non-existent and private lists.
    • Cons: Requires backend logic post-API call.
  • Approach B: Query by Identifier AND isPublic Status
    • Query: Fetch using both identifier and isPublic = true in the API query predicate.
    • Verify: If the API returns a list, display it. If not, return 404 Not Found.
    • Pros: Simpler API interaction; platform does filtering.
    • Cons: Backend cannot distinguish why no list was returned (wrong slug versus private list).
  • Query Optimization: When combining filters in API query predicates, place highly selective identifiers (slug, key, id) before less selective ones (custom(fields(isPublic = true))) for better performance.

Frontend implementation

  • Create a dedicated route, such as /shared-list/:slug, in your frontend application.
  • This page calls your backend endpoint (which uses one of the logic approaches above) to fetch and display the list data.

Expanding sharing: Specific users

Beyond simple public sharing, you can share lists with specific individuals.

  • Mechanism: Use a Custom Field of type Set of String (for example, named sharedWith) on the Shopping List Type. Store user identifiers (for example, customer IDs, emails) in this set.
  • Implementation Steps:
    1. Define the sharedWith field in your Custom Type.
    2. Use the setCustomField API action to add or remove user identifiers from this set on a specific list.
    3. Your application logic must check if the currently logged-in user's identifier is present in the sharedWith custom field before granting access.
  • Considerations: Ensure robust security, clear UI for managing shares, consistent identifier choice, and handle optimistic concurrency (using the list version) during updates.

Advanced Custom Field Applications

Custom Fields unlock many possibilities beyond basic sharing, including:

  • List Metadata: Store extra info directly on the list: listType ("Wishlist", "Grocery"), occasion ("Birthday", "Wedding"), eventDate, eventLocation, shippingAddress (for registries).
  • Partial Purchase Tracking: In shared lists (like registries), track who bought what to prevent duplicates. Add a Custom Field (such as purchasedBy as a Set of String) to the Line Item Type (resourceTypeIds: ["line-item"]). Your application would update this field when an item is purchased from the shared list.
  • Localization: Use LocalizedString types for custom fields needing language-specific values.
  • Text Line Item Notes: Add metadata (for example, priority) to text-based items using a Type associated with text-line-item.
(Applying custom fields to Line Items or Text Line Items follows similar principles: define a Type for that resource, then use specific API actions like setLineItemCustomField or setTextLineItemCustomField.)

List lifecycle management

Commercetools can automatically delete inactive Shopping Lists using the deleteDaysAfterLastModification field.
  • Mechanism: Set this field on the Shopping List via the setDeleteDaysAfterLastModification API update action. Provide the number of days of inactivity before deletion. Setting it to null or omitting it disables auto-deletion.

Test your knowledge