En plus d'accéder aux magasins de données depuis l'API Engine dans Studio ou dans des jeux en direct (DataStoreService), vous pouvez utiliser les API Open Cloud pour accéder aux magasins de données standard et aux magasins de données ordonnés depuis des scripts externes et d'autres outils.
L'accès aux magasins de données via Open Cloud ouvre de nombreux cas d'utilisation potentiels, notamment :
- Un portail de support client qui permet à votre équipe de gérer directement les demandes de support, comme la modification des inventaires d'utilisateur ou l'émission de remboursements
- Des classements mondiaux que vous pouvez afficher sur un site web externe
- Des mises à jour de schéma avec des scripts qui lisent des entrées du magasin de données actuel, les mappent vers le nouveau schéma et réécrivent les entrées dans un nouveau magasin de données
Les exemples de cette page démontrent comment construire un portail de support d'inventaire utilisateur et un tableau de classement externe avec Node.js et Python, mais utilisez le langage que vous préférez ; les API Open Cloud supportent tout langage de programmation capable d'envoyer une requête HTTP.
Différences avec l'API Engine
Bien que les API Open Cloud accèdent aux mêmes magasins de données sous-jacents et soient similaires à l'utilisation de DataStoreService, il existe quelques différences clés :
ID de l'univers : Contrairement à l'API Engine, les API Open Cloud sont sans état et peuvent provenir de n'importe où, donc vous devez toujours fournir l'ID de l'univers, l'identifiant unique de votre jeu.
Permissions séparées pour la création et la mise à jour : L'API Engine crée de nouvelles entrées si elles n'existent pas lorsque vous appelez DataStore:SetAsync(), mais les méthodes Open Cloud pour créer et mettre à jour des entrées sont séparées. Des permissions séparées peuvent être plus sûres et plus flexibles dans certaines situations. Par exemple, vous voudrez peut-être que votre outil de support client ne puisse que modifier le profil d'un utilisateur existant, pas en créer un nouveau.
Sérialisation des données : Tous les points de terminaison Open Cloud nécessitent que vous sérialisiez les données avant de les envoyer. La sérialisation signifie convertir un objet en une chaîne. La désérialisation est l'inverse, convertir une chaîne en un objet. L'API Engine sérialise et désérialise automatiquement le contenu des entrées, mais pour Open Cloud, vous devez générer ou analyser votre entrée en JSON par vous-même.
Permissions
Les magasins de données stockent souvent des informations sensibles, telles que des profils d'utilisateur et de la monnaie virtuelle. Pour maintenir la sécurité, chaque méthode Open Cloud a des permissions correspondantes, appelées scopes, que vous devez ajouter à votre clé API, comme le scope universe-datastores.control:list pour la méthode Lister les magasins de données. Si vous n'ajoutez pas les permissions requises, votre appel API renverra une erreur. Consultez la documentation de référence pour les scopes requis pour chaque point de terminaison.
Pour plus d'informations sur la gestion des permissions, voir Gérer les clés API.
Portail de support d'inventaire utilisateur
Cet exemple utilise un magasin de données nommé Inventory et un schéma pour chaque entrée de "userId": {"currency": number, "weapon": string, "level": number}. La clé est userId.
Scopes requis
Lors de la création d'une clé API pour cet exemple, ajoutez les scopes suivants à votre clé :
- universe-datastores.objects:list
- universe-datastores.objects:read
- universe-datastores.objects:update
Optionnellement, ajoutez les permissions uniquement pour le magasin de données Inventory, définissez une restriction d'adresse IP et fixez une date d'expiration.
Ajouter des scripts pour le portail de support d'inventaire utilisateur
Après avoir créé la clé API avec les permissions nécessaires pour l'application exemple, vous pouvez créer un script pour envoyer des requêtes aux points de terminaison. Ces scripts obtiennent les 10 premières entrées dans le magasin de données, incrémentent la valeur currency de 10 pour chacune, puis mettent à jour chaque entrée. Pour un magasin de données plus grand, vous devrez gérer la pagination en utilisant les paramètres de requête maxPageSize et pageToken.
incrementCurrency.js
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('La variable d\'environnement API_KEY n\'est pas définie.');
}
const apiHeaderKey = 'x-api-key';
const universeId = '';
const dataStoreId = 'Inventory';
const baseUrl = 'https://apis.roblox.com/cloud/v2/';
async function listEntries(universe, dataStore) {
const listPath = `universes/${universe}/data-stores/${dataStore}/entries`;
const url = baseUrl + listPath;
const response = await fetch(url, {
headers: { [apiHeaderKey]: apiKey }
});
return response.json();
}
async function getEntry(path) {
const url = baseUrl + path;
const response = await fetch(url, {
headers: { [apiHeaderKey]: apiKey }
});
return response.json();
}
async function updateEntry(path, payload) {
const url = baseUrl + path;
const response = await fetch(url, {
method: 'PATCH',
headers: {
[apiHeaderKey]: apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload) // Le corps doit être une chaîne
});
return response;
}
(async () => {
try {
const entries = await listEntries(universeId, dataStoreId);
for (const entry of entries.dataStoreEntries) {
const path = entry.path;
console.log(`\nTraitement de l'entrée : ${path}`);
const currentData = await getEntry(path);
currentData.value.currency += 10;
const payload = { value: currentData.value };
const updateResponse = await updateEntry(path, payload);
console.log(`Statut : ${updateResponse.status}`);
console.log(`Réponse : ${await updateResponse.text()}`);
}
} catch (error) {
console.error('Une erreur est survenue pendant l\'exécution :', error);
}
})();
Pour tester, définissez la variable d'environnement API_KEY, installez les dépendances, et exécutez le script :
export API_KEY=<your_key>node incrementCurrency.js
Tableau de classement externe persistant
Cet exemple crée une liste prédéfinie d'utilisateurs à des fins de démonstration, mais pour qu'elle soit utile dans un vrai jeu, vous auriez besoin d'un réel magasin de données d'utilisateurs.
Scopes requis
Lors de la création d'une clé API pour cet exemple, ajoutez les scopes suivants à votre clé :
- universe.ordered-data-store.scope.entry:read
- universe.ordered-data-store.scope.entry:write
Ajouter des scripts pour le tableau de classement
Après avoir créé la clé API avec les permissions nécessaires pour l'application exemple, vous pouvez créer un script pour envoyer des requêtes aux points de terminaison. Ces scripts ajoutent quelques entrées d'exemple au magasin de données ordonné avec des nombres aléatoires, puis les récupèrent par ordre de valeur décroissante. Pour un magasin de données plus grand, vous devrez gérer la pagination en utilisant les paramètres de requête maxPageSize et pageToken.
leaderboard.js
const apiKey = process.env.API_KEY;
const apiHeaderKey = 'x-api-key';
const universeId = '';
const orderedDataStoreId = 'PlayerScores';
const scopeId = 'global';
const baseUrl = 'https://apis.roblox.com/cloud/v2/';
async function createOrderedEntry(universe, orderedDataStore, entryId, payload) {
const createPath = `universes/${universe}/ordered-data-stores/${orderedDataStore}/scopes/${scopeId}/entries`;
const url = new URL(baseUrl + createPath);
url.searchParams.append('id', entryId);
const response = await fetch(url, {
method: 'POST',
headers: {
[apiHeaderKey]: apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Erreur API (${response.status}) : ${errorText}`);
}
return response.text();
}
async function listOrderedEntries(universe, orderedDataStore) {
const listPath = `universes/${universe}/ordered-data-stores/${orderedDataStore}/scopes/${scopeId}/entries`;
const url = new URL(baseUrl + listPath);
url.searchParams.append('orderBy', 'value desc');
return fetch(url, {
headers: {
[apiHeaderKey]: apiKey,
},
});
}
async function main() {
if (!apiKey) {
console.error('Erreur : La variable d\'environnement API_KEY n\'est pas définie.');
process.exit(1);
}
const entryNames = ['Ragdoll', 'Balinese', 'Tabby', 'Siamese'];
console.log('Création de données d\'exemple...');
for (const name of entryNames) {
try {
const randomValue = Math.floor(Math.random() * 50) + 1;
const payload = { value: randomValue };
const responseText = await createOrderedEntry(universeId, orderedDataStoreId, name, payload);
console.log(responseText);
} catch (error) {
console.error(`Échec de la création de l'entrée pour "${name}" : ${error.message}`);
}
}
console.log('\nObtention de la liste triée des entrées...');
try {
const playerScoresResponse = await listOrderedEntries(universeId, orderedDataStoreId);
console.log(playerScoresResponse.status);
const responseText = await playerScoresResponse.text();
console.log(responseText);
} catch (error) {
console.error(`Échec de la liste des entrées : ${error.message}`);
}
}
main();
Pour tester, définissez la variable d'environnement API_KEY, installez les dépendances, et exécutez le script :
export API_KEY=<your_key>node leaderboard.js