Add functionality to the request object in the TypeScript SDK.
The TypeScript SDK v2 client was deprecated on 30 October 2024.
You can add middleware when creating the TypeScript SDK client. You can add multiple middlewares by using a chain of middleware builder methods.
const client = new ClientBuilder()
.withClientCredentialsFlow(authMiddlewareOptions)
.withHttpMiddleware(httpMiddlewareOptions)
.withLoggerMiddleware()
// Chain additional middleware here
.build();
HttpMiddleware
Handles sending the HTTP request to the Composable Commerce API.
type HttpMiddlewareOptions = {
host: string;
credentialsMode?: 'omit' | 'same-origin' | 'include';
includeHeaders?: boolean;
includeResponseHeaders?: boolean;
includeOriginalRequest?: boolean;
includeRequestInErrorResponse?: boolean;
maskSensitiveHeaderData?: boolean;
timeout?: number;
enableRetry?: boolean;
retryConfig?: {
maxRetries?: number;
retryDelay?: number;
backoff?: boolean;
maxDelay?: number;
retryOnAbort?: boolean;
retryCodes?: Array<number | string>;
};
fetch?: any;
abortController?: AbortController; // deprecated
getAbortController?: () => AbortController;
};
const options: HttpMiddlewareOptions = {
host: 'https://api.europe-west1.gcp.commercetools.com',
includeResponseHeaders: true,
maskSensitiveHeaderData: true,
includeOriginalRequest: false,
includeRequestInErrorResponse: false,
enableRetry: true,
retryConfig: {
maxRetries: 3,
retryDelay: 200,
backoff: false,
retryCodes: [503],
},
fetch: fetchFn,
};
const client = new ClientBuilder()
.withHttpMiddleware(options)
// ...
.build();
AuthMiddleware
Handles generating, authenticating, and refreshing auth tokens used when making authenticated requests to the Composable Commerce API.
withRefreshTokenFlow
) for new requests.options
parameter, which you can pass to each middleware.withClientCredentialsFlow
type AuthMiddlewareOptions = {
host: string
projectKey: string
credentials: Credentials
scopes?: Array<string>
oauthUri?: string
fetch?: any
tokenCache?: TokenCache
}
const options: AuthMiddlewareOptions {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET
},
scopes: [`manage_project:${projectKey}`],
fetch: fetchFn
}
const client = new ClientBuilder()
.withClientCredentialsFlow(options)
// ...
.build()
withPasswordFlow
type PasswordAuthMiddlewareOptions = {
host: string;
projectKey: string;
credentials: {
clientId: string;
clientSecret: string;
user: {
username: string;
password: string;
};
};
scopes?: Array<string>;
tokenCache?: TokenCache;
oauthUri?: string;
fetch?: any;
};
const options: PasswordAuthMiddlewareOptions = {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET,
user: {
username: process.env.USERNAME,
password: process.env.PASSWORD,
},
},
scopes: [`manage_project:${projectKey}`],
fetch: fetchFn,
};
const client = new ClientBuilder()
.withPasswordFlow(options)
// ...
.build();
withAnonymousSessionFlow
type AnonymousAuthMiddlewareOptions = {
host: string;
projectKey: string;
credentials: {
clientId: string;
clientSecret: string;
anonymousId?: string;
};
scopes?: Array<string>;
oauthUri?: string;
fetch?: any;
tokenCache?: TokenCache;
};
const options: AnonymousAuthMiddlewareOptions = {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET,
anonymousId: process.env.CTP_ANONYMOUS_ID, // a unique id
},
scopes: [`manage_project:${projectKey}`],
fetch: fetchFn,
};
const client = new ClientBuilder()
.withAnonymousSessionFlow(options)
// ...
.build();
withRefreshTokenFlow
type RefreshAuthMiddlewareOptions = {
host: string;
projectKey: string;
credentials: {
clientId: string;
clientSecret: string;
};
refreshToken: string;
tokenCache?: TokenCache;
oauthUri?: string;
fetch?: any;
};
const options: RefreshAuthMiddlewareOptions = {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET,
},
refreshToken: 'bXvTyxc5yuebdvwTwyXn==',
tokenCache: TokenCache,
scopes: [`manage_project:${projectKey}`],
fetch: fetchFn,
};
const client = new ClientBuilder()
.withRefreshTokenFlow(options)
// ...
.build();
withExistingTokenFlow
Attaches an access token Authorization header.
type ExistingTokenMiddlewareOptions = {
force?: boolean;
};
const authorization: string = 'Bearer G8GLDqrUMYzaOjhdFGfK1HRIOAtj7qQy';
const options: ExistingTokenMiddlewareOptions = {
force: true,
};
const client = new ClientBuilder()
.withExistingTokenFlow(authorization, options)
// ...
.build();
CorrelationIdMiddleware
X-Correlation-ID
entry to the request headers.type CorrelationIdMiddlewareOptions = {
generate: () => string;
};
const options: CorrelationIdMiddlewareOptions = {
generate: () => 'cd260fc9-c575-4ba3-8789-cc4c9980ee4e', // Replace with your own UUID or a generator function
};
const client = new ClientBuilder()
.withCorrelationIdMiddleware(options)
// ...
.build();
UserAgentMiddleware
User-Agent
header to every request. By default it adds the SDK (and its version) and the running process (and its version) to the request. For example:'User-Agent': 'commercetools-sdk-javascript-v2/2.1.4 node.js/18.13.0'
type HttpUserAgentOptions = {
name?: string;
version?: string;
libraryName?: string;
libraryVersion?: string;
contactUrl?: string;
contactEmail?: string;
customAgent?: string;
};
const options: HttpUserAgentOptions = {
name: 'test-client-agent',
version: '2.9.0',
};
const client = new ClientBuilder()
.withUserAgentMiddleware(options)
// ...
.build();
QueueMiddleware
Use QueueMiddleware to reduce concurrent HTTP requests.
type QueueMiddlewareOptions = {
concurrency: number;
};
const options: QueueMiddlewareOptions = {
concurrency: 20,
};
const client = new ClientBuilder()
.withQueueMiddleware(options)
// ...
.build();
withTelemetryMiddleware
// Required import
import {
createTelemetryMiddleware,
TelemetryMiddlewareOptions,
} from '@commercetools/ts-sdk-apm';
const telemetryOptions: TelemetryMiddlewareOptions = {
createTelemetryMiddleware,
apm: () => typeof require('newrelic'), // installed npm `newrelic` package
tracer: () => typeof require('/absolute-path-to-a-tracer-module'),
};
const client = new ClientBuilder()
.withTelemetryMiddleware(telemetryOptions)
// ...
.build();
LoggerMiddleware
options
parameter, which accepts a custom logger function, and another optional parameter to be used within the custom logger function.function logger(options?: LoggerMiddlewareOptions) {
return (next: Next): Next => {
return (req: MiddlewareRequest, res: MiddlewareResponse) => {
console.log(options); // Logs all included options except the logger function output -> { level: 'debug', name: 'custom-logger-fn' }
console.log(req, res);
next(req, res);
};
};
}
const client: Client = new ClientBuilder()
.withProjectKey('projectKey')
.withLoggerMiddleware({
level: 'debug',
name: 'custom-logger-fn',
logger,
})
// ...
.build();
BeforeExecutionMiddleware
.withBeforeExecutionMiddleware()
.import {
type Next,
type Client,
type MiddlewareRequest,
type BeforeExecutionMiddlewareOptions,
type MiddlewareResponse,
ClientBuilder,
} from '@commercetools/sdk-client-v2';
function before(options: BeforeExecutionMiddlewareOptions) {
return (next: Next): Next => {
return (req: MiddlewareRequest, res: MiddlewareResponse) => {
// Logic to be executed goes here
// option will contain { name: 'before-middleware-fn' }
console.log(options); // { name: 'before-middleware-fn' }
next(req, res);
};
};
}
const client: Client = new ClientBuilder()
.withProjectKey('projectKey')
.withBeforeExecutionMiddleware({
name: 'before-middleware-fn',
middleware: before,
})
// ...
.build();
AfterExecutionMiddleware
.withAfterExecutionMiddleware()
.import {
type Next,
type Client,
type MiddlewareRequest,
type AfterExecutionMiddlewareOptions,
type MiddlewareResponse,
ClientBuilder,
} from '@commercetools/sdk-client-v2';
function after(options: AfterExecutionMiddlewareOptions) {
return (next: Next): Next => {
return (req: MiddlewareRequest, res: MiddlewareResponse) => {
// Logic to be executed goes here
// option will contain { name: 'after-middleware-fn' }
console.log(options); // { name: 'after-middleware-fn' }
next(req, res);
};
};
}
const client: Client = new ClientBuilder()
.withProjectKey('projectKey')
.withAfterExecutionMiddleware({
name: 'after-middleware-fn',
middleware: after,
})
// ...
.build();
Custom middleware
Certain use cases, such as adding headers to API requests, may require you to create custom middleware.
X-External-User-ID
.function customHeaderMiddleware() {
return (next) => (request, response) => {
const newRequest = {
...request,
headers: {
...request.headers,
'X-External-User-ID': 'custom-header-value',
},
};
next(newRequest, response);
};
}
.withMiddleware()
method. Using this method, the SDK calls your middleware before calling other middlewares.const client = new ClientBuilder()
.withMiddleware(customHeaderMiddleware())
// ...
.build();
Migrate to the v3 client
The v3 client is similar to the v2 client in many ways. They are both based on a middleware call chain (the middleware pattern).
request
object and returns a response
object. This compares to the v2 client middleware which accepts both a request
and response
object and returns void
.Consult the following tables and example code for information on migrating from v2 client middleware to v3 client middleware.
HttpMiddleware
Option | Replaced/Removed | Reason |
---|---|---|
includeHeaders | Removed | This option was not used in v2. |
fetch | Replaced by httpClient | We replaced this option because we added support for Axios. You can now pass either fetch or axios to the HTTP client function. fetch is the default option, if not defined. |
abortController | Removed | Removed because of deprecation in v2. |
retryOnAbort
is now by default set to true
.type HttpMiddlewareOptions = {
host: string;
credentialsMode?: 'omit' | 'same-origin' | 'include';
includeHeaders?: boolean;
includeResponseHeaders?: boolean;
includeOriginalRequest?: boolean;
includeRequestInErrorResponse?: boolean;
maskSensitiveHeaderData?: boolean;
timeout?: number;
enableRetry?: boolean;
retryConfig?: {
maxRetries?: number;
retryDelay?: number;
backoff?: boolean;
maxDelay?: number;
retryOnAbort?: boolean;
retryCodes?: Array<number | string>;
};
fetch?: any;
abortController?: AbortController; // deprecated
getAbortController?: () => AbortController;
};
const options: HttpMiddlewareOptions = {
host: 'https://api.europe-west1.gcp.commercetools.com',
includeResponseHeaders: true,
maskSensitiveHeaderData: true,
includeOriginalRequest: false,
includeRequestInErrorResponse: false,
enableRetry: true,
retryConfig: {
maxRetries: 3,
retryDelay: 200,
backoff: false,
retryCodes: [503],
},
fetch: fetchFn,
};
const client = new ClientBuilder()
.withHttpMiddleware(options)
// ...
.build();
type HttpMiddlewareOptions = {
host: string;
credentialsMode?: 'omit' | 'same-origin' | 'include';
includeResponseHeaders?: boolean;
includeOriginalRequest?: boolean;
includeRequestInErrorResponse?: boolean;
maskSensitiveHeaderData?: boolean;
timeout?: number;
enableRetry?: boolean;
retryConfig?: {
maxRetries?: number;
retryDelay?: number;
backoff?: boolean;
maxDelay?: number;
retryOnAbort?: boolean;
retryCodes?: Array<number | string>;
};
httpClient: Function<fetch | axiosInstance>;
httpClientOptions?: object; // will be passed as a second argument to your httpClient function for configuration
getAbortController?: () => AbortController;
};
// using a proxy agent
import { HttpsProxyAgent } from 'https-proxy-agent';
const agent = new HttpsProxyAgent('http://8.8.8.8:8888');
const options: HttpMiddlewareOptions = {
host: 'https://api.europe-west1.gcp.commercetools.com',
includeResponseHeaders: true,
maskSensitiveHeaderData: true,
includeOriginalRequest: false,
includeRequestInErrorResponse: false,
enableRetry: true,
retryConfig: {
maxRetries: 3,
retryDelay: 200,
backoff: false,
retryCodes: [503],
},
httpClient: fetch,
httpClientOptions: { agent } // this will be passed to fetch ()
};
const client = new ClientBuilder()
.withHttpMiddleware(options)
// ...
.build();
AuthMiddleware
fetch
property now use httpClient
.ClientCredentialsFlow
Option | Replaced/Removed | Reason |
---|---|---|
fetch | Replaced by httpClient | We replaced this option because we added support for Axios. You can now pass either fetch or axios to the HTTP client function. fetch is the default option, if not defined. |
type AuthMiddlewareOptions = {
host: string
projectKey: string
credentials: Credentials
scopes?: Array<string>
oauthUri?: string
fetch?: any
tokenCache?: TokenCache
}
const options: AuthMiddlewareOptions {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET
},
scopes: [`manage_project:${projectKey}`],
fetch: fetchFn
}
const client = new ClientBuilder()
.withClientCredentialsFlow(options)
// ...
.build()
type AuthMiddlewareOptions = {
host: string
projectKey: string
credentials: {
clientId: string
clientSecret: string
}
scopes?: Array<string>
oauthUri?: string
httpClient: Function
httpClientOptions?: object
tokenCache?: TokenCache
}
const options: AuthMiddlewareOptions {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET
},
scopes: [`manage_project:${projectKey}`],
httpClient: fetch
}
const client = new ClientBuilder()
.withClientCredentialsFlow(options)
// ...
.build()
PasswordAuthMiddleware
Option | Replaced/Removed | Reason |
---|---|---|
fetch | Replaced by httpClient | We replaced this option because we added support for Axios. You can now pass either fetch or axios to the HTTP client function. fetch is the default option, if not defined. |
type PasswordAuthMiddlewareOptions = {
host: string;
projectKey: string;
credentials: {
clientId: string;
clientSecret: string;
user: {
username: string;
password: string;
};
};
scopes?: Array<string>;
tokenCache?: TokenCache;
oauthUri?: string;
fetch?: any;
};
const options: PasswordAuthMiddlewareOptions = {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET,
user: {
username: process.env.USERNAME,
password: process.env.PASSWORD,
},
},
scopes: [`manage_project:${projectKey}`],
fetch: fetchFn,
};
const client = new ClientBuilder()
.withPasswordFlow(options)
// ...
.build();
type PasswordAuthMiddlewareOptions = {
host: string;
projectKey: string;
credentials: {
clientId: string;
clientSecret: string;
user: {
username: string;
password: string;
};
};
scopes?: Array<string>;
tokenCache?: TokenCache;
oauthUri?: string;
httpClient: Function<fetch | axiosInstance>;
httpClientOptions?: object;
};
const options: PasswordAuthMiddlewareOptions = {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET,
user: {
username: process.env.USERNAME,
password: process.env.PASSWORD,
},
},
scopes: [`manage_project:${projectKey}`],
httpClient: fetch,
};
const client = new ClientBuilder()
.withPasswordFlow(options)
// ...
.build();
AnonymousSessionFlow
Option | Replaced/Removed | Reason |
---|---|---|
fetch | Replaced by httpClient | We replaced this option because we added support for Axios. You can now pass either fetch or axios to the HTTP client function. fetch is the default option, if not defined. |
AnonymousAuthMiddlewareOptions
type for options instead of the generic AuthMiddlewareOptions
.type AnonymousAuthMiddlewareOptions = {
host: string;
projectKey: string;
credentials: {
clientId: string;
clientSecret: string;
anonymousId?: string;
};
scopes?: Array<string>;
oauthUri?: string;
fetch?: any;
tokenCache?: TokenCache;
};
const options: AnonymousAuthMiddlewareOptions = {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET,
anonymousId: process.env.CTP_ANONYMOUS_ID, // a unique id
},
scopes: [`manage_project:${projectKey}`],
fetch: fetchFn,
};
const client = new ClientBuilder()
.withAnonymousSessionFlow(options)
// ...
.build();
type AnonymousAuthMiddlewareOptions = {
host: string;
projectKey: string;
credentials: {
clientId: string;
clientSecret: string;
anonymousId?: string;
};
scopes?: Array<string>;
oauthUri?: string;
httpClient: Function<fetch | axiosInstance>;
httpClientOptions?: object
tokenCache?: TokenCache;
};
const options: AnonymousAuthMiddlewareOptions = {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET,
anonymousId: process.env.CTP_ANONYMOUS_ID, // a unique id
},
scopes: [`manage_project:${projectKey}`],
httpClient: fetch,
};
const client = new ClientBuilder()
.withAnonymousSessionFlow(options)
// ...
.build();
RefreshAuthMiddleware
Option | Replaced/Removed | Reason |
---|---|---|
fetch | Replaced by httpClient | We replaced this option because we added support for Axios. You can now pass either fetch or axios to the HTTP client function. fetch is the default option, if not defined. |
type RefreshAuthMiddlewareOptions = {
host: string;
projectKey: string;
credentials: {
clientId: string;
clientSecret: string;
};
refreshToken: string;
tokenCache?: TokenCache;
oauthUri?: string;
fetch?: any;
};
const options: RefreshAuthMiddlewareOptions = {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET,
},
refreshToken: 'bXvTyxc5yuebdvwTwyXn==',
tokenCache: TokenCache,
scopes: [`manage_project:${projectKey}`],
fetch: fetchFn,
};
const client = new ClientBuilder()
.withRefreshTokenFlow(options)
// ...
.build();
type RefreshAuthMiddlewareOptions = {
host: string;
projectKey: string;
credentials: {
clientId: string;
clientSecret: string;
};
refreshToken: string;
tokenCache?: TokenCache;
oauthUri?: string;
httpClient: Function<fetch | axiosInstance>;
httpClientOptions?: object;
};
const options: RefreshAuthMiddlewareOptions = {
host: 'https://auth.europe-west1.gcp.commercetools.com',
projectKey: 'test-project-key',
credentials: {
clientId: process.env.CTP_CLIENT_ID,
clientSecret: process.env.CTP_CLIENT_SECRET,
},
refreshToken: 'bXvTyxc5yuebdvwTwyXn==',
tokenCache: TokenCache,
scopes: [`manage_project:${projectKey}`],
httpClient: fetch,
};
const client = new ClientBuilder()
.withRefreshTokenFlow(options)
// ...
.build();
LoggerMiddleware
Option | Replaced/Removed | Reason |
---|---|---|
logger | Replaced by loggerFn | You can now pass an optional custom logger function to the .withLoggerMiddleware() builder method. If you do not pass a logger function, the SDK uses console.log() . |
function logger(options?: LoggerMiddlewareOptions) {
return (next: Next): Next => {
return (req: MiddlewareRequest, res: MiddlewareResponse) => {
console.log(options); // Logs all included options except the logger function output -> { level: 'debug', name: 'custom-logger-fn' }
console.log(req, res);
next(req, res);
};
};
}
const client: Client = new ClientBuilder()
.withProjectKey('projectKey')
.withLoggerMiddleware({
level: 'debug',
name: 'custom-logger-fn',
logger,
})
// ...
.build();
type LoggerMiddlewareOptions = {
loggerFn?: (options: MiddlewareResponse) => void
}
const loggerMiddlewareOptions: LoggerMiddlewareOptions = {
loggerFn: (response: MiddlewareResponse) => {
console.log('Response is: ', response)
},
}
const client = new ClientBuilder()
.withLoggerMiddleware(loggerMiddlewareOptions)
// ...
.build();
Custom middleware
You must rewrite custom middleware to use the Promise-based v3 client.
function customV2Middleware() {
return (next) => (request, response) => {
const newRequest = {
...request,
headers: {
...request.headers,
'X-UserAgent': 'custom-user-agent',
},
};
next(newRequest, response);
};
}
function customV3Middleware() {
return (next) => (request) => {
const newRequest = {
...request,
headers: {
...request.headers,
'X-UserAgent': 'custom-user-agent',
},
};
return next(newRequest);
};
}