Developing Clients
Learn how to develop custom Clients for seamless communication with other services.
If you need to integrate your VTEX IO app with external services that aren't covered by VTEX IO's native Clients, creating custom Clients can be a powerful solution. Custom Clients extend the functionality of VTEX IO Client types, offering benefits like caching and versioning. This guide will walk you through the process of creating custom Clients for your VTEX IO apps.
Note that direct communication with APIs is generally discouraged in favor of implementing a dedicated Client. By creating custom Clients, you can extend the capabilities of your VTEX IO applications, enabling seamless integration with a wide range of services.
The diagram below illustrates how an app works with a Client to an external service:
As you develop your custom Client, you will define methods within it. These Client methods are functions responsible for handling the logic needed to execute specific actions. They facilitate interactions with services and APIs, managing requests and responses effectively.
Once you've created your custom Client, you can seamlessly integrate it into your VTEX IO app to execute the implemented methods. While you have the flexibility to incorporate data-handling logic within your Client's methods (e.g., field mapping or data filtering), it's essential to keep the core responsibilities of the Client well-organized.
Before you begin
Before diving into Client development, make sure you have the following prerequisites in place:
- VTEX IO development workspace: Ensure you have a VTEX IO development workspace set up. For more information, refer to Creating a Development workspace.
- TypeScript Familiarity: This guide assumes you have a basic understanding of TypeScript, as we'll be using the
nodeBuilder to develop with TypeScript. For more information, refer to TypeScript's official documentation. - Understanding of Clients: Clients play a crucial role in facilitating interactions between your application and both external and internal services. For more information, refer to Clients.
Instructions
In this guide, we will create a custom Client example for communicating with GitHub APIs. We'll implement the following methods within our Client:
getRepo: Fetches a GitHub repository given the owner and repository name.getUser: Retrieves GitHub user data based on a specified GitHub username.createTag: Creates a new tag on GitHub, taking into account the repository owner, repository, and tag data.searchRepos: Searches for GitHub repositories using a specified query.
Step 1 - Setting up your VTEX IO app
-
Start a new VTEX IO app using the
nodebuilder and open the project using your preferred code editor. -
Open a terminal and navigate to the
nodefolder of your project._10cd node -
Install the
@vtex/apiand@octokit/restpackages by running the following command:_10yarn add @vtex/api @octokit/rest -
Open the app's
manifest.jsonfile and add the necessary Policies. Policies are a set of permissions granted to an app, allowing or forbidding it to execute a given set of actions, such as making requests to an external resource. For this example, we will use theoutbound-accesspolicy to communicate with GitHub APIs (api.github.com).Note that incorrect policies may result in request blocking.
Step 2 - Creating a custom Client
- Create a folder named
clientsinside thenodedirectory. - Create a TypeScript file for your Client in the
node/clientsdirectory. Choose a name that easily identifies your Client (e.g.,github.ts). - Implement the TypeScript class that extends the appropriate Client type from
@vtex/api. In this example, we will create theGithubClient. Also, since we are communicating with GitHub's external APIs, we will useExternalClient. - Use
InstanceOptionsas needed, configuring options such as authentication, timeout, caching, and more based on your requirements.
Ensure to export the Client from its module, either default or named export.
Step 3 - Implementing Client methods
Within your Client TypeScript file, implement the methods for your Client. You can leverage the methods provided by the HttpClient to build your own methods. For example:
Below we have the complete code example:
VTEX API core types:
IOContext: Contains the VTEX IO context data, such as account, workspace, locale, authentication token, etc.InstanceOptions: The options for configuring yourHttpClientinstance.ExternalClient: The base Client class for communicating with external APIs.
Type of the base Client that the custom Client extends from. Used to connect with external APIs.
A variable to store a map of routes for each method implemented in the Client. This structure is not mandatory, but it makes the code more readable when calling the HttpClient methods.
Configuration options to each request of this Client. It extends AxiosRequestConfig adding some IO-specific options. In this example, we are setting the number of retries and the Accept header to indicate the desired format to receive.
The metric parameter gives a name to identify each HTTP call for analytics purposes.
The getRaw method retrieves additional information about the response, such as headers. The get method retrieves only the response body.
The query parameters are passed using this format, resulting in ?q={{query}} being appended to the request's URL.
VTEX API core types:
IOContext: Contains the VTEX IO context data, such as account, workspace, locale, authentication token, etc.InstanceOptions: The options for configuring yourHttpClientinstance.ExternalClient: The base Client class for communicating with external APIs.
Type of the base Client that the custom Client extends from. Used to connect with external APIs.
A variable to store a map of routes for each method implemented in the Client. This structure is not mandatory, but it makes the code more readable when calling the HttpClient methods.
Configuration options to each request of this Client. It extends AxiosRequestConfig adding some IO-specific options. In this example, we are setting the number of retries and the Accept header to indicate the desired format to receive.
The metric parameter gives a name to identify each HTTP call for analytics purposes.
The getRaw method retrieves additional information about the response, such as headers. The get method retrieves only the response body.
The query parameters are passed using this format, resulting in ?q={{query}} being appended to the request's URL.
Step 4 - Exporting custom clients
Now that you've created your custom Client, you need to organize and export it for use in your VTEX IO service. Follow these steps:
-
Create an
index.tsfile in thenode/clientsfolder. -
Inside the
index.tsfile, import the custom Client you created in the previous step. For example:_10import GithubClient from "./github.ts"; -
Define a class called
Clientsthat extendsIOClients. This class is used to organize and configure your custom Clients. Within the Clients class, declare agetproperty for each of your custom Clients. This property allows you to access a specific Client by name. In our example, we've created a Client namedgithubthat uses theGithubClientclass._10import { IOClients } from "@vtex/api";_10import GithubClient from "./github.ts";_10_10export class Clients extends IOClients {_10public get github() {_10return this.getOrSet("github", GithubClient);_10}_10}
Now that you have developed and exported your custom Client to communicate with the desired service, your Clients can be accessed and used within your VTEX IO service to perform various tasks, such as interacting with external APIs like GitHub. Learn how to use Clients effectively in the Using Node Clients guide.
Client types
The @vtex/api package provides a structured way to create Clients.
| Type | Use case |
|---|---|
AppClient | Communication with other IO Services via HTTP calls. |
AppGraphQLClient | Communication with other IO GraphQL services. |
ExternalClient | Communication with external APIs. |
JanusClient | Communication with VTEX Core Commerce APIs through Janus Router. |
InfraClient | Communication with VTEX IO Infra services. |
Refer to the diagram below to better understand the relationship between Client types.
Note that context is of type IOContext and options is of type InstanceOptions.
InstanceOptions
The InstanceOptions table below provides a detailed description of the available options for configuring your HttpClient instance:
| Option | Description |
|---|---|
authType | Specifies the authentication type. |
timeout | Sets the request timeout duration in milliseconds. |
memoryCache | Configures a memory cache layer for caching data. |
diskCache | Configures a disk cache layer for caching data. |
baseURL | Defines the base URL for making requests. |
retries | Specifies the number of times a request should be retried in case of failure. |
exponentialTimeoutCoefficient | Configures the coefficient for exponential timeout backoff strategy. |
initialBackoffDelay | Sets the initial delay before starting exponential backoff retries in milliseconds. |
exponentialBackoffCoefficient | Configures the coefficient for exponential backoff retries. |
metrics | Specifies an object for accumulating metrics related to requests. |
concurrency | Defines the maximum number of concurrent requests. |
headers | Sets default headers to be sent with every request. |
params | Sets default query string parameters to be sent with every request. |
middlewares | Configures an array of middleware functions for request processing. |
verbose | Enables or disables verbose logging for requests and responses. |
name | Defines a custom name for the instance. |
serverTimings | Sets server timings for measuring request and response times. |
httpsAgent | Configures the HTTPS agent for making requests over SSL/TLS. |
HttpClient methods
Below is a table outlining the methods available in the HttpClient class:
| Method | Description |
|---|---|
get(url: string, config?: RequestConfig) | Sends an HTTP GET request. Returns only the response body. |
getRaw(url: string, config?: RequestConfig) | Sends an HTTP GET request. Returns all the response data. |
getWithBody(url: string, data?: any, config?: RequestConfig) | Sends an HTTP GET request with a request body. |
getBuffer(url: string, config?: RequestConfig) | Sends an HTTP GET request and resolves with the response data as a buffer along with the headers. |
getStream(url: string, config?: RequestConfig) | Sends an HTTP GET request and resolves with the response as a readable stream (of type IncomingMessage). |
put(url: string, data?: any, config?: RequestConfig) | Sends an HTTP PUT request. Returns only the response body. |
putRaw(url: string, data?: any, config?: RequestConfig) | Sends an HTTP PUT request. Returns all the response data. |
post(url: string, data?: any, config?: RequestConfig) | Sends an HTTP POST request. Returns only the response body. |
postRaw(url: string, data?: any, config?: RequestConfig) | Sends an HTTP POST request. Returns all the response data. |
patch(url: string, data?: any, config?: RequestConfig) | Sends an HTTP PATCH request. Returns only the response body. |
head(url: string, config?: RequestConfig) | Sends an HTTP HEAD request and resolves when the request is complete. |
delete(url: string, config?: RequestConfig) | Sends an HTTP DELETE request. |