Documentatie SEARCH API
- 1 Inleiding
- 2 Dynamische API-documentatie
- 3 Technische documentatie (Github)
- 4 Syntax en technische opbouw
- 5 Regels en weetjes bij het gebruik van de API
- 6 Veel voorkomende bevragingen
- 7 Organisatieregister API-v1
- 8 Omgaan met grote hoeveelheden data
- 9 Omgaan met wijzigingen in data (enkel wijzigingen opvragen)
- 10 Voorbeeld code
Inleiding
Deze pagina beschrijft de API die je als gebruiker in staat stelt om zelf een aantal services te definiëren. Je vindt uitleg over de taal en syntax die je kan gebruiken en een oplijsting van de verschillende klassen en attributen die via de API bevraagbaar zijn.
We werken aan de uitbouw van een aantal voorgedefinieerd services. Ondertussen stelt deze informatie je in staat zelf een aantal requests samen te stellen. Voor meer info, uitleg of ondersteuning kan je steeds contact opnemen met digitaal.vlaanderen@vlaanderen.be
Dynamische API-documentatie
https://api.wegwijs.vlaanderen.be/docs/api-documentation.html#tag/Zoeken
(Swaggerdocumentatie, downloadknop beschikbaar)
Technische documentatie (Github)
Syntax en technische opbouw
De API’s in dit verhaal zijn standaard REST-gebaseerd en stuurt als respons JSON-files over HTTPS terug. Concreet spreken de verschillende mogelijke API’s een ‘index’ aan. Zo’n ‘index’ is op zijn beurt een representatie van (een deel van) het organisatieregister.
In functie van de verschillende contexten/functionaliteiten kunnen verschillende ‘indices’ opgebouwd worden die – mits de correcte indexering – zeer performant kunnen inspelen op uw vraag.
Centraal worden er vanuit Digitaal Vlaanderen een aantal indices ter beschikking gesteld die kunnen bevraagd worden via een reeks van requests. Tenzij anders vermeld zullen de indices standaard de totaliteit van het organisatieregister in termen van organisatie-scope bevatten. Per API wordt meegegeven wat deze omvat in termen van inhoud (welke velden, data).
Eens je weet welke API het best aansluit bij je behoefte, is het zaak of een standaard geformuleerde request aan te spreken of eventueel zelf je request op te bouwen.
Voor het opbouwen moet er een bepaalde syntax gehanteerd worden.
De standaardaanspreking is steeds als volgt : https://api.wegwijs.vlaanderen.be/, gevolgd door het versie-nummer van de api en de verdere zoekparameters.
Regels en weetjes bij het gebruik van de API
een standaard ‘search’-commando doorzoekt de volledige cluster op de opgegeven term
nemen we als zoekparameter verschillende woorden zonder meer, dan wordt er gezocht op elk voorkomen van één van die woorden. De url https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=Informatie Vlaanderen zal zoeken op alles waar of Informatie of Vlaanderen in voorkomt
willen we zoeken op de volledige string “Informatie Vlaanderen” (en niets anders), dan plaatsen we deze tussen dubbele quotes. Dat wordt dus https://api.wegwijs.vlaanderen.be/v1/search/organisations?q="Informatie Vlaanderen”
het *-teken dient als algemeen jokerteken en geeft alles terug. De url https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=* zou dus alles teruggeven uit de API
er kan ‘fuzzy’ gezocht worden via de tilde ‘~’. De url https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=Beleidsdomien~ (let op de spelfout) geeft alles waarin ‘beleidsdomein’ voorkomt; ook bij een verkeerde spelling.
willen we een waarde zoeken binnen een bepaald veld, dan vermelden we de veldnaam:parameter. De url https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=ovoNumber:OVO002949 geeft bvb. één hit terug, m.n. het Agentschap Informatie Vlaanderen (met als identificator OVO002949).
met de commando’s AND/OR kunnen we complexere zaken bevragen, al dan niet in combinatie met haakjes ‘()’. Hierbij gelden wiskundige voorrangsregels.
Tenslotte kun je ook vierkante haakjes ‘[ waarde1 TO waarde2 ]’ gebruiken om alles binnen een bepaald bereik (tussen waarde1 en waarde2) te zoeken. De URL https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=validity.start:[ * TO 2016-02-16] zal bvb. alle organisaties weergeven die van start gingen voor 16 februari 2016.
Veel voorkomende bevragingen
Vraag | Query |
---|---|
zoeken naar een organisatie op basis van de OVO-code | https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=ovoNumber:OVO002949 |
zoeken naar een organisatie op basis van de naam van de organisatie (geen exacte match) | |
zoeken naar een organisatie op basis van de naam van de organisatie (exacte match) hoofdlettergevoelig | |
zoeken naar een organisatie op basis van het KBO-nummer | https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=kboNumber:0244142664 |
zoeken naar een organisatie op basis van de Vlimpers-code (exacte match) | https://api.wegwijs.vlaanderen.be/v1/search/organisations?q=keys.value.keyword:"1 C 3E" |
Organisatieregister API-v1
Conform afspraken binnen de URI-strategie werken we binnen het aanbod van webservices op het organisatieregister in verschillende versies.
Versie 1 van de API is vooral gestuurd vanuit organisatie-standpunt. Je stelt een vraag en krijgt een volledige set van organisatiegerelateerde informatie terug.
ondersteunt 2 commando’s:
een GET-command dat voorziet in eenvoudige URL-based queries om data op te zoeken
een POST-command dat het mogelijk maakt om meer complexe queries te gaan opstellen
Voor het GET-command is de structuur vrij simpel en laagdrempelig. Hiermee is het slechts mogelijk om per object (klasse zoals verder in dit document bepaald) één filter toe te passen. Je kan bvb. wel alle organisaties opzoeken wiens naam begint met de term ‘Beleidsdomein’, maar je kan dat niet combineren met een filter op tijd in hetzelfde object.
Het POST-command is een meer gesofisticeerde manier om de databank te bevragen, maar vereist wel meer voorkennis en een console om de vraag te lanceren. Hiermee kun je geneste queries opstellen (bvb. alle organisaties waarvan de naam begint met ‘Beleidsdomein’, met daarbinnen enkel degene die een einddatum hebben).
Het GET-command werkt als volgt :
De algemene structuur – https://api.wegwijs.vlaanderen.be/v1 – gevolgd door :
/search/{indexnaam}?q={zoekterm}&fields={filter}&offset={start}&limit={aantal}
Waarbij:
Indexnaam, met momenteel keuze uit 3 endpoints waarbinnen je kan zoeken:
organisations (organisaties)
people (personen, bv. hun functies of hoedanigheden)
bodies (organen)
Zoekterm: Elasticsearch QueryString zoekterm
[Optioneel] Filter: veldnamen die in respons zullen zitten
[Optioneel] Offset: startpunt van zoekresultaten (voor paging bijvoorbeeld)
[Optioneel] Limit: aantal resultaten, default 100 (ook voor paging)
Bijvoorbeeld:
/search/organisations?q=Vlaanderen&fields=name,ovoNumber&offset=10&limit=1000
Het POST-commando geeft zoals vermeld veel meer mogelijkheden, oa. geneste zoekopdrachten binnen één klasse. Om een POST-opdracht te geven, kun je niet werken via een URL. Je moet een script op de cluster laten draaien via een scripting-tool (vb. POSTMAN).
De standaardsyntax bestaat uit :
/search/{indexnaam}? fields={filter}&offset={start}&limit={aantal}
{
…….. query object
}
Waarbij de parameters dezelfde zijn als bij het GET-commando, behalve dat je geen zoekterm, maar een volledig zoekobject kan meegeven in de body.
Bijvoorbeeld:
{
"nested" : {
"path" : "capacities",
"query" : {
"bool" : {
"must" : [
{ "match" : {"capacities.capacityName" : "HR business partner"} },
{ "bool": {
"should": [
{ "range" : {"capacities.validity.end" : {"gte" : "now/d"}} },
{ "bool": {
"must_not": [ { "exists": { "field": "capacities.validity.end"}} ]
} }
]
}}
]
}
}
}
}
Dit geeft dan bvb. een overzicht van alle HR business partners.
Omgaan met grote hoeveelheden data
By default beperkt de api zich tot 100 hits en met de optie ‘&limit=’ kan dit opgetrokken worden tot 10.000. Maar wat als je om een bepaalde reden meer dan 10.000 organisaties wil opvragen in één request?
Voor dat scenario kan je volgende werkwijze volgen :
Maak een request zoals je normaal doet, maar maak geen gebruik van ‘offset’ of ‘limit’. Gebruik in plaats daarvan ‘scroll=true’
https://api.wegwijs.vlaanderen.be/v1/search/people?q=changeId:[43625 TO *]&sort=changeId,id&scroll=true
Dit geeft 100 resultaten die je gewoon kan verwerken. In aanvulling krijg je hierdoor ook een http-header x-search-metadata die een Scroll-Id bevat, samen met nog wat andere info. (deze header is een json-string).
Na deze request heb je 30 seconden de tijd om een call te doen naar https://api.wegwijs.vlaanderen.be/v1/search/people/scroll?id=SCROLLID
Deze zal je de volgende pagina geven (opnieuw 100 items), samen met de x-search-metadata header en een nieuwe scrollId.
Herhaal dit proces tot je geen nieuwe items meer krijgt.
Deze methodiek geeft je de zekerheid dat je geen organisaties over het hoofd ziet door veranderingen tussen calls. Dit werkt op een snapshot genomen bij je eerste request.
Als je om één of andere reden niet in de mogelijkheid bent 100 items te verwerken in 30 seconden, is het best zelf logica te voorzien om de data op te slaan en nadien te verwerken.
Omgaan met wijzigingen in data (enkel wijzigingen opvragen)
Als je enkel wijzigingen wil binnenhalen op de reeds ingelezen data kan je gebruik maken van de changeId.
Maak een request voor alle organisaties met als zoekterm de laatste changeId + 1 om alle nadien gewijzigde informatie te verkrijgen. Het changeId geeft aan dat informatie m.b.t. de organisatie gewijzigd is (maar geeft niet aan welke informatie gewijzigd is, bv. een naamswijziging of een nieuwe woordvoerder).
"changeId": 628782,
"changeTime": "2020-04-13",
"id": "743efdbf-42a5-4b62-9c27-956bbbcfd66c",
"name": "Centrum voor Jeugdtoerisme",
Voorbeeld code
Onderstaande code, geschreven in Python, zal alle organisaties opvragen wiens naam het woord dienst bevat en voor deze organisaties een aantal gegevens tonen:
OVO-code
Naam van de organisatie
of deze actief is
de naam van de eventuele moeder-organisatie
import requests
import json
from datetime import date
def main():
# Samenstellen van de URL
base_url = "https://api.wegwijs.vlaanderen.be/v1/search/organisations"
query_string = "?q=name:dienst"
url_string = base_url + query_string + "&scroll=true"
aantal_organisaties = 0
# Deze op het eerste zicht oneindige lus wordt in de code onderbroken wanneer er
# geen verdere resultaten meer beschikbaar zijn.
while True:
response = requests.get(url_string)
res = response.json()
# lus afbreken als er geen verdere resultaten meer zijn
if len(res) == 0:
break
aantal_organisaties += len(res)
for org in res:
print(org["ovoNumber"] , org["name"], "-", isvalid(org["validity"]), "-", getParent(org))
resp_header = json.loads(response.headers["x-search-metadata"])
url_string = base_url + "/scroll?id=" + resp_header["scrollId"]
print(f'\n==> {aantal_organisaties} organisaties gevonden')
def getParent(org):
"""
zoeken naar het attribuut parents en daarbinnen enkel de geldige lijn opzoeken
Van deze lijn wordt de naam van de parent opgehaald
Noot: in theorie is het niet mogelijk, maar bij wijze van code voorbeeld en uit veiligheidsoverwegingen
wordt er ook rekening mee gehouden dat er 2 actieve parents zouden kunnen zijn.
"""
if "parents" in org:
# wat volgt is de uitgeschreven versie van de volgende python constructie:
# return "-".join([key[field] for key in org["parents"] if isvalid(key["validity"])])
resultaat = ""
for key in org["parents"]:
if isvalid(key["validity"]):
if len(resultaat)>0:
resultaat += "-"
resultaat += key["parentOrganisationName"]
return resultaat
else:
return ""
def isvalid(val, compare=date.today()):
valid = True
if "start" in val:
if date.fromisoformat(val["start"]) > compare: valid = False
if "end" in val:
if date.fromisoformat(val["end"]) < compare: valid = False
return valid
if __name__ == "__main__":
main()