diff --git a/content/en-us/cloud/open-cloud/usage-data-stores.md b/content/en-us/cloud/open-cloud/usage-data-stores.md index ef9d64d76..7fd055fba 100644 --- a/content/en-us/cloud/open-cloud/usage-data-stores.md +++ b/content/en-us/cloud/open-cloud/usage-data-stores.md @@ -78,6 +78,9 @@ When [creating an API Key](./api-keys.md) for this example, make sure you perfor #### Add scripts for the user inventory support portal +
+ Click for Python Example + After creating the API key with permissions required for the example app, you need to add Python scripts to perform app functionalities. The `data_stores_methods.py` file shows how to define [`List Entries`](../../reference/cloud/datastores-api/v1.json#list-entries), [`Get Entry`](../../reference/cloud/datastores-api/v1.json#get-entry), and [`Increment Entry`](../../reference/cloud/datastores-api/v1.json#increment-entry) methods. The `update_inventory` file uses the defined methods to list a subset of user inventories, increase the virtual currency for each user, and update the data. ```python title='data_stores_methods.py' @@ -186,6 +189,102 @@ To test, set the `API_KEY` environment variable and run `update_inventory` file: export API_KEY=... \ python update_inventory ``` + +
+ +
+ Click for JavaScript Example + +After creating the API key with the required permissions for the example app, you need to add JavaScript code to perform app functionalities. The `data_stores_methods.js` file shows how to define [`List Entries`](../../reference/cloud/datastores-api/v1.json#list-entries), [`Get Entry`](../../reference/cloud/datastores-api/v1.json#get-entry), and [`Increment Entry`](../../reference/cloud/datastores-api/v1.json#increment-entry) methods. The `update_inventory.js` file uses the defined methods to list a subset of user inventories, increase the virtual currency for each user, and update the data. + +```javascript title='dataStoresMethods.js' +const fetch = require('node-fetch'); + +class DataStores { + constructor() { + this._baseUrl = "https://apis.roblox.com/datastores/v1/universes/{universeId}"; + this._apiKey = process.env.API_KEY; + this._universeId = "UNIVERSE_ID"; + this.ATTR_HDR = 'Roblox-entry-Attributes'; + this.USER_ID_HDR = 'Roblox-entry-UserIds'; + this._objectsUrl = `${this._baseUrl}${this._universeId}/standard-datastores/datastore/entries/entry`; + this._incrementUrl = `${this._objectsUrl}/increment`; + this._listObjectsUrl = `${this._baseUrl}${this._universeId}/standard-datastores/datastore/entries`; + } + + async _getHeaders() { + return { 'x-api-key': this._apiKey }; + } + + async getEntry(datastore, objectKey, scope = null) { + const url = `${this._objectsUrl}?datastoreName=${datastore}&entryKey=${objectKey}&scope=${scope || ''}`; + const response = await fetch(url, { headers: await this._getHeaders() }); + const data = await response.json(); + return data; + } + + async listEntries(datastore, scope = null, prefix = "", limit = 100) { + const url = `${this._listObjectsUrl}?datastoreName=${datastore}&scope=${scope}&prefix=${prefix}&limit=${limit}`; + const response = await fetch(url, { headers: await this._getHeaders() }); + const data = await response.json(); + return data; + } + + async incrementEntry(datastore, objectKey, incrementBy, scope = null) { + const url = `${this._incrementUrl}?datastoreName=${datastore}&entryKey=${objectKey}&incrementBy=${incrementBy}&scope=${scope || ''}`; + const response = await fetch(url, { method: 'POST', headers: await this._getHeaders() }); + const data = await response.json(); + return data; + } +} + +module.exports = DataStores; +``` + +```javascript title='updateInventory.js' +const DataStores = require('./dataStoresMethods'); +const dataStoresApi = new DataStores(); + +// Set up +const datastoreName = "Inventory"; + +// List keys for a subset of users +dataStoresApi.listEntries(datastoreName) + .then(keys => { + console.log(keys); + }); + +// Read inventory for each user +for (let x = 0; x < 5; x++) { + const updatedObjectKey = `User_${x + 1}`; + dataStoresApi.getEntry(datastoreName, updatedObjectKey) + .then(value => { + console.log(`${updatedObjectKey} has ${value.gems} gems in their inventory`); + }); +} + +// Update the currency of each user by 10 +for (let x = 0; x < 5; x++) { + const updatedObjectKey = `User_${x + 1}`; + dataStoresApi.incrementEntry(datastoreName, updatedObjectKey, 10) + .then(value => { + console.log(`${updatedObjectKey} now has ${value.robux} robux in their inventory`); + }); +} +``` + +To test, set the `API_KEY` environment variable and run the JavaScript file: + +```bash +export API_KEY=... \ +node updateInventory.js +``` + +
+ +### External Persistent Leaderboard + +======= ### External persistent leaderboard @@ -219,6 +318,9 @@ When [creating an API Key](./api-keys.md) for this example, make sure you perfor #### Add scripts for the leaderboard +
+Click for Python Example + After creating the API key with permissions required for the example app, you need to add Python scripts to perform app functionalities. The `ordered_data_stores.py` file shows how to define [`List`](../../reference/cloud/datastores-api/ordered-v1.json#list), [`Create`](../../reference/cloud/datastores-api/ordered-v1.json#create), [`Update`](../../reference/cloud/datastores-api/ordered-v1.json#update) and [`Increment`](../../reference/cloud/datastores-api/ordered-v1.json#increment) methods. The `leaderboard` file uses the defined methods to create entries of users in ordered data stores, display scores, increment scores of winning users, and update the leaderboard. The `leaderboard` file also imports a `config` JSON file for configuring the Universe ID, API domain, and your API key. @@ -308,3 +410,105 @@ python leaderboard ``` After completing testing, you can publish or embed the leaderboard to websites outside of Roblox for more reach. + +
+ +
+Click for JavaScript Example + +After creating the API key with the required permissions for the example app, you need to add JavaScript code to perform app functionalities. + +The `ordered_data_stores.js` file shows how to define [`List`](../../reference/cloud/datastores-api/ordered-v1.json#list), [`Create`](../../reference/cloud/datastores-api/ordered-v1.json#create), [`Update`](../../reference/cloud/datastores-api/ordered-v1.json#update), and [`Increment`](../../reference/cloud/datastores-api/ordered-v1.json#increment) methods. The `leaderboard.js` file uses the defined methods to create entries of users in ordered data stores, display scores, increment scores of winning users, and update the leaderboard. The `leaderboard.js` file also imports a `config.json` file for configuring the Universe ID, API domain, and your API key. + +```javascript title='ordered_data_stores.js' +const axios = require('axios'); +const fs = require('fs'); + +class DataStores { + constructor(configFile) { + this._config = JSON.parse(fs.readFileSync(configFile, 'utf-8')); + } + + _H() { + return { 'x-api-key': this._config.api_key, 'Content-Type': 'application/json' }; + } + + async list(datastore, scope, pageSize = 10, orderBy = "", filter = "", exclusiveStartKey = "") { + const url = `${this._config.api_key_url}universes/${this._config.universe_id}/orderedDataStores/${datastore}/scopes/${scope}/entries`; + const response = await axios.get(url, { + headers: this._H(), + params: { "max_page_size": pageSize, "order_by": orderBy, "filter": filter, "page_token": exclusiveStartKey } + }); + return response.data; + } + + async create(datastore, scope, entry, data) { + const url = `${this._config.api_key_url}universes/${this._config.universe_id}/orderedDataStores/${datastore}/scopes/${scope}/entries`; + const payload = JSON.stringify({ "value": 11 }); + const response = await axios.post(url, payload, { + headers: this._H(), + params: { "id": entry } + }); + return response.data; + } + + async increment(datastore, scope, entry, incrementBy) { + const url = `${this._config.api_key_url}universes/${this._config.universe_id}/orderedDataStores/${datastore}/scopes/${scope}/entries/${entry}:increment`; + const payload = JSON.stringify({ "amount": incrementBy }); + const response = await axios.post(url, payload, { headers: this._H() }); + return response.data; + } +} +``` + +```javascript title='leaderboard.js' +const leaderboardEndpoints = require('./ordered_data_stores'); + +const datastores = new leaderboardEndpoints.DataStores('config.json'); + +// Variables +const orderedDataStore = 'PlayerScores'; +const scope = 'global'; +const entryNames = ['Ragdoll', 'Balinese', 'Tabby', 'Siamese']; + +// Create an entry and give each new player 50 points for joining the game +entryNames.forEach(async (name) => { + await datastores.create(orderedDataStore, scope, name, 50); +}); + +// Display the players' scores +datastores.list(orderedDataStore, scope).then((playerScores) => { + console.log(playerScores); +}); + +// Increment the first player's score for winning the game +datastores.increment(orderedDataStore, scope, entryNames[0], 100); + +// Increment all the players' scores for participating in the game +entryNames.forEach(async (name) => { + await datastores.increment(orderedDataStore, scope, name, 10); +}); + +// Display the updated leaderboard +datastores.list(orderedDataStore, scope).then((updatedPlayerScores) => { + console.log(updatedPlayerScores); +}); +``` + +```json title='config' +{ + "universe_id": "", + "api_key_url": "https://apis.roblox.com/datastores/ordered-v1/", + "api_key": "" +} +``` + +To test, set the `API_KEY` environment variable and run the `leaderboard.js` file: + +```bash +export API_KEY=... \ +node leaderboard.js +``` + +After completing testing, you can publish or embed the leaderboard to websites outside of Roblox for more reach. +