Skip to main content

GraphQL API

Complete GraphQL API reference for querying and managing applications, hooks, settings, and assets.

Overview

The AppServer GraphQL API is available at:

HTTP/WebSocket: http://localhost:8080/graphql

Based on pkg/v2/presentation/graphql/schema/:

Features:

  • Queries: Fetch apps, hooks, settings, assets, health, and metrics
  • Mutations: Install/uninstall apps, trigger hooks, update settings
  • Subscriptions: Real-time app state changes, hook events, system events
  • Relay Pagination: Cursor-based pagination for list queries
  • Type Safety: Strongly typed schema with validation

Access and Authentication

GraphQL Playground

Development Only:

URL: http://localhost:8080/graphql
Enabled when: APPSERVER_GRAPHQL_PLAYGROUND_ENABLED=true

WARNING: Disable in production for security!

Authentication

GraphQL queries require:

  • User Authentication: Kratos session cookie (ory_kratos_session)
  • App Authentication: Certificate-based authentication for app-to-app calls
  • Authorization: OpenFGA permission checks for protected resources

Queries

Based on pkg/v2/presentation/graphql/schema/queries.graphql:

App Queries

app(name: String!): App

Fetch a single application by name.

Example:

query GetApp {
app(name: "todos-bff") {
id
name
state
registeredAt
installedAt
webApp {
ui {
mode
routeBase
navigation {
title
href
icon
requiredPermissions
}
}
api {
basePath
upstreamBaseURL
requiredPermissions
defaultRateLimit {
rpm
burst
}
}
}
dependencies {
app {
name
}
kind
}
}
}

Response:

{
"data": {
"app": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "todos-bff",
"state": "INSTALLED",
"registeredAt": "2024-01-15T10:30:00Z",
"installedAt": "2024-01-15T10:31:00Z",
"webApp": {
"ui": {
"mode": "FEDERATION",
"routeBase": "/apps/todos",
"navigation": [
{
"title": "My Tasks",
"href": "/apps/todos/list",
"icon": "task-icon.svg",
"requiredPermissions": ["todos:read"]
}
]
},
"api": {
"basePath": "/api/apps/todos",
"upstreamBaseURL": "http://todos-bff.svc:8080",
"requiredPermissions": ["todos:read", "todos:write"],
"defaultRateLimit": {
"rpm": 60,
"burst": 10
}
}
},
"dependencies": []
}
}
}

apps(filter: AppFilter, first: Int, after: String): AppConnection!

List applications with filtering and pagination.

Arguments:

  • filter - Optional filter criteria
    • state - Filter by single state
    • states - Filter by multiple states
    • nameContains - Search by name substring
    • registeredAfter - Filter by registration date
    • installedAfter - Filter by installation date
  • first - Number of results per page
  • after - Cursor for pagination

Example:

query ListApps {
apps(
filter: { states: [INSTALLED], nameContains: "bff" }
first: 10
) {
edges {
node {
id
name
state
isInstalled
installedAt
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
totalCount
}
}

Response:

{
"data": {
"apps": {
"edges": [
{
"node": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "todos-bff",
"state": "INSTALLED",
"isInstalled": true,
"installedAt": "2024-01-15T10:31:00Z"
},
"cursor": "YXJyYXljb25uZWN0aW9uOjA="
}
],
"pageInfo": {
"hasNextPage": false,
"endCursor": "YXJyYXljb25uZWN0aW9uOjA="
},
"totalCount": 1
}
}
}

Hook Queries

hook(id: ID!): Hook

Fetch a single hook by ID.

Example:

query GetHook {
hook(id: "hook-123") {
id
name
app {
name
}
async
totalExecutions
successRate
averageDurationMs
}
}

hooks(appName: String, filter: HookFilter): [Hook!]!

List hooks for an app or all apps.

Arguments:

  • appName - Filter by app name (optional)
  • filter - Optional filter criteria
    • async - Filter by async/sync
    • nameContains - Search by name substring

Example:

query ListHooks {
hooks(appName: "todos-bff", filter: { async: false }) {
id
name
async
totalExecutions
successRate
averageDurationMs
registeredAt
}
}

Response:

{
"data": {
"hooks": [
{
"id": "hook-123",
"name": "app.installed",
"async": false,
"totalExecutions": 42,
"successRate": 0.98,
"averageDurationMs": 125.5,
"registeredAt": "2024-01-15T10:30:00Z"
}
]
}
}

Settings Queries

settings(appID: ID!): Settings

Fetch all settings for an application.

Example:

query GetSettings {
settings(appID: "550e8400-e29b-41d4-a716-446655440000") {
appID
schema
values
updatedAt
updatedBy
}
}

Response:

{
"data": {
"settings": {
"appID": "550e8400-e29b-41d4-a716-446655440000",
"schema": {
"type": "object",
"properties": {
"api_key": {
"type": "string",
"encrypted": true
}
}
},
"values": {
"api_key": "encrypted:base64..."
},
"updatedAt": "2024-01-15T12:00:00Z",
"updatedBy": "user:123"
}
}
}

settingValue(appID: ID!, key: String!): SettingValue

Fetch a single setting value.

Example:

query GetSettingValue {
settingValue(appID: "550e8400-e29b-41d4-a716-446655440000", key: "api_key") {
key
value
}
}

Asset Queries

asset(appName: String!, assetName: String!): Asset

Fetch asset metadata.

Example:

query GetAsset {
asset(appName: "todos-bff", assetName: "remoteEntry.js") {
name
mimeType
size
sha256
url
}
}

Response:

{
"data": {
"asset": {
"name": "remoteEntry.js",
"mimeType": "application/javascript",
"size": 51234,
"sha256": "abc123...",
"url": "/apps/todos-bff/assets/remoteEntry.js"
}
}
}

System Queries

health: HealthStatus!

Check system health.

Example:

query GetHealth {
health {
status
checks {
name
status
message
timestamp
}
timestamp
}
}

Response:

{
"data": {
"health": {
"status": "HEALTHY",
"checks": [
{
"name": "database",
"status": "HEALTHY",
"message": "Connected",
"timestamp": "2024-01-15T14:30:00Z"
},
{
"name": "redis",
"status": "HEALTHY",
"message": "Connected",
"timestamp": "2024-01-15T14:30:00Z"
},
{
"name": "rabbitmq",
"status": "HEALTHY",
"message": "Connected",
"timestamp": "2024-01-15T14:30:00Z"
}
],
"timestamp": "2024-01-15T14:30:00Z"
}
}
}

metrics: Metrics!

Get system metrics.

Example:

query GetMetrics {
metrics {
apps {
totalApps
registeredApps
installedApps
}
hooks {
totalHooks
totalExecutions
successRate
}
proxy {
totalRequests
requestsPerSecond
averageLatencyMs
errorRate
}
system {
uptime
cpuUsage
memoryUsage {
total
used
percentUsed
}
}
}
}

Mutations

Based on pkg/v2/presentation/graphql/schema/mutations.graphql:

App Lifecycle

installApp(name: String!): AppMutationResult!

Install an application and its dependencies.

Example:

mutation InstallApp {
installApp(name: "todos-bff") {
success
app {
id
name
state
installedAt
}
error {
code
message
}
}
}

Response (Success):

{
"data": {
"installApp": {
"success": true,
"app": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "todos-bff",
"state": "INSTALLED",
"installedAt": "2024-01-15T10:31:00Z"
},
"error": null
}
}
}

Response (Error):

{
"data": {
"installApp": {
"success": false,
"app": null,
"error": {
"code": "DEPENDENCY_NOT_FOUND",
"message": "Required dependency 'auth-service' not found",
"details": {
"missing": ["auth-service"]
}
}
}
}
}

uninstallApp(name: String!): AppMutationResult!

Uninstall an application.

Example:

mutation UninstallApp {
uninstallApp(name: "todos-bff") {
success
app {
name
state
uninstalledAt
}
error {
code
message
}
}
}

Hook Operations

triggerHook(name: String!, data: JSON): HookTriggerResult!

Manually trigger a hook.

Example:

mutation TriggerHook {
triggerHook(
name: "app.settings.updated"
data: { appName: "todos-bff", keys: ["api_key"] }
) {
success
results {
app {
name
}
success
data
error {
code
message
}
}
error {
code
message
}
}
}

Response:

{
"data": {
"triggerHook": {
"success": true,
"results": [
{
"app": {
"name": "todos-bff"
},
"success": true,
"data": {
"processed": true
},
"error": null
}
],
"error": null
}
}
}

Settings Operations

updateSettings(appID: ID!, settings: JSON!): SettingsMutationResult!

Update application settings.

Example:

mutation UpdateSettings {
updateSettings(
appID: "550e8400-e29b-41d4-a716-446655440000"
settings: {
api_key: "new-secret-key"
feature_enabled: true
}
) {
success
settings {
values
updatedAt
updatedBy
}
error {
code
message
}
}
}

Response:

{
"data": {
"updateSettings": {
"success": true,
"settings": {
"values": {
"api_key": "encrypted:base64...",
"feature_enabled": true
},
"updatedAt": "2024-01-15T15:00:00Z",
"updatedBy": "user:123"
},
"error": null
}
}
}

deleteSettings(appID: ID!): SettingsMutationResult!

Delete all settings for an application.

Example:

mutation DeleteSettings {
deleteSettings(appID: "550e8400-e29b-41d4-a716-446655440000") {
success
settings {
appID
}
error {
code
message
}
}
}

Subscriptions

Based on pkg/v2/presentation/graphql/schema/subscriptions.graphql:

Real-Time App State Changes

appStateChanged(filter: AppStateFilter): App!

Subscribe to app state changes.

Arguments:

  • filter - Optional filter
    • states - Only receive changes for these states
    • appNames - Only receive changes for these apps

Example:

subscription WatchAppState {
appStateChanged(
filter: {
states: [INSTALLED, UNINSTALLED]
appNames: ["todos-bff"]
}
) {
id
name
state
installedAt
uninstalledAt
}
}

Event Stream:

{
"data": {
"appStateChanged": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "todos-bff",
"state": "INSTALLED",
"installedAt": "2024-01-15T10:31:00Z",
"uninstalledAt": null
}
}
}

Hook Events

hookTriggered(hookName: String): HookEvent!

Subscribe to hook trigger events.

Example:

subscription WatchHooks {
hookTriggered(hookName: "app.installed") {
hook {
name
}
triggeredBy {
name
}
data
timestamp
}
}

Event Stream:

{
"data": {
"hookTriggered": {
"hook": {
"name": "app.installed"
},
"triggeredBy": {
"name": "todos-bff"
},
"data": {
"appName": "todos-bff",
"installTime": "2024-01-15T10:31:00Z"
},
"timestamp": "2024-01-15T10:31:00Z"
}
}
}

System Events

systemEvent(types: [SystemEventType!]): SystemEvent!

Subscribe to system events.

Event Types:

  • SERVER_STARTED - Server started
  • SERVER_STOPPING - Server gracefully stopping
  • ERROR_OCCURRED - System error occurred
  • CONFIG_CHANGED - Configuration changed

Example:

subscription WatchSystemEvents {
systemEvent(types: [ERROR_OCCURRED, CONFIG_CHANGED]) {
type
message
data
timestamp
}
}

Types

Based on pkg/v2/presentation/graphql/schema/types.graphql:

Core Types

App:

  • id - Unique identifier (UUID)
  • name - App name (unique)
  • state - Current state (UNREGISTERED, REGISTERED, INSTALLED, UNINSTALLED)
  • dependencies - App dependencies with kind (HARD, SOFT)
  • registeredAt - Registration timestamp
  • installedAt - Installation timestamp (nullable)
  • webApp - Web app configuration (UI, API, assets)
  • hooks - Registered hooks
  • settings - App settings

WebApp:

  • assets - Uploaded assets
  • ui - UI configuration (mode, entrypoint, navigation)
  • api - API configuration (routes, rate limits, permissions)

Hook:

  • id - Unique identifier
  • name - Hook name (e.g., "app.installed")
  • app - Owner app
  • async - Async execution flag
  • totalExecutions - Execution count
  • successRate - Success percentage
  • averageDurationMs - Average duration

Settings:

  • appID - Owner app ID
  • schema - JSON schema definition
  • values - Setting values (encrypted if marked)
  • updatedAt - Last update timestamp
  • updatedBy - User who updated

Enums

AppState:

enum AppState {
UNREGISTERED # Manifest submitted, not persisted
REGISTERED # Persisted in database
INSTALLED # Installed and active
UNINSTALLED # Previously installed, now removed
}

DependencyKind:

enum DependencyKind {
HARD # Required dependency (installation fails if missing)
SOFT # Optional dependency (installation continues if missing)
}

UIMode:

enum UIMode {
FEDERATION # Module Federation
WEB_COMPONENT # Web Component
ESM_COMPONENT # ESM Component
}

HTTPMethod:

enum HTTPMethod {
GET
POST
PUT
PATCH
DELETE
HEAD
OPTIONS
}

Error Handling

All mutations return a result type with:

  • success - Boolean success flag
  • error - Error object (if failed)
    • code - Machine-readable error code
    • message - Human-readable message
    • details - Additional error context (JSON)

Common Error Codes:

  • APP_NOT_FOUND - App does not exist
  • APP_ALREADY_INSTALLED - App already installed
  • DEPENDENCY_NOT_FOUND - Required dependency missing
  • PERMISSION_DENIED - Insufficient permissions
  • VALIDATION_ERROR - Invalid input data
  • INTERNAL_ERROR - Server error

Best Practices

Query Optimization

DO:

  • Request only needed fields
  • Use pagination for large lists
  • Use fragments for reusable field sets
  • Filter results server-side

DON'T:

  • Fetch all fields if not needed
  • Request deeply nested data without necessity
  • Perform client-side filtering on large datasets

Example with Fragments:

fragment AppBasic on App {
id
name
state
isInstalled
}

query ListApps {
apps(first: 10) {
edges {
node {
...AppBasic
}
}
}
}

query GetApp {
app(name: "todos-bff") {
...AppBasic
dependencies {
app {
...AppBasic
}
}
}
}

Real-Time Updates

DO:

  • Filter subscriptions to needed events
  • Handle reconnections gracefully
  • Unsubscribe when no longer needed
  • Combine with queries for initial state

DON'T:

  • Subscribe to all events without filtering
  • Ignore connection errors
  • Keep unnecessary subscriptions open

Example:

// Fetch initial state
const { data } = await client.query({
query: GET_APPS
});

// Subscribe to changes
const subscription = client.subscribe({
query: WATCH_APP_STATE,
variables: {
filter: { states: ['INSTALLED'] }
}
}).subscribe({
next: (event) => {
// Update local state
updateApp(event.data.appStateChanged);
},
error: (err) => {
console.error('Subscription error:', err);
// Reconnect logic
}
});

// Cleanup
subscription.unsubscribe();

Error Handling

DO:

  • Check success field in mutations
  • Display user-friendly error messages
  • Log detailed errors for debugging
  • Implement retry logic for transient errors

Example:

const result = await client.mutate({
mutation: INSTALL_APP,
variables: { name: 'todos-bff' }
});

if (result.data.installApp.success) {
toast.success('App installed successfully');
} else {
const error = result.data.installApp.error;

if (error.code === 'DEPENDENCY_NOT_FOUND') {
toast.error(`Missing dependencies: ${error.details.missing.join(', ')}`);
} else {
toast.error(error.message);
}

console.error('Installation failed:', error);
}

Code References

ComponentFilePurpose
Schemapkg/v2/presentation/graphql/schema/schema.graphqlRoot schema definition
Queriespkg/v2/presentation/graphql/schema/queries.graphqlQuery definitions
Mutationspkg/v2/presentation/graphql/schema/mutations.graphqlMutation definitions
Subscriptionspkg/v2/presentation/graphql/schema/subscriptions.graphqlSubscription definitions
Typespkg/v2/presentation/graphql/schema/types.graphqlType definitions
Resolverspkg/v2/presentation/graphql/resolvers/Query/mutation implementations