TypeScript SDK best practices

Ask about this Page
Copy for LLM
View as Markdown

Recommended patterns for building reliable applications with the TypeScript SDK.

Client initialization

Use the ClientBuilder to create a client. Always load credentials from environment variables rather than hardcoding them in your application.
import { ClientBuilder } from '@commercetools/ts-client'

const projectKey = process.env.CTP_PROJECT_KEY

const authMiddlewareOptions = {
  host: process.env.CTP_AUTH_HOST,
  projectKey,
  credentials: {
    clientId: process.env.CTP_CLIENT_ID,
    clientSecret: process.env.CTP_CLIENT_SECRET,
  },
  scopes: [process.env.CTP_SCOPES],
  httpClient: fetch,
}

const httpMiddlewareOptions = {
  host: process.env.CTP_API_HOST,
  includeRequestInErrorResponse: true,
  includeOriginalRequest: true,
  httpClient: fetch,
}

const client = new ClientBuilder()
  .withProjectKey(projectKey)
  .withClientCredentialsFlow(authMiddlewareOptions)
  .withHttpMiddleware(httpMiddlewareOptions)
  .withUserAgentMiddleware()
  .withLoggerMiddleware()
  .build()
Never expose credentials such as clientId and clientSecret in your source code or version control. Always use environment variables or a secrets manager to store sensitive values.

Client reuse

The client acts as a connection pool. To prevent unnecessary network overhead and connection limits, create a single instance of the client and reuse it throughout your application's lifecycle.

// client.ts
import { ClientBuilder } from '@commercetools/ts-client'
import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk'

function getClient(options) {
  return new ClientBuilder()
    .withProjectKey(options.projectKey)
    .withClientCredentialsFlow(options.authMiddlewareOptions)
    .withHttpMiddleware(options.httpMiddlewareOptions)
    .withUserAgentMiddleware()
    .build()
}

const options = {
  projectKey: process.env.CTP_PROJECT_KEY,
  authMiddlewareOptions: { /* ... */ },
  httpMiddlewareOptions: { /* ... */ },
}

export const apiRoot = createApiBuilderFromCtpClient(
  getClient(options)
).withProjectKey({ projectKey: options.projectKey })
Import and use the exported apiRoot throughout your application. This ensures only a single client instance is created for all requests.

Token management

The SDK manages the full auth token lifecycle automatically. When a request is made, the SDK checks the token, generates a new one if expired or unavailable, and injects it into the request header. No manual token refresh is required.

For details on the available authentication flows, see AuthMiddleware.

Configure retries and timeouts

You can configure retry behavior and timeouts on the HttpMiddleware options:
  • enableRetry: Enable retries on network errors and selected 5xx responses. false by default to avoid unexpected behavior. Enable only if your application can tolerate retries.
  • timeout: Maximum time in milliseconds to wait for a request. Requests exceeding this duration are aborted. Required when enableRetry is true. undefined by default, which means no timeout is applied.
  • maxRetries: Maximum number of retry attempts. 10 by default.
  • backoff: Use exponential backoff between retries to avoid overloading the server. true by default. Set to false to use a fixed delay between retries.
  • retryDelay: Time in milliseconds to wait before the first retry. 200 by default.
  • maxDelay: Maximum delay in milliseconds between retries, used to cap exponential backoff growth. undefined by default, which means no maximum delay is applied.
const httpMiddlewareOptions = {
  host: process.env.CTP_API_HOST,
  enableRetry: true,
  timeout: 10000,
  maxRetries: 5,
  retryDelay: 200,
  maxDelay: 5000,
  httpClient: fetch,
}
Choose timeout and retry values that match your use case. If requests frequently time out due to network issues, consider increasing timeout and reducing retryDelay.

Customize responses

You can control what the SDK includes in successful and error responses using the following HttpMiddleware options:
  • includeOriginalRequest: Include the original client request in successful responses. true by default.
  • includeRequestInErrorResponse: Include the original request in error responses. false by default.
  • maskSensitiveHeaderData: Redact sensitive headers (such as the Authorization header) from included request data. true by default.
const httpMiddlewareOptions = {
  host: process.env.CTP_API_HOST,
  includeOriginalRequest: true,
  includeRequestInErrorResponse: true,
  maskSensitiveHeaderData: true,
  httpClient: fetch,
}

Concurrent requests

Use QueueMiddleware to throttle the number of concurrent HTTP requests. This prevents overloading the API and can improve overall throughput.
const client = new ClientBuilder()
  .withClientCredentialsFlow(authMiddlewareOptions)
  .withHttpMiddleware(httpMiddlewareOptions)
  .withQueueMiddleware({ concurrency: 5 }) // defaults to 20
  .build()

Configure proxies

Configure proxies at the HTTP client level by providing a custom httpClient function to HttpMiddleware options:
import HttpsProxyAgent from 'https-proxy-agent'

const fetchWithProxy = (url, fetchOptions = {}) => {
  fetchOptions.agent = new HttpsProxyAgent(process.env.HTTPS_PROXY)
  return fetch(url, fetchOptions)
}

const httpMiddlewareOptions = {
  host: process.env.CTP_API_HOST,
  httpClient: fetchWithProxy,
}

Make direct requests

If the SDK does not provide a method for a specific endpoint, use the execute function to construct and send requests directly:
const request = {
  uri: `/${projectKey}/in-store/key=${storeKey}/customers/token`,
  method: 'GET',
  headers: {
    Authorization: `Bearer ${token}`,
  },
}

client
  .execute(request)
  .then((result) => { /* handle result */ })
  .catch((error) => { /* handle error */ })

Process batch requests

The SDK exposes a Process function for processing paginated or batch requests. It takes a request, a callback invoked for each batch, and an options object.
import { Process, ClientBuilder } from '@commercetools/ts-client'
import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk'

const ctpClient = new ClientBuilder()
  .withProjectKey(projectKey)
  .withClientCredentialsFlow(authMiddlewareOptions)
  .withHttpMiddleware(httpMiddlewareOptions)
  .build()

const apiRoot = createApiBuilderFromCtpClient(ctpClient)
  .withProjectKey({ projectKey })

const request = await apiRoot.categories().get().clientRequest

const processBatch = (data) => data

Process(request, processBatch, {
  total: 50,       // total number of items to process
  accumulate: true // accumulate all results into a single array (default: true)
})
  .then((results) => {
    // results is an array of all processed batches
  })
  .catch(console.error)

HTTP client

const authMiddlewareOptions = {
  // ...
  httpClient: fetch,
}

const httpMiddlewareOptions = {
  // ...
  httpClient: fetch,
}
Due to breaking changes in node-fetch v3, projects using node-fetch v3 inside the SDK must use ESM (.mjs) module format. node-fetch v2 is fully supported without restrictions.

Client connection lifecycle

The SDK tears down connections automatically after each request-response cycle. You do not need to manually close or destroy client connections.

Read or write fields not in the SDK

In some cases, the platform API may return properties that are not part of the SDK's type definitions. You can extend an existing type to access those fields:

import { ErrorObject } from '@commercetools/platform-sdk'

type ExtendedErrorObject = ErrorObject & {
  customField: string
}
Fields may be absent from the SDK types when they are not part of the official API documentation. See this GitHub issue for further context.

Error handling

The SDK has built-in error handling. No additional error handling setup is required. For custom behavior, use ErrorMiddleware.

Logging

The withLoggerMiddleware() can be added at multiple points in the middleware chain to log the request and response at each stage:
const client = new ClientBuilder()
  .withLoggerMiddleware()          // log before the HTTP middleware
  .withHttpMiddleware(httpMiddlewareOptions)
  .withLoggerMiddleware()          // log after the HTTP middleware
  .build()
For more details, see LoggerMiddleware.

Keep the SDK up to date

Always use the latest version of the SDK packages to ensure you have the latest features, bug fixes, and security patches. Subscribe to GitHub releases to be notified of new versions.