API-referentie

Data opvragen

Alle lijstquery's in de Tidal Control API volgen dezelfde patronen voor paginering, filtering en sortering. Leer ze eenmalig en ze gelden overal.

Verzoekstructuur

Elk GraphQL-verzoek is een POST naar https://portal.tidalcontrol.com/graphql met een JSON-body:

{
  "query": "...",
  "variables": { ... }
}

Gebruik altijd variables in plaats van waarden rechtstreeks in de querystring te plaatsen — dat houdt query's leesbaar en voorkomt injectieproblemen.

Paginering

Alle *_paged-query's gebruiken cursor-gebaseerde paginering volgens de Relay Connection-specificatie. Vraag een pagina op met first (paginagrootte) en after (cursor van de vorige pagina):

query ExportRisks($first: Int, $after: String) {
  risks_paged(first: $first, after: $after) {
    edges {
      node {
        id
        name
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Variabelen:

{ "first": 50, "after": null }

Als pageInfo.hasNextPage true is, geef je pageInfo.endCursor door als after in het volgende verzoek.

Alle pagina's ophalen (Python)

def fetch_all(graphql_fn, query, page_size=50):
    """Haal alle pagina's op van een gepagineerde query."""
    results = []
    cursor = None

    while True:
        data = graphql_fn(query, {"first": page_size, "after": cursor})
        key = next(iter(data))
        page = data[key]
        results.extend(edge["node"] for edge in page["edges"])

        if not page["pageInfo"]["hasNextPage"]:
            break
        cursor = page["pageInfo"]["endCursor"]

    return results
Tip

Een paginagrootte van 50 is een goede standaard. Je kunt hoger gaan, maar zeer grote pagina's kunnen de responstijd verlengen.

Filtering

Geef een filter-argument mee om resultaten te beperken. Elke entiteit heeft zijn eigen filtertype met relevante velden. Alle filtervelden zijn optioneel — laat velden die je niet nodig hebt weg.

Voorbeeld — alleen open, hoge-prioriteit issues ophalen:

query FilteredIssues($filter: IssueFilter) {
  issues_paged(first: 50, filter: $filter) {
    edges {
      node {
        id
        name
        priority
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Variabelen:

{
  "filter": {
    "closed": false,
    "priority": ["HIGH"]
  }
}

Veelgebruikte filtervelden

Beschikbaar op de meeste entiteiten:

  • archived: Boolean — gearchiveerde records in- of uitsluiten
  • assignees: [UUID!] — filteren op toegewezen gebruikers-ID's
  • search: String — vrije-tekstzoekactie op naam/omschrijving

Activiteiten (issues, taken):

  • closed: Boolean — open of gesloten activiteiten
  • controls: [UUID!] — activiteiten gekoppeld aan specifieke controls
  • assets: [UUID!] — activiteiten gekoppeld aan specifieke assets
  • status: [ActivityDueStatus!]NOT_DUE_SOON, DUE_SOON, OVERDUE, NOT_SET

Alleen issues:

  • priority: [Priority!]LOW, MEDIUM, HIGH
  • type: [IssueType!] — bijv. AUDIT_FINDING, INCIDENT, CONTROL_GAP

Risico's en controls:

  • frameworks: [UUID!] — gekoppeld aan specifieke frameworks
  • references: [UUID!] — gekoppeld aan specifieke frameworkreferenties

Sortering

Geef een sort-array mee om de volgorde van resultaten te bepalen. Elk sorteerelement geeft een field-naam en een optionele direction (ASC of DESC) aan:

query SortedRisks {
  risks_paged(
    first: 50,
    sort: [{ field: "sequenceId", direction: ASC }]
  ) {
    edges {
      node {
        sequenceId
        name
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Je kunt meerdere sorteervelden opgeven. Veelgebruikte velden zijn name, sequenceId, createdDate, notBefore en expires.

Records tellen

Gebruik *_count-query's om een totaaltelling op te halen zonder alle gegevens op te vragen:

query {
  risks_count
  controls_count(filter: { archived: false })
  issues_count(filter: { closed: false, priority: ["HIGH"] })
}

Foutafhandeling

Een geslaagd antwoord heeft altijd HTTP-statuscode 200, ook wanneer de GraphQL-query zelf fouten bevat. Controleer de errors-array in de response-body:

{
  "data": null,
  "errors": [
    {
      "message": "Unauthorized",
      "locations": [{ "line": 1, "column": 1 }]
    }
  ]
}

Veelvoorkomende fouten:

  • Unauthorized — je token ontbreekt of is verlopen; authenticeer opnieuw
  • Field does not exist — controleer de veldnaam in het schema
  • Variable … expected type … — een filtervariabele heeft het verkeerde type