The commercetools API provides a way to extend the behavior of an API with your own business logic. For instance, when you want to check if the content of a cart is valid, you can execute your own logic on the creation or update a cart. That update will be executed before the cart object is actually committed, making it an ideal solution for validation, additions, etc. In this article, I will describe how you can use API extensions with Deno, and how to run them from your laptop for demo or POC purposes.
API extensions
Within commercetools, you can register an API extension on the following resources: Carts, Orders, Payments, Customers, Quote Requests, Staged Quotes, Quotes and Business Units. The API extension can be triggered on the Create or Update of one of these resources. When you register an API extension for a resource, you will need to provide a destination address that will be called when the API extension is triggered. The destination can be an HTTPDestination, a GoogleCloudFunctionDestination or an AWSLambdaDestination. In this article, I will use the HTTPDestination that will point to a web server that I will host on my laptop.
When the cart extension is registered, it will call the extension every time when an update is made to the cart resource, regardless if the update is made through the API or, for instance, the Merchant Center. The called HTTP endpoint will receive the action and should reply with a statuscode of 200 to indicate that the validation succeeded. commercetools will then commit the cart object. If the response is a statuscode of 400, the transaction will be rolled back and an error will be thrown.
Registering a web server running on your laptop
With Deno, it's really easy to start a web server to listen to incoming requests using the Oak middleware:
When you run this with deno run --allow-net helloWorld.ts you have a web server that listens to any incoming request on port 8080 and will respond with a “hello world!” message.
But when you want to register an API extension in commercetools, that HTTP endpoint needs to be publicly accessible. Luckily there is an application called NGROK that can help. You can install NGROK locally on your machine (see: https://ngrok.com/download). Install NGROK, create an authentication token and run it using:
This will create a public HTTP address that forwards all incoming requests to it on port 8080 running on your machine.
To make this work a bit simpler, I created a small wrapper class that starts NGROK as a subprocess and gives you the public URL using the NGROK API. The only thing needed are the following two lines in your .env file:
The API key can be retrieved here: https://dashboard.ngrok.com/api
With NGROK installed and running we can proceed to the next step: Registering and unregistering the API extension.
Registering and unregistering the API extension
The whole process of registering an API extension is very well described in the API documentation of commercetools.
I created two methods for registering and unregistering:
This function takes a list of triggers and the destination, and creates the ExtensionDraft for it. The real registration for each trigger happens here (simplified for readability):
For unregistering:
I have put all these functions in a class to handle these.
The array of triggers, passed into these methods, have the following interface:
The base handler is a handler that will handle all messages, and take care of dispatching the right functions when a message is received. It will also take care of the various actions a specific handler might want to perform.
Running the API listener
The API listener can now be run using the following example:
When running this application with:
The following can be seen in the terminal:
When you make a change to a customer, the following will appear on the screen:
Here we can see, step by step, what is happening:
This creates a new API listener class that is able to listen to registered triggers. The triggers are registered with the following array of triggers:
This one trigger will listen to Create and Update messages on the customer resource. An incoming message will be handled by a CustomerHandler. To this customer handler, new sub handlers can be added. In this case, a customerLogMessage handler, is doing the following:
The handle method is called by the CustomerHandler and is returning a responseCode.SUCCSESS in this instance. All the typing for the resources is handled by iCustomerMessage and iCustomerResponse, so that intellisense is fully working in vscode.
Multiple handlers can be chained together so that multiple pieces of business logic can be executed on an API extension. The following example demonstrates setting a customer number on the customer object when it is not already set:
This extra function can be chained to the CustomerHandler in the following way:
When creating a new customer in commercetools, the following will now be shown in the terminal window:
The responses from the various sub handlers are all chained together. When one fails, all fail and a 400 is returned to commercetools. When multiple actions are returned, they are returned as one big action array.
This can really speed up the process of testing and validating API extensions with commercetools in a demo or POC scenario. In another of my following articles, I will use this module to build a couple of useful business scenarios that will illustrate the use of API extensions with real-life examples.
To learn about streamlining development with the Deno SDK, read my blog post A Deno SDK for commercetools.