API-referentie

Schema-introspectie

GraphQL heeft ingebouwde introspectie: je kunt het schema zelf bevragen om te ontdekken welke queries, types en velden beschikbaar zijn. Dit is handig bij het bouwen van scripts of het verkennen van beschikbare data.

Alle introspectiequery's gebruiken hetzelfde endpoint en dezelfde authenticatie als gewone queries.

Alle beschikbare queries weergeven

{
  __schema {
    queryType {
      fields {
        name
        description
      }
    }
  }
}

Dit geeft de volledige lijst van root query-velden terug — bijvoorbeeld controls_paged, activities_paged, risks_paged enzovoort.

Een specifiek type inspecteren

Gebruik __type om de velden van een type op te vragen:

{
  __type(name: "Activity") {
    fields {
      name
      description
      type {
        name
        kind
        ofType {
          name
          kind
        }
      }
    }
  }
}

Vervang "Activity" door een willekeurige typenaam — bijvoorbeeld "Control", "Risk", "Issue" of "Assessment".

Enum-waarden weergeven

Gebruik dit om de geldige waarden van een enum-type op te vragen:

{
  __type(name: "ActivityDueStatus") {
    enumValues {
      name
    }
  }
}

Veelgebruikte enums om te inspecteren: ActivityDueStatus, Effectiveness, ControlCategory, Priority, IssueType.

Volledig Python-voorbeeld

Dit script authenticeert en print een samenvatting van het schema: alle query-velden en de velden van een opgegeven type.

import requests
import json
import time

TENANT = "{jouw-tenant}"
BASE_URL = f"https://auth.tidalcontrol.com/realms/{TENANT}/protocol/openid-connect"
CLIENT_ID = "portal"
GRAPHQL_URL = "https://portal.tidalcontrol.com/graphql"


def get_token():
    r = requests.post(
        f"{BASE_URL}/auth/device",
        data={"client_id": CLIENT_ID, "scope": "openid"},
    )
    r.raise_for_status()
    device = r.json()

    print(f"\nOpen deze URL in je browser om in te loggen:")
    print(f"  {device['verification_uri_complete']}\n")

    interval = device.get("interval", 5)
    deadline = time.time() + device["expires_in"]

    while time.time() < deadline:
        time.sleep(interval)
        r = requests.post(
            f"{BASE_URL}/token",
            data={
                "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
                "client_id": CLIENT_ID,
                "device_code": device["device_code"],
            },
        )
        if r.status_code == 200:
            print("Authenticatie geslaagd.")
            return r.json()
        body = r.json()
        if body.get("error") == "authorization_pending":
            continue
        if body.get("error") == "slow_down":
            interval += 5
            continue
        r.raise_for_status()

    raise RuntimeError("Authenticatie verlopen.")


def graphql(query, access_token):
    r = requests.post(
        GRAPHQL_URL,
        json={"query": query, "variables": {}},
        headers={"Authorization": f"Bearer {access_token}"},
    )
    r.raise_for_status()
    result = r.json()
    if "errors" in result:
        raise RuntimeError(result["errors"])
    return result["data"]


def list_queries(access_token):
    data = graphql(
        "{ __schema { queryType { fields { name description } } } }",
        access_token,
    )
    fields = data["__schema"]["queryType"]["fields"]
    print(f"\n{len(fields)} query-velden beschikbaar:\n")
    for f in sorted(fields, key=lambda x: x["name"]):
        desc = f.get("description") or ""
        print(f"  {f['name']:<40} {desc}")


def describe_type(type_name, access_token):
    data = graphql(
        f'{{ __type(name: "{type_name}") {{ fields {{ name description '
        f'type {{ name kind ofType {{ name }} }} }} }} }}',
        access_token,
    )
    t = data.get("__type")
    if not t:
        print(f"Type '{type_name}' niet gevonden.")
        return
    print(f"\nVelden van {type_name}:\n")
    for f in t["fields"]:
        type_info = f["type"]
        type_name_str = type_info.get("name") or (type_info.get("ofType") or {}).get("name", "")
        print(f"  {f['name']:<30} {type_name_str}")


if __name__ == "__main__":
    token = get_token()
    access_token = token["access_token"]

    list_queries(access_token)
    describe_type("Activity", access_token)
    describe_type("Control", access_token)