This is the early access documentation preview for Custom Views. This documentation might not be in sync with our official documentation.
Convert an existing integration to a Connector
Overview
This step-by-step guide explains how to convert an existing integration into a Connector. It outlines the modifications needed to ensure that the project aligns with the new Connector requirements.
The guide covers various aspects such as the Connector specification file (connect.yaml
), determining the appropriate application type, implementing the proper folder structure, and constructing the necessary automation scripts for managing extensions and subscriptions.
Configure connect.yaml
To convert an existing repository to a valid Connector you must create and configure a connect.yaml
file. connect.yaml
is required and is the starting point of each Connector repository.
connect.yaml
contains the descriptions and configurations of each application to be deployed, and is used to publish and deploy the Connector.
Example connect.yaml file
You can use the following example connect.yaml file as a reference to create your own.
deployAs:- name: service_app_nameapplicationType: serviceendpoint: /servicescripts:postDeploy: npm run connector:post-deploypreUndeploy: npm run connector:pre-undeployconfiguration:standardConfiguration:- key: CTP_PROJECT_KEYdescription: Project key of the commercetools Composable Commerce Projectrequired: truedefault: 'default-key'securedConfiguration:- key: CTP_CLIENT_IDdescription: client_id of an API Client for the commercetools Composable Commerce Projectrequired: true- name: job_app_nameapplicationType: jobendpoint: /jobproperties:schedule: '*/5 * * * *'configuration:standardConfiguration:- key: CTP_PROJECT_KEYdescription: Project key of the commercetools Composable Commerce Projectrequired: truesecuredConfiguration:- key: CTP_CLIENT_IDdescription: client_id of an API Client for the commercetools Composable Commerce Projectrequired: true
See the following table for explanations of each attribute.
Key | Required | Description |
---|---|---|
deployAs | Yes | The root key of the file containing an array of the applications that we want to deploy in our Connector. In this file example, two applications named service_app_name and job_app_name are deployed. The name must match the folder for the application in your repository. |
name | Yes | Identifier of the application deployment. This is important as the deployment's output URL, topic, and schedule are fetched based on this reference. |
applicationType | Yes | The type of application to deploy. Connectors currently support four application types: service , event , job , and merchant-center-custom-application . |
endpoint | Yes | The endpoint naming used by the Deployment URL. The URL is constructed using the format {connect-provided-url}/{endpoint} (for example: https://service-11111111-1111-1111-1111-111111111111.europe-west1.gcp.commercetools.app/service ) |
properties.schedule | Yes (job type applications) | This configuration is only required for job applications. As it will work as a cron job it is important to specify the execution schedule. |
scripts | No | Displays the configuration for the Connector's scripts. You will need this field if you need to create and use commercetools API Extensions and Subscriptions. |
configuration | No | An object of configurations to be used in the Connector as schema validation. This is an array containing standardConfiguration and securedConfiguration . |
After gaining an understanding of the required application types for the Connector and creating connect.yaml, it is essential to adhere to a project structure that aligns with it.
Structure your project
In the context of Connect, each application is treated independently and it is necessary to isolate each application in a separate folder, as each one will be provisioned in a slightly different manner based on its application type.
Each folder must contain the value specified in the name
attribute.
Using the previous connect.yaml
example, we should have the following directory structure:
myconnector/├── service_app_name/│ ├── server.js│ └── package.json├── job_app_name/│ ├── server.js│ └── package.json└── connect.yaml
Choose an application type
Connect supports the following types of applications:
Service
Services allow you to handle API Extensions. A possible use case is to validate newly created resources and apply additional updates, such as calculating custom shipping costs for a cart or adding mandatory items.
Event
Events allow you to handle asynchronous events triggered by your Subscriptions. You can use event applications to notify your customers after a successful payment or if a product is back in stock.
Job
Jobs allow you to execute server-side logic on a regular schedule that you define using cron expressions like schedule: 0 0 * * *
. You can use job applications to do work that happens on a periodic basis, such as updating a resource every minute, generating a nightly report, or sending an automated weekly email newsletter.
Custom Applications
Custom Applications extend the functionality of the Merchant Center.
Implement Connect applications
Every application receives the necessary configuration as defined in connect.yaml, which is provided through environment variables.
Additionally, each Connect application must ensure that it exposes an HTTP server at 8080, encompassing all the required integration endpoints, as in the following examples:
Service
import express, { Request, Response } from 'express';import bodyParser from 'body-parser';const app = express();app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: true }));app.post('/service', async (req: Request, res: Response) => {const action = req.body;console.info('New action received', action);// handle business logicconst additionalActions = [];// build additional resource update actionres.status(200).json({ actions: additionalActions });});
Event
import express, { Request, Response } from 'express';import bodyParser from 'body-parser';const app = express();app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: true }));app.post('/event', async (req: Request, res: Response) => {const event = req.body;console.info('New event received', event);// handle business logic// ex: notify user product back in stockres.status(200).send();});
Job
import express, { Request, Response } from 'express';import bodyParser from 'body-parser';const app = express();app.post('/job', async (req: Request, res: Response) => {const event = req.body;console.info('New event received', event);// handle business logic// ex: build report, send emailres.status(200).send();});
package.json
You must include the following scripts in package.json.
Name | Description |
---|---|
gcp-build | Automates the build process of the project to generate production-ready code. |
start | The entry point of the application, responsible for initializing the server listening on port 8080. |
"scripts": {"gcp-build": "tsc","start": "node build/index.js"}
Adding automation scripts
It is common for any integration to require the creation of specific resources during the deployment lifecycle in the Composable Commerce API, such as Types, API Extensions, or Subscriptions.
You can define scripts in connect.yaml which run on different deployment stages, which allows Connect to create and modify those resources.
postDeploy
postDeploy
runs after a successful deployment of the Connect application and is useful when you need to set up an API Extension or Subscription required to trigger your Connector endpoint.
postDeploy
has access to extra environment variables depending on the application type.
Environment variable | Application type | Description |
---|---|---|
CONNECT_SERVICE_URL | Service | The public URL of the Connect application, should be used when setting up the API Extension in the Composable Commerce API. |
CONNECT_GCP_PROJECT_ID | Event | Google Cloud Platform (GCP) project ID. Should be used when setting up the Subscription in the Composable Commerce API. |
CONNECT_GCP_TOPIC_NAME | Event | GCP Pub/Sub topic name. Should be used when setting up the Subscription in the Composable Commerce API . |
preUndeploy
preUndeploy
runs before the Connector is undeployed and is useful when deleting unused resources from the Composable Commerce API.
Example service application
# connect.yaml# ...applicationType: servicescripts:postDeploy: node post-deploy.jspreUndeploy: node pre-undeploy.js# ...
// post-deploy.jsasync function run() {try {const EXTENSION_KEY = 'myconnector-extension-key';const serviceUrl = process.env.CONNECT_SERVICE_URL;// ...const result = await apiRoot.extensions().post({body: {key: EXTENSION_KEY,destination: {type: 'HTTP',url: serviceUrl,},triggers: [{resourceTypeId: 'cart',actions: ['Update'],},],},}).execute();} catch (error) {process.stderr.write(`Post-deploy failed: ${error.message}\n`);process.exitCode = 1;}}run();
// pre-undeploy.jsasync function run() {try {const EXTENSION_KEY = 'myconnector-extension-key';const serviceUrl = process.env.CONNECT_SERVICE_URL;// ...const result = await apiRoot.extensions().delete({body: {key: EXTENSION_KEY,},}).execute();} catch (error) {process.stderr.write(`Post-deploy failed: ${error.message}\n`);process.exitCode = 1;}}run();
Example event application
# connect.yaml# ...applicationType: eventscripts:postDeploy: node post-deploy.jspreUndeploy: node pre-undeploy.js# ...
// post-deploy.jsasync function run() {try {const SUBSCRIPTION_KEY = 'myconnector-subscription-key';const topicName = process.env.CONNECT_GCP_TOPIC_NAME;const projectId = process.env.CONNECT_GCP_PROJECT_ID;// ...const result = await apiRoot.subscriptions().post({body: {key: SUBSCRIPTION_KEY,destination: {type: 'GoogleCloudPubSub',topic: topicName,projectId,},messages: [{resourceTypeId: 'customer',types: ['CustomerCreated'],},],},}).execute();} catch (error) {process.stderr.write(`Post-deploy failed: ${error.message}\n`);process.exitCode = 1;}}run();
// pre-undeploy.jsasync function run() {try {const SUBSCRIPTION_KEY = 'myconnector-subscription-key';// ...const result = await apiRoot.subscriptions().delete({ body: { key: SUBSCRIPTION_KEY } }).execute();} catch (error) {process.stderr.write(`Post-deploy failed: ${error.message}\n`);process.exitCode = 1;}}run();
Testing your Connect application
It is mandatory to include tests for your Connect application. This is to ensure that your application codebase has a good level of quality to guarantee proper functionality and maintainability.
We recommend using a tool like Jest, which allows you to use multiple useful assertions and mocks, and gather code coverage.
// isInteger.jsconst isInteger = (value) => !isNaN(parseInt(value, 10));export { isInteger };
// __tests__/isInteger.spec.jsimport { isInteger } from './isInteger';describe('isInteger function', () => {test('it should check if value is an integer number', () => {expect(isInteger(-1)).toEqual(true);expect(isInteger(0)).toEqual(true);expect(isInteger(1).toEqual(true));expect(isInteger(1.5).toEqual(false));});});
npm testPASS __tests__/isInteger.spec.jsisInteger function✓ it should check if value is an integer number (2ms)Test Suites: 1 passed, 1 totalTests: 1 passed, 1 totalSnapshots: 0 totalTime: 0.764s, estimated 1s