Documentation
Feedback
Guides
App Development

App Development
ServicesDeveloping services on VTEX IO
5. Using the Master Data client

Now that we are actively using the data retrieved from Analytics, the next crucial step is to persist and update this data. To achieve this, we'll leverage Master Data, a database-as-a-service product from VTEX.

Master Data is the foundation for creating database architectures within a VTEX store. Initially designed for storing and organizing customer data, it has evolved into a versatile tool widely utilized by VTEX stores for business rule customizations and creating apps. The @vtex/api package provides a native Master Data client, accessible through ctx.clients.masterdata.

In this step, Master Data will be used to fetch data regarding the top N most viewed products, where N is a parameter that will be used to get the desired number of products.

Master Data uses the concept of data entities and JSON Schema to validate and index documents. One data entity can have many schemas, depending on how you need to use the data stored.

Creating a Master Data entity

First, you will use the Master Data API to create an entity and new schema in Master Data to save your product list. Use Postman or any other API client you prefer to send the cURL request presented in the right panel, providing the following information:

  • accountName: Name of your VTEX account.
  • data_entity_name: Name of the data entity to be created in Master Data. Use course_backend_product_list to be consistent with our app.
  • schema_name: Name of the schema to be created in Master Data. Use v1 to be consistent with our app (identical to the one used in service-course-template/node/event/updateLiveUsers.ts).
  • userToken: Value of your user authentication cookie. To get your VTEX local token, run vtex local token in your terminal.
cURL

_32
curl --location --request PUT 'https://{{accountName}}.vtexcommercestable.com.br/api/dataentities/{{data_entity_name}}/schemas/{{schema_name}}' \
_32
--header 'Content-Type: application/json' \
_32
--header 'VtexIdclientAutCookie: {{userToken}}' \
_32
--data '{
_32
"properties": {
_32
"slug": {
_32
"type": "string"
_32
},
_32
"count": {
_32
"type": "number"
_32
}
_32
},
_32
"v-indexed": [
_32
"slug",
_32
"count"
_32
],
_32
"v-security": {
_32
"allowGetAll": true,
_32
"publicRead": [
_32
"slug",
_32
"count"
_32
],
_32
"publicWrite": [
_32
"slug",
_32
"count"
_32
],
_32
"publicFilter": [
_32
"slug",
_32
"count"
_32
]
_32
}
_32
}'

Response

_10
{
_10
"Message": "JSON Schema persisted successfully. Revalidation and indexing process running in background."
_10
}

Saving data to Master Data

Now, to save the data, we need to check if the productSlug is already saved in Master Data. Use the searchDocuments method of the Master Data client in the node/event/liveUsersUpdate.ts file, as highlighted in the provided code.

Note: The COURSE_ENTITY global constant is course_backend_product_list, the name of our Master Data schema.

cURL
service-course-template/node/event/liveUsersUpdate.ts

_28
import { Clients } from '../clients/index'
_28
import { EventContext } from '@vtex/api'
_28
import { COURSE_ENTITY } from '../utils/constants'
_28
_28
export async function updateLiveUsers(ctx: EventContext<Clients>) {
_28
const liveUsersProducts = await ctx.clients.analytics.getLiveUsers()
_28
console.log('LIVE USERS: ', liveUsersProducts)
_28
await Promise.all(
_28
liveUsersProducts.map(async ({ slug, liveUsers }) => {
_28
const [savedProduct] = await ctx.clients.masterdata.searchDocuments<{
_28
id: string
_28
count: number
_28
slug: string
_28
}>({
_28
dataEntity: COURSE_ENTITY,
_28
fields: ['count', 'id', 'slug'],
_28
pagination: {
_28
page: 1,
_28
pageSize: 1,
_28
},
_28
schema: 'v1',
_28
where: `slug=${slug}`,
_28
})
_28
console.log('SAVED PRODUCT', savedProduct)
_28
})
_28
)
_28
return true
_28
}

Handling errors and exceptions

To ensure proper error handling, implement a try-catch structure, as presented in the code to the right.

cURL
service-course-template/node/event/liveUsersUpdate.ts

_33
import { Clients } from '../clients/index'
_33
import { EventContext } from '@vtex/api'
_33
import { COURSE_ENTITY } from '../utils/constants'
_33
_33
export async function updateLiveUsers(ctx: EventContext<Clients>) {
_33
const liveUsersProducts = await ctx.clients.analytics.getLiveUsers()
_33
console.log('LIVE USERS: ', liveUsersProducts)
_33
await Promise.all(
_33
liveUsersProducts.map(async ({ slug, liveUsers }) => {
_33
try {
_33
const [savedProduct] = await ctx.clients.masterdata.searchDocuments<{
_33
id: string
_33
count: number
_33
slug: string
_33
}>({
_33
dataEntity: COURSE_ENTITY,
_33
fields: ['count', 'id', 'slug'],
_33
pagination: {
_33
page: 1,
_33
pageSize: 1,
_33
},
_33
schema: 'v1',
_33
where: `slug=${slug}`,
_33
})
_33
console.log('SAVED PRODUCT', savedProduct)
_33
} catch (e) {
_33
console.log(`failed to update product ${slug}`)
_33
console.log(e)
_33
}
_33
})
_33
)
_33
return true
_33
}

Updating existing documents

If a product is already saved, we need to update it by incrementing its count. The Master Data client provides the createOrUpdateEntireDocument method for this purpose. Implement the incrementation in the Master Data entity in the liveUsersUpdate.ts file, right after the console.log({savedProduct}) line.

cURL
service-course-template/node/event/liveUsersUpdate.ts

_42
import { Clients } from '../clients/index'
_42
import { EventContext } from '@vtex/api'
_42
import { COURSE_ENTITY } from '../utils/constants'
_42
_42
export async function updateLiveUsers(ctx: EventContext<Clients>) {
_42
const liveUsersProducts = await ctx.clients.analytics.getLiveUsers()
_42
console.log('LIVE USERS: ', liveUsersProducts)
_42
await Promise.all(
_42
liveUsersProducts.map(async ({ slug, liveUsers }) => {
_42
try {
_42
const [savedProduct] = await ctx.clients.masterdata.searchDocuments<{
_42
id: string
_42
count: number
_42
slug: string
_42
}>({
_42
dataEntity: COURSE_ENTITY,
_42
fields: ['count', 'id', 'slug'],
_42
pagination: {
_42
page: 1,
_42
pageSize: 1,
_42
},
_42
schema: 'v1',
_42
where: `slug=${slug}`,
_42
})
_42
console.log('SAVED PRODUCT', savedProduct)
_42
await ctx.clients.masterdata.createOrUpdateEntireDocument({
_42
dataEntity: COURSE_ENTITY,
_42
fields: {
_42
count: liveUsers,
_42
slug,
_42
},
_42
id: savedProduct?.id,
_42
schema: 'v1'
_42
})
_42
} catch (e) {
_42
console.log(`failed to update product ${slug}`)
_42
console.log(e)
_42
}
_42
})
_42
)
_42
return true
_42
}

Linking the app

Finally, run vtex link and wait for an event to be fired. Once it does, check your terminal for the logs in the code.

Break the vtex link by typing ctrl + C and use the provided cURL command to inspect the updates on Master Data. Replace {{accountName}} with your VTEX account name.

To run a cURL on Windows, ensure to replace single quotes (') with double quotes ("). For Windows versions earlier than Windows 10 (version 1803), download and install cURL.

cURL
service-course-template/node/event/liveUsersUpdate.ts
curl

_10
curl --location --request GET 'https://api.vtex.com/api/dataentities/course_backend_product_list/search?_fields=slug,count&_schema=v1&an={{accountName}}' \
_10
--header 'Content-Type: application/json'

Response

_10
[{"slug": "1762", "count" : 10}, {"slug": "1461", "count" :4}, {"slug" :"1581", "count" :1}, {"slug": "1663", "count": 6}, {"slug": "1705", "count" : 1}, {"slug": "1806", "count" :5}, {"slug": "1154", "count": 8}, {"slug": "1472", "count" :6}, {"slug": "1317", "count" :8}, {"slug": "1336", "count" :9}, {"slug": "1968", "count" :2}, {"slug": "1472", "count" :3}, {"slug": "1252", "count" :3}, {"slug": "1066", "count" : 1}, {"slug":"1140", "count" :3}]

Creating a Master Data entity

First, you will use the Master Data API to create an entity and new schema in Master Data to save your product list. Use Postman or any other API client you prefer to send the cURL request presented in the right panel, providing the following information:

  • accountName: Name of your VTEX account.
  • data_entity_name: Name of the data entity to be created in Master Data. Use course_backend_product_list to be consistent with our app.
  • schema_name: Name of the schema to be created in Master Data. Use v1 to be consistent with our app (identical to the one used in service-course-template/node/event/updateLiveUsers.ts).
  • userToken: Value of your user authentication cookie. To get your VTEX local token, run vtex local token in your terminal.

Saving data to Master Data

Now, to save the data, we need to check if the productSlug is already saved in Master Data. Use the searchDocuments method of the Master Data client in the node/event/liveUsersUpdate.ts file, as highlighted in the provided code.

Note: The COURSE_ENTITY global constant is course_backend_product_list, the name of our Master Data schema.

Handling errors and exceptions

To ensure proper error handling, implement a try-catch structure, as presented in the code to the right.

Updating existing documents

If a product is already saved, we need to update it by incrementing its count. The Master Data client provides the createOrUpdateEntireDocument method for this purpose. Implement the incrementation in the Master Data entity in the liveUsersUpdate.ts file, right after the console.log({savedProduct}) line.

Linking the app

Finally, run vtex link and wait for an event to be fired. Once it does, check your terminal for the logs in the code.

Break the vtex link by typing ctrl + C and use the provided cURL command to inspect the updates on Master Data. Replace {{accountName}} with your VTEX account name.

To run a cURL on Windows, ensure to replace single quotes (') with double quotes ("). For Windows versions earlier than Windows 10 (version 1803), download and install cURL.

cURL

_32
curl --location --request PUT 'https://{{accountName}}.vtexcommercestable.com.br/api/dataentities/{{data_entity_name}}/schemas/{{schema_name}}' \
_32
--header 'Content-Type: application/json' \
_32
--header 'VtexIdclientAutCookie: {{userToken}}' \
_32
--data '{
_32
"properties": {
_32
"slug": {
_32
"type": "string"
_32
},
_32
"count": {
_32
"type": "number"
_32
}
_32
},
_32
"v-indexed": [
_32
"slug",
_32
"count"
_32
],
_32
"v-security": {
_32
"allowGetAll": true,
_32
"publicRead": [
_32
"slug",
_32
"count"
_32
],
_32
"publicWrite": [
_32
"slug",
_32
"count"
_32
],
_32
"publicFilter": [
_32
"slug",
_32
"count"
_32
]
_32
}
_32
}'

Response

_10
{
_10
"Message": "JSON Schema persisted successfully. Revalidation and indexing process running in background."
_10
}

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