Backend calls with Lambda and AppSync
Call backend functions and exchange data through AppSync.
Use Lambda for a backend operation and AppSync for a GraphQL API with live subscriptions. Both require AWS setup and deployed resources; these nodes do not create your backend logic.
Call a Lambda function
Loading the interactive viewer.
Game module dependencies: AWSIKLambda, BetideCore, Engine.
#include "Engine/GameInstance.h"
#include "AWSIKLambda.h"
#include "Providers/IUCIKBackendFunctionProvider.h"
void LoadDailyChallenges(UGameInstance &GameInstance)
{
const auto Backend = FAWSIKLambdaModule::Get().GetFunctionProvider();
if (!Backend)
{
UE_LOG(LogAWSIKLambda, Warning, TEXT("Lambda provider unavailable"));
return;
}
Backend->CallFunction(TEXT("GetDailyChallenges"), TEXT("{\"playlist\":\"duos\"}"),
FUCIKBackendFunctionCallback::CreateWeakLambda(
&GameInstance, [](const TBetideResult<FString> &Result) {
if (!Result.bOk)
{
UE_LOG(LogAWSIKLambda, Warning, TEXT("%s"),
*Result.Error.GetLogString());
return;
}
UE_LOG(LogAWSIKLambda, Log, TEXT("%s"), *Result.GetValue());
}));
}Deploy a function named GetDailyChallenges (or change Name) that accepts { "playlist": "duos" } and returns JSON. The request must be a JSON object; empty or non-JSON responses fail. The caller needs permission to invoke that function. The helper waits for its response and reports Lambda function errors as failures. Parse the returned JSON for your own business result too; a valid response can still reject a purchase or match result. Make retried writes idempotent in your backend.
Configure AppSync
Set GraphQL Endpoint and Auth Mode in Betide → Crossplay → AWS AppSync:
| Mode | Credential source |
|---|---|
| IAM | AWS credential chain. |
| API Key | Environment variable named by API Key Environment Variable. |
| Cognito User Pool | ID token in the environment variable named by JWT Environment Variable. |
The current Cognito mode reads that environment variable; it does not automatically take a token from the login subsystem. Leave Realtime Endpoint empty for a standard endpoint, or supply the WebSocket endpoint for your custom domain.
Backend fields used below
The examples read and update lobby-demo. Create it in your backend, or replace the ID. The API needs these fields and matching query/mutation resolvers:
Example AppSync schema
type Lobby {
id: ID!
status: String!
}
type Query {
getLobby(id: ID!): Lobby
}
type Mutation {
updateLobby(id: ID!, status: String!): Lobby
}
type Subscription {
onUpdateLobby(id: ID!): Lobby @aws_subscribe(mutations: ["updateLobby"])
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}Enforce who can read or update each lobby in your backend. The mutation returns both id and status so subscribers receive both fields. See AppSync subscription setup.
Query AppSync
Read lobby status
Loading the interactive viewer.
Update lobby status
Loading the interactive viewer.
Game module dependencies: AWSIKAppSync, BetideCore, Engine.
#include "Engine/GameInstance.h"
#include "AWSIKAppSync.h"
#include "Providers/IUCIKRealtimeDataProvider.h"
void RequestLobbyStatus(UGameInstance &GameInstance, bool bUpdate)
{
const auto Backend = FAWSIKAppSyncModule::Get().GetProvider();
if (!Backend)
{
UE_LOG(LogAWSIKAppSync, Warning, TEXT("AppSync provider unavailable"));
return;
}
auto Completion = FUCIKRealtimeResultCallback::CreateWeakLambda(
&GameInstance, [](const TBetideResult<FString> &Result) {
if (!Result.bOk)
{
UE_LOG(LogAWSIKAppSync, Warning, TEXT("%s"), *Result.Error.GetLogString());
return;
}
UE_LOG(LogAWSIKAppSync, Log, TEXT("%s"), *Result.GetValue());
});
if (bUpdate)
{
Backend->Mutate(TEXT("mutation UpdateLobby($id: ID!, $status: String!) { updateLobby(id: "
"$id, status: $status) { id status } }"),
TEXT("{\"id\":\"lobby-demo\",\"status\":\"Ready\"}"), MoveTemp(Completion));
}
else
{
Backend->Query(TEXT("query ReadLobby($id: ID!) { getLobby(id: $id) { id status } }"),
TEXT("{\"id\":\"lobby-demo\"}"), MoveTemp(Completion));
}
}Use bUpdate = false to read and true to set Ready in C++. Pass a document matching your schema and a JSON object for variables ({} when none). HTTP query/mutation responses with a non-empty GraphQL errors array fail even when HTTP succeeds.
Subscribe and unsubscribe
Loading the interactive viewer.
The graph keeps a LobbySubscription variable of type Guid. Call Stop Watching Lobby Status when closing the screen; call Watch again to restart.
#include "Engine/GameInstance.h"
#include "AWSIKAppSync.h"
#include "Providers/IUCIKRealtimeDataProvider.h"
void WatchLobbyStatus(UGameInstance &GameInstance, FGuid &SubscriptionId)
{
if (SubscriptionId.IsValid())
return;
const auto Backend = FAWSIKAppSyncModule::Get().GetProvider();
if (!Backend)
{
UE_LOG(LogAWSIKAppSync, Warning, TEXT("AppSync provider unavailable"));
return;
}
const TWeakObjectPtr<UGameInstance> WeakGameInstance(&GameInstance);
SubscriptionId = Backend->Subscribe(
TEXT("subscription WatchLobby($id: ID!) { onUpdateLobby(id: $id) { id status } }"),
TEXT("{\"id\":\"lobby-demo\"}"), [WeakGameInstance](const TBetideResult<FString> &Event) {
if (!WeakGameInstance.IsValid())
return;
if (!Event.bOk)
{
UE_LOG(LogAWSIKAppSync, Warning, TEXT("%s"), *Event.Error.GetLogString());
return;
}
UE_LOG(LogAWSIKAppSync, Log, TEXT("%s"), *Event.GetValue());
});
if (!SubscriptionId.IsValid())
UE_LOG(LogAWSIKAppSync, Warning, TEXT("Subscription request could not start"));
}
void StopWatchingLobbyStatus(FGuid &SubscriptionId)
{
if (const auto Backend = FAWSIKAppSyncModule::Get().GetProvider())
Backend->Unsubscribe(SubscriptionId);
SubscriptionId.Invalidate();
}Keep SubscriptionId as an FGuid member and call StopWatchingLobbyStatus when the owning screen/session closes.
A valid ID means the request was tracked locally, not that the server accepted it. Updates arrive through the event; inspect the JSON payload for your data and GraphQL errors. AppSync sends updates for the linked mutation, not direct database writes.
Reconnect uses the configured backoff. The current wrapper has no connected/reconnected event. Query the latest state when opening or returning to the screen; subscriptions do not replay missed updates.