GraphQL API

Overview

The GraphQL API provides a flexible, efficient interface for querying and mutating incident data. It’s designed for mobile and web clients that need to minimize data transfer and network requests.

Endpoint: http://localhost:8080/api/v1/graphql Authentication: Bearer token (JWT) Playground: http://localhost:8080/graphql/playground (development mode only)

Authentication

All GraphQL requests require a valid JWT token in the Authorization header:

curl -X POST http://localhost:8080/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{"query": "{ myIncidents { id title } }"}'

Schema

Enums

enum Severity {
  SEV_1
  SEV_2
  SEV_3
  SEV_4
}

enum Status {
  OPEN
  ACKNOWLEDGED
  MITIGATED
  RESOLVED
  CLOSED
  DUPLICATE
  CANCELED
}

enum RACIRole {
  IC
  OPS
  COMMS
  SECURITY
  PRIVACY
}

enum ActionType {
  ACK
  ESCALATE
  JOIN_WAR_ROOM
  ADD_NOTE
  CHANGE_SEVERITY
  ASSIGN_ROLE
}

Types

type IncidentSummary {
  id: ID!
  title: String!
  severity: Severity!
  status: Status!
  lastUpdate: DateTime!
}

type IncidentMobileView {
  id: ID!
  title: String!
  severity: Severity!
  status: Status!
  assignedTo: UserSummary
  lastUpdate: String!
  warRoomLink: String
  quickTimeline: [TimelineEventSummary!]!
}

type MobileAction {
  id: ID!
  label: String!
  icon: String!
  actionType: ActionType!
  enabled: Boolean!
  confirmText: String
}

type NotificationPreferences {
  userId: ID!
  pushEnabled: Boolean!
  severityFilter: [Severity!]!
  quietHours: QuietHours
  channels: [String!]!
}

Queries

type Query {
  # Get incidents assigned to the current user (array filters)
  myIncidents(limit: Int = 20, status: [Status!], severity: [Severity!]): [IncidentSummary!]!

  # Get mobile-optimized incident details (limited timeline)
  incidentStatus(id: ID!): IncidentMobileView

  # Get available quick actions based on user role and incident state
  quickActions(incidentId: ID!): [MobileAction!]!

  # Get user's notification preferences
  notificationSettings: NotificationPreferences
}

Mutations

type Mutation {
  # Declare a new incident
  declareIncident(input: DeclareIncidentInput!): Incident!

  # Acknowledge an incident
  ackIncident(id: ID!): Incident!

  # Add a note to an incident
  addNote(incidentId: ID!, content: String!): Note!

  # Assign a role on an incident
  assignRole(incidentId: ID!, role: RACIRole!, userId: ID!): Incident!

  # Update notification preferences
  updateNotificationSettings(input: NotificationPreferencesInput!): NotificationPreferences!
}

input DeclareIncidentInput {
  title: String!
  severity: Severity!
  services: [String!]
  labels: JSON
  visibility: String
}

input NotificationPreferencesInput {
  pushEnabled: Boolean
  severityFilter: [Severity!]
  quietHours: QuietHoursInput
  channels: [String!]
}

Example Queries

List My Incidents

query MyIncidents {
  myIncidents(status: [OPEN, ACKNOWLEDGED], limit: 10) {
    id
    title
    severity
    status
    lastUpdate
  }
}

Get Incident Details (Mobile View)

query IncidentDetails($id: ID!) {
  incidentStatus(id: $id) {
    id
    title
    severity
    status
    lastUpdate
    warRoomLink
    quickTimeline {
      id
      type
      summary
      time
    }
  }
}

Variables:

{
  "id": "INC-12345"
}

Get Quick Actions

query QuickActions($incidentId: ID!) {
  quickActions(incidentId: $incidentId) {
    id
    label
    icon
    actionType
    enabled
    confirmText
  }
}

Example Mutations

Declare Incident

mutation DeclareIncident($input: DeclareIncidentInput!) {
  declareIncident(input: $input) {
    id
    title
    severity
    status
    createdAt
  }
}

Variables:

{
  "input": {
    "title": "Database Connection Timeout",
    "severity": "SEV_2",
    "services": ["auth-service"]
  }
}

Acknowledge Incident

mutation AckIncident($id: ID!) {
  ackIncident(id: $id) {
    id
    status
    updatedAt
  }
}

Add Note

mutation AddNote($incidentId: ID!, $content: String!) {
  addNote(incidentId: $incidentId, content: $content) {
    id
    content
    createdAt
  }
}

Variables:

{
  "incidentId": "INC-12345",
  "content": "Investigating database connection pool exhaustion"
}

Update Notification Preferences

mutation UpdateNotifications($input: NotificationPreferencesInput!) {
  updateNotificationSettings(input: $input) {
    pushEnabled
    severityFilter
    channels
  }
}

Variables:

{
  "input": {
    "pushEnabled": true,
    "severityFilter": ["SEV_1", "SEV_2"],
    "channels": ["push", "email"]
  }
}

Using with curl

Query

curl -X POST http://localhost:8080/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "query": "query { myIncidents { id title severity } }"
  }'

Mutation with Variables

curl -X POST http://localhost:8080/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "query": "mutation($id: ID!) { ackIncident(id: $id) { id status } }",
    "variables": {"id": "INC-12345"}
  }'

Error Handling

GraphQL errors are returned in the standard format:

{
  "errors": [
    {
      "message": "incident not found",
      "path": ["incidentStatus"],
      "extensions": {
        "code": "NOT_FOUND"
      }
    }
  ],
  "data": {
    "incidentStatus": null
  }
}

Query Complexity

The API enforces a maximum query complexity of 1000 to prevent abuse. Complex nested queries may be rejected if they exceed this limit.

Development Playground

In development mode, a GraphQL Playground is available at:

http://localhost:8080/graphql/playground

This provides an interactive IDE for exploring the schema and testing queries.