Oprócz uzyskiwania dostępu do magazynów danych z interfejsu API silnika w Studio lub w doświadczeniach na żywo (DataStoreService), możesz używać interfejsów API Open Cloud do uzyskiwania dostępu do standardowych i posortowanych magazynów danych z zewnętrznych skryptów i innych narzędzi.
Dostęp do magazynów danych w chmurze otwiera wiele potencjalnych zastosowań, w tym:
- Portal wsparcia klienta, który pozwala zespołowi bezpośrednio obsługiwać zgłoszenia wsparcia, takie jak modyfikowanie inwentarzy użytkowników lub wydawanie zwrotów
- Globalne tabele liderów, które możesz wyświetlić na zewnętrznej stronie internetowej
- Aktualizacje schematów za pomocą skryptów, które odczytują wpisy z bieżącego magazynu danych, mapują je na nowy schemat i zapisują wpisy z powrotem do nowego magazynu danych
Przykłady na tej stronie pokazują, jak zbudować portal wsparcia inwentarza użytkownika i zewnętrzną tabelę liderów przy użyciu Node.js i Pythona, ale użyj dowolnego języka, który preferujesz; interfejsy API Open Cloud obsługują dowolny język programowania, który może wysłać żądanie HTTP.
Różnice między interfejsem API silnika
Chociaż interfejsy API Open Cloud uzyskują dostęp do tych samych podstawowych magazynów danych i są podobne do pracy z DataStoreService, istnieje kilka kluczowych różnic:
Identyfikator uniwersum: W przeciwieństwie do interfejsu API silnika, interfejsy API Open Cloud są bezstanowe i mogą pochodzić z dowolnego miejsca, dlatego zawsze musisz podać identyfikator uniwersum, unikalny identyfikator twojego doświadczenia.
Oddzielne uprawnienia do tworzenia i aktualizacji: Interfejs API silnika tworzy nowe wpisy, jeśli nie istnieją, gdy wywołasz DataStore:SetAsync(), ale metody Open Cloud do tworzenia i aktualizacji wpisów są oddzielne. Oddzielne uprawnienia mogą być bezpieczniejsze i bardziej elastyczne w niektórych sytuacjach. Na przykład możesz chcieć, aby twoje narzędzie wsparcia klienta mogło tylko edytować profil istniejącego użytkownika, a nie tworzyć nowego.
Serializacja danych: Wszystkie punkty końcowe Open Cloud wymagają, abyś zserializował dane przed ich wysłaniem. Serializacja oznacza konwersję obiektu na ciąg znaków. Deserializacja to przeciwieństwo, konwersja ciągu znaków na obiekt. Interfejs API silnika automatycznie serializuje i deserializuje zawartość wpisu, ale w przypadku Open Cloud musisz samodzielnie generować lub analizować swój wpis do i z JSON.
Uprawnienia
Magazyny danych często przechowują informacje wrażliwe, takie jak profile użytkowników i wirtualna waluta. Aby utrzymać bezpieczeństwo, każda metoda Open Cloud ma odpowiadające jej uprawnienia, zwane zakresami, które musisz dodać do swojego klucza API, takie jak zakres universe-datastores.control:list dla metody List Data Stores. Jeśli nie dodasz wymaganych uprawnień, twoje wywołanie API zakończy się błędem. Zobacz dokumentację referencyjną, aby uzyskać wymagane zakresy dla każdego punktu końcowego.
Aby uzyskać więcej informacji na temat zarządzania uprawnieniami, zobacz Zarządzaj kluczami API.
Portal wsparcia inwentarza użytkownika
Ten przykład używa magazynu danych o nazwie Inventory oraz schematu dla każdego wpisu "userId": {"currency": number, "weapon": string, "level": number}. Klucz to userId.
Wymagane zakresy
Podczas tworzenia klucza API dla tego przykładu dodaj następujące zakresy do swojego klucza:
- universe-datastores.objects:list
- universe-datastores.objects:read
- universe-datastores.objects:update
Opcjonalnie dodaj uprawnienia tylko do magazynu danych Inventory, ustaw ograniczenie adresu IP i datę wygaśnięcia.
Dodaj skrypty do portalu wsparcia inwentarza użytkownika
Po utworzeniu klucza API z wymaganymi uprawnieniami dla przykładowej aplikacji, możesz utworzyć skrypt do wykonywania żądań do punktów końcowych. Te skrypty pobierają pierwsze 10 wpisów w magazynie danych, zwiększają wartość currency dla każdego o 10, a następnie aktualizują każdy wpis. Dla większego magazynu danych musiałbyś zająć się paginacją przy użyciu parametrów zapytania maxPageSize i pageToken.
incrementCurrency.js
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('Zmiennej środowiskowej API_KEY nie ustawiono.');
}
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) // Ciało musi być ciągiem
});
return response;
}
(async () => {
try {
const entries = await listEntries(universeId, dataStoreId);
for (const entry of entries.dataStoreEntries) {
const path = entry.path;
console.log(`\nPrzetwarzanie wpisu: ${path}`);
const currentData = await getEntry(path);
currentData.value.currency += 10;
const payload = { value: currentData.value };
const updateResponse = await updateEntry(path, payload);
console.log(`Status: ${updateResponse.status}`);
console.log(`Odpowiedź: ${await updateResponse.text()}`);
}
} catch (error) {
console.error('Wystąpił błąd podczas wykonywania:', error);
}
})();
Aby przetestować, ustaw zmienną środowiskową API_KEY, zainstaluj zależności i uruchom skrypt:
export API_KEY=<twoj_klucz>node incrementCurrency.js
Zewnętrzna trwała tabela liderów
Ten przykład tworzy z góry zdefiniowaną listę użytkowników w celach demonstracyjnych, ale aby był przydatny w rzeczywistym doświadczeniu, potrzebowałbyś rzeczywistego magazynu danych użytkowników.
Wymagane zakresy
Podczas tworzenia klucza API dla tego przykładu dodaj następujące zakresy do swojego klucza:
- universe.ordered-data-store.scope.entry:read
- universe.ordered-data-store.scope.entry:write
Dodaj skrypty do tabeli liderów
Po utworzeniu klucza API z wymaganymi uprawnieniami dla przykładowej aplikacji, możesz utworzyć skrypt do wykonywania żądań do punktów końcowych. Te skrypty dodają kilka przykładowych wpisów do posortowanego magazynu danych z losowymi liczbami, a następnie pobierają je od najwyższej do najniższej wartości. Dla większego magazynu danych musiałbyś zająć się paginacją przy użyciu parametrów zapytania maxPageSize i 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(`Błąd 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('Błąd: Zmienna środowiskowa API_KEY nie jest ustawiona.');
process.exit(1);
}
const entryNames = ['Ragdoll', 'Balinese', 'Tabby', 'Siamese'];
console.log('Tworzenie danych przykładowych...');
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(`Nie udało się utworzyć wpisu dla "${name}": ${error.message}`);
}
}
console.log('\nPobieranie posortowanej listy wpisów...');
try {
const playerScoresResponse = await listOrderedEntries(universeId, orderedDataStoreId);
console.log(playerScoresResponse.status);
const responseText = await playerScoresResponse.text();
console.log(responseText);
} catch (error) {
console.error(`Nie udało się wylistować wpisów: ${error.message}`);
}
}
main();
Aby przetestować, ustaw zmienną środowiskową API_KEY, zainstaluj zależności i uruchom skrypt:
export API_KEY=<twoj_klucz>node leaderboard.js