Learn how to properly manage errors when implementing Cart actions using the Composable Commerce SDK.
After completing this page, you should be able to:
- Implement robust error handling to manage common API responses, including a recovery strategy for
409 Conflict
errors. - Apply a backend security check to validate that a user is only able to access and modify their own Cart.
When working with Carts in Composable Commerce, several types of errors can occur. Understanding and handling errors correctly ensures a smoother shopping experience for your customers.
Typical error scenarios include:
- Version conflicts: another process updated the Cart between your read and update actions.
- Invalid data: incorrect SKU, currency, or other required fields missing.
- Cart not found: attempting to operate on a Cart that no longer exists or was deleted.
- Authorization errors: using an incorrect
anonymousId
,customerId
, or missing permissions. - Price mismatch: price selection failed because no matching price was found for country, currency, and Channel.
- CartState issues: trying to update a
Merged
,Frozen
, orOrdered
Cart.
Error responses have the following structure across the different Composable Commerce APIs:
{
"statusCode": 401,
"message": "Example error message.",
"errors": [
{
"code": "invalid_token",
"message": "Example error message."
},
]
}
- statusCode: HTTP status code corresponding to the error.
- message: first error message in the
errors
array. - errors: errors returned for a request. A single error response can contain multiple errors if the errors are related to the same HTTP status code such as
400
.
Below, is a breakdown of common errors, their details, and suggestions on how to handle them:
Status code | Meaning | Suggested handling |
---|---|---|
400 Bad Request | Indicates an issue with the request itself, such as invalid JSON or missing required fields. | Consult the docs and validate input before sending. |
401 Unauthorized | Occurs when your API client lacks the necessary authentication credentials or scopes. | Revise scopes of the API key, ensure you have a valid access token and the required scopes for the operation. |
403 Forbidden | Your API client has valid credentials but lacks permission to perform the requested action. | Verify your API client’s roles and permissions. |
404 Not Found | The requested Cart or resource does not exist. | Make sure you are using the right Cart ID or key. |
429 Too Many Requests | You’ve exceeded the API rate limit. | Implement rate limiting and retry mechanisms in your application. |
5xx Server Errors | Indicate an issue on the Composable Commerce side. | Retry your request after a short delay. If the issue persists, contact Composable Commerce support. |
Best practices for error handling
Composable Commerce uses standard HTTP status codes to indicate errors. Your error-handling logic should:
- Catch errors in API requests.
- Examine the
statusCode
anderrors
array in the API response. - Implement retry mechanisms for recoverable errors like server errors or rate limiting.
- Log all errors for debugging and monitoring.
- Handle errors gracefully. Provide informative error messages to the customer and avoid exposing technical details.
Handle version conflicts
Version conflicts occur when you try to update a Cart that has already been modified.
import { ErrorResponse } from "@Composable Commerce/platform-sdk";
// Code to create an array of CartUpdateAction for example addLineItemAction, removeLineItemAction
try {
const response = await apiRoot
.inStoreKeyWithStoreKeyValue({ storeKey })
.carts()
.withId({ ID: cartId })
.post({ body: { version, actions } })
.execute();
} catch (error) {
const errorResponse = error as ErrorResponse;
if (errorResponse.statusCode === 409) {
// Version conflict. Handle error for example Handle by using the version number in the error body here or do this in the middleware layer.
} else {
// Handle other errors
}
}
Security: validate Cart ownership
id
alone does not validate ownership. A malicious actor could potentially guess Cart IDs to view another user's Cart contents.customerId
(for logged-in users) or anonymousId
(for guest users) matches the identifier of the user making the request.- The frontend makes a request to your BFF API to get the Cart.
- Your API authenticates the user and gets their
userId
oranonymousId
from their session/token. - Your API fetches the Cart from Composable Commerce using the
cartId
. - Crucially, your API compares the
cart.body.customerId
orcart.body.anonymousId
with the user's ID from the session. - If they match, return the Cart.
- If they do not match, treat it as a
404 Not Found
to avoid leaking information that the Cart exists. Log this as a potential security event.
API design: communicating state changes and partial success
When a user modifies their Cart, the frontend may need to provide specific feedback, such as "Item X was added to your Cart" or "The quantity for Item Y was updated." Simply receiving the updated Cart object from the API is not enough, as the frontend doesn't automatically know what changed between the update and the last version of the Cart.
The BFF's primary responsibility is to bridge this gap. It must inspect the client's request, observe the result from the Composable Commerce API, and return a structured response that explicitly describes the outcome of each requested change.
actions
array) with the final outcome (the updated Cart and the errors
array from the API response).- Receive and retain: the BFF receives a request from the client containing the list of
actions
to perform. The BFF must keep this list in memory for the next step. - Execute: the BFF sends the
actions
to the Composable Commerce API. - Analyze the response: the BFF must inspect both the updated
cart
object and theerrors
array in the response body. - Reconcile and build response: the BFF iterates through the original
actions
it received from the client and any actions it added. For each action, it determines if it succeeded or failed. - Construct a rich response: the BFF sends a response to the client that includes:
- The final, updated
cart
object with the necessary field. - A structured
changes
ormessages
object that clearly lists the successful and failed operations, providing enough detail for the UI to display meaningful notifications.
- The final, updated