Armazenamentos de dados do Open Cloud

*Este conteúdo é traduzido por IA (Beta) e pode conter erros. Para ver a página em inglês, clique aqui.

Além de acessar armazenamentos de dados pela API do Engine no Studio ou em jogos ao vivo (DataStoreService), você pode usar as APIs do Open Cloud para acessar armazenamentos de dados padrão e armazenamentos de dados ordenados a partir de scripts externos e outras ferramentas.

O acesso do Open Cloud aos seus armazenamentos de dados desbloqueia muitos casos de uso potenciais, incluindo:

  • Um portal de suporte ao cliente que permite que sua equipe lide diretamente com solicitações de suporte, como modificar inventários de usuários ou emitir reembolsos
  • Classificações globais que você pode exibir em um site externo
  • Atualizações de esquema com scripts que leem entradas do armazenamento de dados atual, mapeiam para o novo esquema e escrevem entradas de volta em um novo armazenamento de dados

Os exemplos nesta página demonstram como construir um portal de suporte de inventário de usuários e uma classificação externa com Node.js e Python, mas use a linguagem que preferir; as APIs do Open Cloud suportam qualquer linguagem de programação que possa enviar uma solicitação HTTP.

Diferenças em relação à API do Engine

Embora as APIs do Open Cloud acessem os mesmos armazenamentos de dados subjacentes e sejam semelhantes ao trabalho com DataStoreService, existem algumas diferenças principais:

  • ID do universo: Ao contrário da API do Engine, as APIs do Open Cloud são sem estado e podem vir de qualquer lugar, portanto, você deve sempre fornecer o ID do universo, o identificador exclusivo do seu jogo.

  • Permissões separadas para criação e atualização: A API do Engine cria novas entradas se elas não existirem quando você chama DataStore:SetAsync(), mas os métodos do Open Cloud para criar e atualizar entradas são separados. Permissões separadas podem ser mais seguras e flexíveis em certas situações. Por exemplo, você pode querer que sua ferramenta de suporte ao cliente só possa editar o perfil de um usuário existente, e não criar um novo.

  • Serialização de dados: Todos os endpoints do Open Cloud exigem que você serialize os dados antes de enviá-los. Serialização significa converter um objeto em uma string. Desserialização é o oposto, convertendo uma string em um objeto. A API do Engine serializa e desserializa o conteúdo da entrada automaticamente, mas para o Open Cloud, você deve gerar ou analisar sua entrada para e a partir de JSON por conta própria.

Números não finitos

Entradas de armazenamento de dados escritas através da API do Engine podem conter números Luau não finitos. Como o JSON não pode representar esses números, as respostas do Open Cloud os substituem por objetos JSON marcados no valor da entrada retornada:

  • Infinito positivo (inf): {"m": null, "t": "numeric", "v": "inf"}
  • Infinito negativo (-inf): {"m": null, "t": "numeric", "v": "-inf"}
  • NaN (nan): {"m": null, "t": "numeric", "v": "nan"}

Permissões

Os armazenamentos de dados frequentemente armazenam informações sensíveis, como perfis de usuários e moeda virtual. Para manter a segurança, cada método do Open Cloud tem permissões correspondentes, chamadas escopos, que você deve adicionar à sua chave de API, como o escopo universe-datastores.control:list para o método Listar Armazenamentos de Dados. Se você não adicionar as permissões necessárias, sua chamada de API retornará um erro. Consulte a documentação de referência para os escopos necessários para cada endpoint.

Para mais informações sobre como gerenciar permissões, veja Gerenciar chaves de API.

Portal de suporte de inventário de usuários

Este exemplo usa um armazenamento de dados chamado Inventory e um esquema para cada entrada de "userId": {"currency": number, "weapon": string, "level": number}. A chave é userId.

Escopos necessários

Ao criar uma chave de API para este exemplo, adicione os seguintes escopos à sua chave:

  • universe-datastores.objects:list
  • universe-datastores.objects:read
  • universe-datastores.objects:update

Opcionalmente, adicione as permissões apenas para o armazenamento de dados Inventory, defina uma restrição de endereço IP e defina uma data de expiração.

Adicionar scripts para o portal de suporte de inventário de usuários

Após criar a chave de API com as permissões necessárias para o aplicativo de exemplo, você pode criar um script para fazer solicitações aos endpoints. Esses scripts obtêm as primeiras 10 entradas no armazenamento de dados, incrementam o valor de currency para cada uma em 10 e, em seguida, atualizam cada entrada. Para um armazenamento de dados maior, você precisaria lidar com paginação usando os parâmetros de consulta maxPageSize e pageToken.

incrementCurrency.js
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('A variável de ambiente API_KEY não está definida.');
}
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) // O corpo deve ser uma string
});
return response;
}
(async () => {
try {
const entries = await listEntries(universeId, dataStoreId);
for (const entry of entries.dataStoreEntries) {
const path = entry.path;
console.log(`\nProcessando entrada: ${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(`Resposta: ${await updateResponse.text()}`);
}
} catch (error) {
console.error('Ocorreu um erro durante a execução:', error);
}
})();

Para testar, defina a variável de ambiente API_KEY, instale as dependências e execute o script:

export API_KEY=<sua_chave>
node incrementCurrency.js

Classificação externa persistente

Este exemplo cria uma lista predefinida de usuários para fins de demonstração, mas para que seja útil em um jogo real, você precisaria de um armazenamento de dados real de usuários.

Escopos necessários

Ao criar uma chave de API para este exemplo, adicione os seguintes escopos à sua chave:

  • universe.ordered-data-store.scope.entry:read
  • universe.ordered-data-store.scope.entry:write

Adicionar scripts para a classificação

Após criar a chave de API com as permissões necessárias para o aplicativo de exemplo, você pode criar um script para fazer solicitações aos endpoints. Esses scripts adicionam algumas entradas de exemplo ao armazenamento de dados ordenado com números aleatórios e, em seguida, as recuperam do maior para o menor valor. Para um armazenamento de dados maior, você precisaria lidar com paginação usando os parâmetros de consulta maxPageSize e 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(`Erro da 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('Erro: A variável de ambiente API_KEY não está definida.');
process.exit(1);
}
const entryNames = ['Ragdoll', 'Balinese', 'Tabby', 'Siamese'];
console.log('Criando dados de exemplo...');
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(`Falha ao criar entrada para "${name}": ${error.message}`);
}
}
console.log('\nObtendo lista ordenada de entradas...');
try {
const playerScoresResponse = await listOrderedEntries(universeId, orderedDataStoreId);
console.log(playerScoresResponse.status);
const responseText = await playerScoresResponse.text();
console.log(responseText);
} catch (error) {
console.error(`Falha ao listar entradas: ${error.message}`);
}
}
main();

Para testar, defina a variável de ambiente API_KEY, instale as dependências e execute o script:

export API_KEY=<sua_chave>
node leaderboard.js
©2026 Roblox Corporation, Roblox, o logotipo Roblox e Powering Imagination estão entre nossas marcas registradas e não registradas nos EUA e em outros países.