Appearance
Appearance
The Liveops Dashboard is the place you go to find information about your game, but where does the data come from? The answer is, of course, from the game server. There are standard ways of fetching this data (such as using the Axios library) but there are also complications (such as polling for updates or user authentication) that can make things messy, very quickly.
The Metaplay SDK takes care of all of this complexity and hides it away, providing you with two well-defined ways to fetch data. These have their strengths and weaknesses and are intended for different scenarios.
The supported methods are:
Ultimately, subscriptions are the best choice in almost all cases. You can often use the Axios method to fetch your data if your needs are simple and then migrate to subscriptions as your needs increase.
The Axios library is a simple, industry-standard way to communicate with HTTP APIs. Axios is very flexible and has many configuration options that allow you to, for example, handle errors consistently or pass authentication headers to APIs that require them. These can be quite complex to set up, so the Metaplay SDK does this for you and exposes a pre-configured Axios instance that you can import with useGameServerApi
.
In its simplest form, Axios can be used to synchronously fetch data from the game server API like this:
import { useGameServerApi } from '@metaplay/game-server-api'
let playerData = null
const gameServerApi = useGameServerApi()
try {
const res = await gameServerApi.get('/players/Player:2pTRbBftFA')
console.log('Received player data:', res)
playerData = result.data
} catch (err) {
throw new Error(`Failed to load data from the server! Reason: ${err.message}.`)
}
This example would fetch the data for player Player:2pTRbBftFA
and store it in playerData
.
Subscriptions take data fetching further by adding polling and caching. Caching means that the data is retained after it has been fetched. If another component then requests the same data, the result can be returned from the cache instead of having to make another request to the game server. Data even remains in the cache once you leave a page. If you return to the same page later, the data will be served from the cache, speeding up page loading.
The subscription system uses what we call "policies" to define how data is fetched and cached on a per-subscription basis. A subscription is a set of rules that define how data is fetched, how often it is fetched and how long it is kept in the cache. For example, you might want a polling subscription to player data that fetches the data every 5 seconds and keeps it in the cache for 5 minutes.
Subscriptions are easy to set up and can be integrated directly into your components. To subscribe to data, you'll create a subscription in your component's setup function:
// Import the function to set up a subscription.
import { useSubscription } from '@metaplay/subscriptions'
// Import the pre-made subscription options for a single player based on their ID.
import { getSinglePlayerSubscriptionOptions } from '@metaplay/core'
/**
* Set up the subscription and cherry pick the (reactive) data property
* from the returned subscription.
*/
const {
data: playerData,
} = useSubscription(() => getSinglePlayerSubscriptionOptions('Player:2pTRbBftFA'))
For an up-to-date list of all the pre-written subscriptions, see the src/subscription_configs
folder in the Metaplay SDK's Core module.
There are several pre-written subscription options that follow the pattern get???SubscriptionOptions
that you can use to subscribe to the various game server endpoints. These pre-written options know how to fetch the data, how often to update it and when to evict the data from the cache. Note that there is no need to manually unsubscribe - this is done automatically when your component unloads.
In the last example, we used a hard-coded player ID, but in reality, this would not be the case. Let's look at an example from the player details page where the player ID comes from a property that is passed into the component:
import { useSubscription } from '@metaplay/subscriptions'
import { getSinglePlayerSubscriptionOptions } from '@metaplay/core'
const props = defineProps<{
playerId: string
}>()
/**
* Note that if the property changes, the subscription will not automatically
* re-subscribe to a different player. This is usually not an issue as all our
* built-in pages get the property from the URL parameter and changing that parameter
* also re-initializes all the components and their subscriptions on the page.
*/
const {
data: playerData,
error: playerError,
} = useSubscription(() => getSinglePlayerSubscriptionOptions(props.playerId))
Subscriptions handle periodic fetching of new data from the game server. If you know that the data has become stale, you can trigger a fresh fetch without having to wait for the next poll:
// Destructure the refresh function from the returned subscription.
const {
data: playerData:,
refresh: playerRefresh,
} = useSubscription(() => getSinglePlayerSubscriptionOptions(props.playerId))
// Call the refresh function to immediately fetch new data.
playerRefresh()
In some advanced cases, you might need to change the subscription options dynamically and essentially change what data you are subscribed to. For example, you might want to subscribe to a different player based on a form input from the dashboard user. This is easy to do:
import { ref, watch } from 'vue'
import { useSubscription } from '@metaplay/subscriptions'
import { getSinglePlayerSubscriptionOptions } from '@metaplay/core'
// A reactive variable that will change when the user selects a player. In this example, there is no default selection.
const selectedPlayerId = ref<string>()
// Set up the subscription.
const {
data: playerData,
} = useSubscription(() => {
if (selectedPlayerId.value) {
// Player selected. Tell the subscription system where to get the
// required data from.
return getSinglePlayerSubscriptionOptions(selectedPlayerId.value)
} else {
// No player selected, so we return `undefined` to tell the subscription
// system to stop fetching any data.
return undefined
}
})
You may have noticed that we pass a function into useSubscription
, and the return value from that function contains the information that the subscription system needs. The subscription system leverages the power of Vue's reference system to notice when this function needs to be re-computed (in this case, when selectedPlayerId
changes). It can then unsubscribe from the old source and resubscribe to the new one, automatically.
You can also define your own re-usable subscriptions if you've added game-specific API endpoints. You can simply copy one of our core subscriptions as an example and modify it to suit your needs.
For example, if you wanted to create a subscription that fetched the data for a single player every 5 seconds and kept it in the cache for 5 minutes, you could do something like this:
import {
type SubscriptionOptions,
getFetcherPolicyGet,
getCacheRetentionPolicyKeepForever,
getCacheRetentionPolicyTimed,
getPollingPolicyTimer,
} from '@metaplay/subscriptions'
export function getCustomPlayerSubscriptionOptions (playerId: string): SubscriptionOptions {
return {
// The user permission, if any, required to access the underlying data.
permission: 'api.players.view',
// How often is new data fetched?
pollingPolicy: getPollingPolicyTimer(5000), // 5000ms, or 5 seconds
// How is the data fetched?
fetcherPolicy: getFetcherPolicyGet(`/players/${playerId}`),
// How long is the data kept in the cache after polling has stopped?
cacheRetentionPolicy: getCacheRetentionPolicyTimed(300000), // 300000ms, or 5 minutes
}
}
We've set up subscriptions for the most commonly used types of data, but if you need something else, you'll want to check out the in-depth guide Working with Subscriptions.