CMP-SDK is a nodejs client package to work with Optimizely CMP (formerly known as Welcome) provided Public REST API Endpoints.
The package is available on npm registry. You can install the package with the npm install
command,
npm install @welcomesoftware/cmp-sdk
In your project, import the CmpClient
class from the '@welcomesoftware/cmp-sdk' package.
import { CmpClient } from "@welcomesoftware/cmp-sdk";
const cmpClient = new CmpClient(param);
param
is an object with the following properties
-
accessToken
type:string
orFunction
(function interface:(tokenGetParam: any) => string | Promise<string>
)
Value of the access token to be used or a function that returns an access token. The optionaltokenGetParam
parameter can be astring
,object
or afunction
that the function may need to fetch the access token (more on this later) -
refreshToken
type:string
orFunction
(function interface:(tokenGetParam: any) => string | Promise<string>
)
Value of the refresh token to be used or a function that returns a refresh token. The optionaltokenGetParam
parameter can be astring
,object
or afunction
that the function may need to fetch the refresh token (more on this later) -
clientId
type:string
The client Id of the app registered in Optimizely CMP. If you omit this field, the app will try to extract the value fromCMP_CLIENT_ID
environment variable -
clientSecret
type:string
The client secret of the app registered in Optimizely CMP. If you omit this field, the app will try to extract the value fromCMP_CLIENT_SECRET
environment variable -
redirectUri
type:string
The redirect URI registered in Optimizely CMP with the associated app -
enableAutoRetry
type:boolean
Iftrue
the app will try to update the access token using the refresh token if any api call encounters401 Unauthorized
error and retry again. If the second retry also fails, the app will raise an error.
Default:false
-
onAuthSuccess
type:Function
(interface:(accessToken: string, refreshToken: string, tokenGetParam: any) => any
)
This function will be called when authorization code flow completes successfully. You can omit this field if you handle oauth callback manually. -
onAuthFailure
type:Function
(interface:(error: string) => any
)
This function will be called if authorization server redirects to redirect URL with any error. You can omit this field if you handle oauth callback manually -
tokenChangeCallback
type:Function
(interface:(accessToken: string, refreshToken: string, tokenGetParam: any) => any
)
This function will be called when the app updates the current tokens. You can use this function to store the updated access and refresh tokens in your database. The optional third parametertokenGetParam
can be astring
,object
,function
or anything that your function may need.
tokenGetParam : Above and throughout the document, you can see a parameter named tokenGetParam
. If you use functions as the accessToken
and/or refreshToken
properties, and if any parameter is required for those functions to work, then the tokenGetParam
parameter is needed to be paased. You can only ignore this optional parameter, if your token getter functions do not require any parameter.
Here is a full example of using the sdk in an express application,
import express from "express";
import { CmpClient } from "@welcomesoftware/cmp-sdk";
const app = express();
const dummyDB = {
accessToken: "",
refreshToken: "",
};
const cmpClient = new CmpClient({
accessToken: () => dummyDB.accessToken,
refreshToken: () => dummyDB.refreshToken,
onAuthFailure: (err) => {
console.log("authorization failed with error " + err);
throw new Error(err);
},
onAuthSuccess: (accessToken, refreshToken) => {
dummyDB = { accessToken, refreshToken };
console.log("authorization successful");
},
tokenChangeCallback: (accessToken, refreshToken) => {
dummyDB.accessToken = accessToken;
dummyDB.refreshToken = refreshToken;
console.log("token updated");
},
redirectUri: "https://www.example.com/optimizely-cmp/oauth/callback", // assuming, your server is hosted on www.example.com
enableAutoRetry: true,
});
// handling Optimizely CMP app authorization with the SDK
app.get("/optimizely-cmp/oauth", (req, res) => {
cmpClient.auth.initiateOAuth((url) => res.redirect(url));
});
app.get("/optimizely-cmp/oauth/callback", async (req, res) => {
try {
await cmpClient.auth.handleOAuthCallback(req.query);
return res.send("success");
} catch (err) {
return res.status(400).json({ message: err.message });
}
});
// accessing resources on Optimizely CMP with the SDK
app.get("/optimizely-cmp/assets", async (req, res) => {
const cmpAssets = await cmpClient.library.getAssets();
return res.json({ cmpAssets });
});
app.listen(process.env.PORT);
Learn more about using the SDK in the full API Reference
In the detailed documents, you may see some of the methods have an badge. These methods are based on experimental APIs. Experimental APIs provide early access to APIs that are currently under development. The documentation may highlight new features, new data properties and data models, new filters, and other features specific to the new API. Our intention in providing you with early access to the documentation for these APIs in the experimental stage is that you may plan for implementing them in the near future and provide us with necessary feedback to meet your needs. These APIs are most often NOT operational and the documentation is subject to change frequently from the time the documentation is available to the time the APIs are fully released. Experimental APIs will generally require testing and development on your own applications before relying on them in your stable production environments
You may want to test out released APIs that are not yet availbale in the SDK or want to add more functionality to the CmpClient
class based on your usecase. You can write your own custom class extending from the CmpClient
class provided by the SDK. Here is an example of how you can write your own custom class extending from the CmpClient
class.
import { CmpClient } from "@welcomesoftware/cmp-sdk";
import { APICaller } from '@welcomesoftware/cmp-sdk/lib/modules/api-caller';
import type { CmpClientConstructorParam } from "@welcomesoftware/cmp-sdk";
// define your own module
class StructuredContent {
#apiCaller: APICaller;
constructor(apiCaller: APICaller) {
this.#apiCaller = apiCaller;
}
async acknowledgeContentReviewRequest(
url: string,
contentHash: string,
userId: string,
) {
const payload: ContentPreviewRequestedAcknowledgePayload = {
acknowledgedBy: userId,
contentHash: contentHash,
};
await this.#apiCaller.post(url, payload);
}
async completeContentReviewRequest(
url: string,
sitename: string,
previewUrl: string,
) {
const payload = {
keyed_previews: {
[sitename]: previewUrl,
},
};
await this.#apiCaller.post(url, payload);
}
}
// extend CmpClient
class ExtendedCmpClient extends CmpClient {
structuredContent: StructuredContent;
constructor(params: CmpClientConstructorParam) {
super(params);
const apiCaller = new APICaller(this.auth, params.enableAutoRetry, false);
this.structuredContent = new StructuredContent(apiCaller);
}
}
// initiate an instance of the `ExtendedCmpClient` class instead of the `CmpClient` class
export const cmpClient = new ExtendedCmpClient(...)
See the Example folder for a full demo.