Documentation
Feedback
Guides
App Development

App Development
ServicesDeveloping services on VTEX IO
3. Using the Analytics client

Now that we have successfully set up event listening, our next objective is to gain insights into the live number of views for each product page in our store whenever an event is triggered.

To achieve this, we will implement a custom client with analytics capabilities. This client will be responsible for retrieving information about a product's number of views from mocked data.

In VTEX IO, a client is responsible for establishing connections with external APIs and other VTEX services. The Analytics client, which will be developed in this step, will execute a REST request, fetching valuable information about product views.

Developing a custom client

Navigate to the service-course-template/node/clients/analytics.ts file. This is where the Analytics client will be implemented. Observe that the Analytics client extends the AppClient class from the @vtex/api package, ensuring secure communication configurations within your app.

service-course-template/node/clients/analytics.ts

_16
import { AppClient, InstanceOptions, IOContext } from '@vtex/api'
_16
_16
export default class Analytics extends AppClient {
_16
constructor(context: IOContext, options?: InstanceOptions) {
_16
super('vtex.mocked-analytics@0.x', context, options)
_16
}
_16
_16
public getLiveUsers(): Promise<LiveUsersProduct[]> {
_16
return this.http.get('_v/live-products')
_16
}
_16
}
_16
_16
interface LiveUsersProduct {
_16
slug: string
_16
liveUsers: number
_16
}

Defining a constructor

The client includes a constructor, a special method invoked when an object is instantiated from a class. Its primary purpose is to initialize the object's properties and perform any necessary setup, ensuring that the Analytics client can interact effectively with other parts of the app and the vtex.mocked-analytics app.

The vtex.mocked-analytics app provides mocked live products data via the /_v/live-products endpoint.

service-course-template/node/clients/analytics.ts

_16
import { AppClient, InstanceOptions, IOContext } from '@vtex/api'
_16
_16
export default class Analytics extends AppClient {
_16
constructor(context: IOContext, options?: InstanceOptions) {
_16
super('vtex.mocked-analytics@0.x', context, options)
_16
}
_16
_16
public getLiveUsers(): Promise<LiveUsersProduct[]> {
_16
return this.http.get('_v/live-products')
_16
}
_16
}
_16
_16
interface LiveUsersProduct {
_16
slug: string
_16
liveUsers: number
_16
}

Implementing the client's method

Proceed to implement the getLiveUsers method, responsible for making an HTTP GET request to the _v/live-products endpoint. This method returns a promise for fetching an array, with each element of type LiveUsersProduct - an object containing slug (product ID) and liveUsers (quantity of users viewing the product).

service-course-template/node/clients/analytics.ts

_16
import { AppClient, InstanceOptions, IOContext } from '@vtex/api'
_16
_16
export default class Analytics extends AppClient {
_16
constructor(context: IOContext, options?: InstanceOptions) {
_16
super('vtex.mocked-analytics@0.x', context, options)
_16
}
_16
_16
public getLiveUsers(): Promise<LiveUsersProduct[]> {
_16
return this.http.get('_v/live-products')
_16
}
_16
}
_16
_16
interface LiveUsersProduct {
_16
slug: string
_16
liveUsers: number
_16
}

Exporting the custom client

Expose the custom client by extending the default Clients implementation. Open the node/clients/index.ts file, import the analytics client, and update the Clients class as highlighted.

service-course-template/node/clients/analytics.ts
service-course-template/node/clients/index.ts

_10
import { IOClients } from '@vtex/api'
_10
import Analytics from '../clients/analytics'
_10
_10
// Extend the default IOClients implementation with our own custom clients.
_10
export class Clients extends IOClients {
_10
public get analytics() {
_10
return this.getOrSet('analytics', Analytics)
_10
}
_10
}

Using the custom client

Defining the handler function

With our new analytics client, let's update its handler function to display the output of the analytics client's getLiveUsers method. Go to the node/handlers/analytics.ts file and replace the content of ctx.body with the method developed in the previous steps (ctx.analytics.getLiveUsers()).

service-course-template/node/clients/analytics.ts
service-course-template/node/clients/index.ts
service-course-template/node/handlers/analytics.ts

_10
export async function analytics(ctx: Context, next: () => Promise<any>) {
_10
const {
_10
clients: { analytics },
_10
} = ctx
_10
ctx.status = 200
_10
ctx.body = await analytics.getLiveUsers()
_10
ctx.set('cache-control', 'no-cache')
_10
await next()
_10
}

Defining the service route

Go to the node/service.json file, and define a public route named analytics with the path /_v/app/analytics/realTime.

service-course-template/node/clients/analytics.ts
service-course-template/node/clients/index.ts
service-course-template/node/handlers/analytics.ts
service-course-template/node/service.json

_14
{
_14
"memory": 128,
_14
"ttl": 10,
_14
"timeout": 10,
_14
"minReplicas": 2,
_14
"maxReplicas": 10,
_14
"workers": 4,
_14
"routes": {
_14
"analytics": {
_14
"path": "/_v/app/analytics/realTime",
_14
"public": true
_14
}
_14
}
_14
}

Relating a route to a handler

Update the node/index.ts file to relate a route to a handler. Note that the routes section associates the analytics route with the analytics handler function. The GET method is associated with the analytics handler.

Therefore, when a GET request is made to the analytics route previously defined, it triggers the analytics handler function, which, in turn, executes the getLiveUsers() method of the Analytics client, providing real-time insights into product views.

service-course-template/node/clients/analytics.ts
service-course-template/node/clients/index.ts
service-course-template/node/handlers/analytics.ts
service-course-template/node/service.json
service-course-template/node/index.ts

_55
import {
_55
LRUCache,
_55
Service,
_55
ServiceContext,
_55
ParamsContext,
_55
RecorderState,
_55
method,
_55
} from '@vtex/api'
_55
import { Clients } from './clients'
_55
import { analytics } from './handlers/analytics'
_55
import { updateLiveUsers } from './event/liveUsersUpdate'
_55
_55
// Create a LRU memory cache for the Status client.
_55
// The @vtex/api HttpClient respects Cache-Control headers and uses the provided cache.
_55
const memoryCache = new LRUCache<string, any>({ max: 5000 })
_55
metrics.trackCache('status', memoryCache)
_55
_55
declare global {
_55
type Context = ServiceContext<Clients, State>
_55
_55
interface State extends RecorderState {
_55
code: number
_55
}
_55
}
_55
_55
const THREE_SECONDS_MS = 3 * 1000
_55
const CONCURRENCY = 10
_55
_55
export default new Service<Clients, State, ParamsContext>({
_55
clients: {
_55
implementation: Clients,
_55
options: {
_55
default: {
_55
retries: 2,
_55
timeout: 10000,
_55
},
_55
events: {
_55
exponentialTimeoutCoefficient: 2,
_55
exponentialBackoffCoefficient: 2,
_55
initialBackoffDelay: 50,
_55
retries: 1,
_55
timeout: THREE_SECONDS_MS,
_55
concurrency: CONCURRENCY,
_55
},
_55
},
_55
},
_55
events: {
_55
liveUsersUpdate: updateLiveUsers,
_55
},
_55
routes: {
_55
analytics: method({
_55
GET: [analytics],
_55
}),
_55
},
_55
})

Linking the app

To test the Analytics client, link your app using vtex link. Then, use Postman or curl to send a GET request to the designated route, replacing {workspace} with your workspace name and {accountName} with your VTEX account name.

The request should return status 200 OK and data in the same format as the example in the right.

service-course-template/node/clients/analytics.ts
service-course-template/node/clients/index.ts
service-course-template/node/handlers/analytics.ts
service-course-template/node/service.json
service-course-template/node/index.ts
cURL

_10
curl --location '{workspace}--{accountName}.myvtex.com/_v/app/analytics/realTime' \
_10
--header 'Cookie: janus_sid=fd2b4008-1241-483c-a8ef-bff9230fe63b'

Response

_10
[
_10
{
_10
"slug": "1926",
_10
"liveUsers": 3
_10
},
_10
{
_10
"slug": "1992",
_10
"liveUsers": 5
_10
}
_10
]

Developing a custom client

Navigate to the service-course-template/node/clients/analytics.ts file. This is where the Analytics client will be implemented. Observe that the Analytics client extends the AppClient class from the @vtex/api package, ensuring secure communication configurations within your app.

Defining a constructor

The client includes a constructor, a special method invoked when an object is instantiated from a class. Its primary purpose is to initialize the object's properties and perform any necessary setup, ensuring that the Analytics client can interact effectively with other parts of the app and the vtex.mocked-analytics app.

The vtex.mocked-analytics app provides mocked live products data via the /_v/live-products endpoint.

Implementing the client's method

Proceed to implement the getLiveUsers method, responsible for making an HTTP GET request to the _v/live-products endpoint. This method returns a promise for fetching an array, with each element of type LiveUsersProduct - an object containing slug (product ID) and liveUsers (quantity of users viewing the product).

Exporting the custom client

Expose the custom client by extending the default Clients implementation. Open the node/clients/index.ts file, import the analytics client, and update the Clients class as highlighted.

Using the custom client

Defining the handler function

With our new analytics client, let's update its handler function to display the output of the analytics client's getLiveUsers method. Go to the node/handlers/analytics.ts file and replace the content of ctx.body with the method developed in the previous steps (ctx.analytics.getLiveUsers()).

Defining the service route

Go to the node/service.json file, and define a public route named analytics with the path /_v/app/analytics/realTime.

Relating a route to a handler

Update the node/index.ts file to relate a route to a handler. Note that the routes section associates the analytics route with the analytics handler function. The GET method is associated with the analytics handler.

Therefore, when a GET request is made to the analytics route previously defined, it triggers the analytics handler function, which, in turn, executes the getLiveUsers() method of the Analytics client, providing real-time insights into product views.

Linking the app

To test the Analytics client, link your app using vtex link. Then, use Postman or curl to send a GET request to the designated route, replacing {workspace} with your workspace name and {accountName} with your VTEX account name.

The request should return status 200 OK and data in the same format as the example in the right.

service-course-template/node/clients/analytics.ts

_16
import { AppClient, InstanceOptions, IOContext } from '@vtex/api'
_16
_16
export default class Analytics extends AppClient {
_16
constructor(context: IOContext, options?: InstanceOptions) {
_16
super('vtex.mocked-analytics@0.x', context, options)
_16
}
_16
_16
public getLiveUsers(): Promise<LiveUsersProduct[]> {
_16
return this.http.get('_v/live-products')
_16
}
_16
}
_16
_16
interface LiveUsersProduct {
_16
slug: string
_16
liveUsers: number
_16
}

Contributors
2
Photo of the contributor
Photo of the contributor
+ 2 contributors
Was this helpful?
Yes
No
Suggest edits (Github)
Contributors
2
Photo of the contributor
Photo of the contributor
+ 2 contributors
On this page