API’s, open data & integratie

Een relatieve API-link is geen tekst om achter een domein te plakken

De kern

Leg eerst de basis-URI vast. Resolutie bepaalt een bestemming; zij verleent geen toestemming om die bestemming te bezoeken.

Wat past bij jou? Beantwoord 30 korte vragen →

Maak van een link twee beslissingen

Een respons kan een relatieve resourceverwijzing bevatten. De consumer moet eerst bepalen welke URI daarmee bedoeld wordt en daarna of die bestemming binnen de afgesproken vervolgscope valt. Door die beslissingen te scheiden kun je een link beoordelen zonder hem op te vragen. Dat is nuttig bij detailweergaven en downloads, ook wanneer er helemaal geen paginering is.

RFC 3986 definieert resolutie tegen een basis en onderscheidt onder meer pad, query en authority.[3] Een verwijzing die alleen een query bevat, is dus niet hetzelfde als een nieuw padsegment. De lokale proef hieronder kiest expliciet de opgegeven basis-URI; een representatie met een eigen basismechanisme vraagt eerst interpretatie van dat formaat.

Een bestemmingskaart zonder netwerkverkeer

  • Basis: de URI die voor deze representatie als basis is vastgesteld.
  • Letterlijke verwijzing: bewaar pad- en querybetekenis; maak er geen kleine letters van.
  • Opgeloste URI: laat een resolutiefunctie het werk doen, niet stringconcatenatie.
  • Vervolgstatus: ready betekent alleen dat de lokale originvergelijking slaagt; hold vraagt een afzonderlijke beslissing.

De verzonnen basis hieronder eindigt op items/7 en bevat lang=nl. De verwijzing 8 vervangt het laatste padsegment. ?lang=en behoudt dat pad en vervangt de query. /health gaat naar de oorsprongsroot. Een authority-verwijzing naar een andere host wordt wel opgelost maar vastgehouden. Geen van de voorbeeldhosts wordt benaderd.

Volledige lokale proef en letterlijke uitvoer

Gebruik Kopieer code om alle code exact te kopiëren. Handmatig selecteren kan de laatste regelovergang weglaten.

import json
from urllib.parse import urljoin, urlsplit

def origin(u):
    p = urlsplit(u)
    if p.scheme != "https" or not p.hostname or p.username is not None or p.password is not None:
        raise ValueError("unsupported authority")
    return (p.scheme, p.hostname.lower(), p.port if p.port is not None else 443)

def destination(base, reference):
    if type(reference) is not str or any(ord(c) in range(33) for c in reference):
        raise ValueError("invalid reference for this example")
    base_origin = origin(base)
    resolved = urljoin(base, reference)
    target_origin = origin(resolved)
    if urlsplit(resolved).fragment:
        return {"state": "hold_fragment", "url": resolved}
    return {"state": "ready" if target_origin == base_origin else "hold_external", "url": resolved}

# Reserved example hostnames, never contacted.
base = "https://api.example.test/v1/items/7?lang=nl"
cases = ["8", "?lang=en", "/health", "//other.example.test/x", "#part"]
results = [destination(base, x) for x in cases]
assert results[0]["url"] == "https://api.example.test/v1/items/8"
assert results[1]["url"] == "https://api.example.test/v1/items/7?lang=en"
assert [x["state"] for x in results] == ["ready", "ready", "ready", "hold_external", "hold_fragment"]
assert destination(base, "https://api.example.test:443/x")["state"] == "ready"
assert destination(base, "https://api.example.test:0/x")["state"] == "hold_external"
for bad in ["http://api.example.test/x", "https://user@api.example.test/x", "bad link"]:
    try:
        destination(base, bad)
    except ValueError:
        pass
    else:
        raise AssertionError("unsupported reference accepted")
print(json.dumps({"destinations": results, "rejected": 3}, sort_keys=True))

{"destinations": [{"state": "ready", "url": "https://api.example.test/v1/items/8"}, {"state": "ready", "url": "https://api.example.test/v1/items/7?lang=en"}, {"state": "ready", "url": "https://api.example.test/health"}, {"state": "hold_external", "url": "https://other.example.test/x"}, {"state": "hold_fragment", "url": "https://api.example.test/v1/items/7?lang=nl#part"}], "rejected": 3}

De drie geweigerde gevallen gebruiken HTTP, gebruikersinformatie in de authority of een spatie in de verwijzing. Een expliciete HTTPS-poort 443 telt in deze oefening als dezelfde origin. Fragmenten krijgen een eigen hold_fragment: de code verzint niet hoe een client zo’n verwijzing binnen een document moet afhandelen. De labels zijn beleidsuitkomsten, geen HTTP-statussen.

Wat ready nadrukkelijk niet betekent

Een URI op dezelfde origin kan alsnog buiten de afgesproken resourcefamilie vallen. De proef heeft geen padallowlist, redirectbeleid, DNS-controle of HTTP-client en is geen algemene URL-veiligheidsvalidator. Hij behandelt ook geen afwijkende URI-schemes, volledige URI-normalisatie of alle vormen van Unicode. Gebruik hem uitsluitend om de scheiding tussen resolutie en vervolgbesluit te oefenen.

Noteer bij een echte overdracht basisbron, verwijzingsveld, opgeloste bestemming en verantwoordelijke voor uitzonderingen. Bevestig toegang en brongebruik apart voordat je verzoeken toevoegt. Deze brononderbouwde offline oefening bewijst geen beschikbaarheid, complete dataset of toegangsrecht. Zij blijft een concept met feiten-, originaliteits- en vertaalreview in afwachting.

Bronnen & onderbouwing

  1. Oorspronkelijke brontitel: RFC 3986 — Uniform Resource Identifier (URI): Generic Syntax

    Geraadpleegd: 2026-10-18T22:58:30.463656+00:00

Een keuzehulp voor jouw situatie

Je antwoorden blijven in deze pagina tot je ze zelf indient. Niet-opgeslagen antwoorden verdwijnen bij herladen.

Opslaan is nog niet ingesteld. Er worden geen antwoorden of contactgegevens verzonden of bewaard.

Welke integratiestap helpt je verder?

30 korte vragen over API’s en gegevens koppelen. Een antwoord kiezen gaat automatisch verder. Je kunt teruggaan, wijzigen en overslaan. Dit is een praktische leesroute, geen wetenschappelijke test.

JavaScript is nodig voor deze keuzehulp.

Contact & correcties

Stuur een vraag of meld een correctie via dit formulier.

Alleen na Verzenden worden je naam, e-mailadres, onderwerp en bericht naar de contactdienst gestuurd om je bericht te behandelen. Dit is geen nieuwsbriefinschrijving. Niet-verzonden tekst verdwijnt bij herladen. Privacyinformatie

Voorbeeld: verzenden is niet ingesteld. Dit formulier verzendt of bewaart niets.

Je bericht — alle velden zijn verplicht