Use Case: GraphQL Open endpoint
Voor de Nederlandse versie, klik hier.
Disclaimer
This page describes the first open GraphQL endpoint that the Cadastre Land Registry makes available as an experiment. This endpoint is maintained with a “best-effort” service level and only concerns open data sources at the Cadastre Land Registry. For this endpoint, we cannot guarantee that the data is always up-to-date and will occasionally (without announcement) renew the endpoint as part of further development. Do you have any questions or comments about this? Then contact us.
Introductie
With GraphQL we overcome a number of common shortcomings of the services we provide on our key registers.
- Delivery of data is demand-driven instead of supply-driven. We give the user the opportunity to query exactly the data he / she needs
- We make inquiries based on objects possible
- Various datasets with an administrative connection can be integrally queried
With GraphQL we define a model of our data in so-called objects and their attributes. For this endpoint, this currently only contains data from the Addresses & Buildings Basic Administration (BAG). A full data model of this source can be found in Figure 1.

The following objects have been made available for this endpoint:
Woonplaats (City)
Woonplaats has the following attributes:- identificatiecode (Identification Code)
- uoi
- woonplaatsnaam (City name)
- woonplaatsstatus (City status)
- geovlak (Geometry); geometry, in the RD (Dutch) coordinate system
- openbareruimten (Public Areas); all public areas (streets) in this city
Openbare Ruimte (Public Area)
Openbare ruimte (or: street) has the following attributes:- identificatiecode (Identification Code)
- uoi
- openbareruimtenaam (Public Area Name)
- openbareruimtestatus (Public Area Status)
- openbareruimtetype (Public Area Type)
- gerelateerdeWoonplaats (Related City); the city in which this public area resides
- nummeraanduidingen (Addresses); all addresses in this public area
Nummeraanduiding (Address)
Nummeraanduiding (or: address) has the following attributes:- identificatiecode (Identification Code)
- uoi
- postcode (Postal Code)
- huisnummer (House Number)
- huisletter (House Letter)
- huisnummertoevoeging (House Number Addition)
- nummeraanduidingstatus (Address Status)
- bijbehorendeOpenbareRuimte (Related Public Area); public area (street) in which this address resides
- hoofdadresVan (Main Address of); the house of which this address is the main address
Verblijfsobject (residence object)
Verblijfsobject (or: residence/establishment) has the following attributes:- identificatiecode (Identification Code)
- uoi
- oppervlakteverblijfsobject (Surface Area)
- verblijfsobjectstatus (Residence Status)
- geopunt (Geometry); geometry, in the RD (Dutch) coordinate system
- hoofdadres (Primary Address); the primary address of this residence
- ligtinpand (Resides in building); the building in which this residence lies
Pand (Building)
Pand (or: building) has the following attributes:- identificatiecode (Identification Code)
- uoi
- bouwjaar (Building Year)
- pandstatus (Building status)
- geovlak (Geometry); geometry, in the RD (Dutch) coordinate system
- vbosinpand (Residences in Building); all residences residing in this building
These objects cover the entire country. Queries can therefore be conducted throughout the Netherlands on the available data through this endpoint.
Kadaster terms
Not many people will describe their house as a residence object (‘Verblijfsobject’), as it is officially included in the Basisadministratie Addresses en Gebouwen (BAG). For a good description of the objects and what they represent, we refer the reader to a reliable source such as that of the Municipality of Amsterdam .
GraphQL Introspection
When you use the GraphQL Playground to set up a query in GraphQL, the user interface supports you in setting up the correct queries. For this step, the endpoint uses the GraphQL Introspection query. As you type, this shows the objects and attributes available in a query. This data model can also be found in Docs on the right of the screen. The data model can also be visualized with GraphQL Voyager. Use this SDL file for that. Within the GraphQL Voyager demo environment you can change the scheme with this SDL file with ‘Change Schema’.
Bevragingen middels een identificatiecode
Each object within the BAG has its own identification code (a 16-digit ‘string’ containing, among other things, references to the municipality involved and the type of object being described). Looking for the identification code of your address or public space? Take a look at the BAGViewer.
Using GraphQL, a query can be performed in two ways, by means of an identification code or by means of a first / offset / filter combination. Take as an example a query in which we query the information of a number designation (address) with identification code 0307200000495314. See, for example, the query below.
query informatieVoorEenIdentificatiecode {
bagnummeraanduiding(identificatiecode: "0307200000495314", peilDatum: "2020-11-13") {
identificatiecode
postcode
huisnummer
huisletter
huisnummertoevoeging
uoi
}
}
In fact, this query behaves like a simple REST API interface on a Number indication, showing all information (attributes) given this object.
Peildatums
We have provided an explicit reference date in the above specific survey. This means that we only retrieve the objects valid at this specific moment. If this reference date is not included, the endpoint takes the current date as the reference date by default. It is therefore currently not possible to query history through this endpoint.
UOI
Kadaster recently worked on a Unique Object Identifier (UOI) in collaboration with the Ministry of the Interior and Kingdom Relations and Fibree. This is integrated in the BAG dataset for this open endpoint.
An object can therefore be used as identification code by means of the same query with an uoi. An example of a query around the same object as in the above query is done as follows.
query informatieVoorEenUOI {
bagnummeraanduiding(uoi: "NL.550e8400-e29b-na0a-0307-200000495314", peilDatum: "2020-11-13")
{
uoi
postcode
huisnummer
huisletter
huisnummertoevoeging
identificatiecode
}
}
Bevragingen middels first/offset en filter
It may happen that the user is not interested in querying a single object, but that a user wants to query a set of objects from, for example, a residence or public space (street). In that case you can use the first and offset arguments. This will query the first (first) objects, starting from the (offset) object. An example survey can be found below. This query queries the first 3 public spaces (streets) for a given place of residence with identification code 1245 (The Hague) and five number designations (addresses) of these public spaces are queried there, starting with number 11.
Note: To limit extreme load on the endpoint, a query should not take longer than 60 seconds. After that, it will give a timeout error. This means that the number chosen for first should not be too high (because this makes the number of retrieved elements very large). The style rule that we use here is not to request batches larger than 1000 at the same time. By working with first and offset, these can be queried in several batches consecutively.
query AdressenInDenHaag
{
## Deze query bevraagt verschillende adressen in Den Haag (code: 1245) op basis van de eerste openbare ruimten
bagwoonplaats(identificatiecode: "1245", peilDatum: "2020-11-13") {
woonplaatsnaam
woonplaatsstatus
uoi
peilDatum
openbareruimten(first: 3) {
openbareruimtenaam
identificatiecode
uoi
nummeraanduidingen(first: 5, offset: 10) {
identificatiecode
uoi
postcode
huisnummer
huisletter
huisnummertoevoeging
}
}
}
}
Bevragingen middels een filter
The starting point with this open GraphQL endpoint is that we want to make a transition with Kadaster from supply-driven to demand-driven surveys. This means that the user chooses which data he / she wants to see, within the data model of the available data. For this reason, we do not filter data from the source in advance. Only the use of a reference date (the default or a chosen variant) is forced.
The user can add a filter himself. Almost every object has an argument filter with which a certain selection can be made. The available columns that can be filtered in the object are all attributes that are also in the object itself. Multiple filters are separated with an ‘and’. An example query with the use of a filter looks like this:
query InfoVoorEenAdres {
## Deze query bevraagt alle informatie uit de BAG voor het hoofdkantoor van de politie in Den Haag
bagnummeraanduiding(filter: "postcode='2585BG' and huisnummer=35") {
identificatiecode
uoi
postcode
huisnummer
huisletter
hoofdadresVan {
identificatiecode
uoi
oppervlakteverblijfsobject
ligtinpand {
identificatiecode
uoi
bouwjaar
}
}
}
}
This query queries (a set of bag number designations) without first and offset. It takes the two attributes of a bag number indication (zip code and house number) and places a filter on these attributes. Note that because zip code is a string, quotation marks (‘’) are required in the filter. Because house number is a number, this is not necessary here. This query therefore queries all number designations with postcode 2585BG and house number 35. From this number designation, the relevant residence object and building are also searched for, including the attributes of these objects relevant to us.
Bevragingen in een programmeertaal (Python)
Do you want to query the above endpoint with something other than the user interface? Which can! The endpoint also serves as a traditional HTTP endpoint where GET requests can be executed to retrieve the necessary data. An example in Python on how to do this can be found below:
from six.moves import urllib
import json
class GraphQLClient:
"""
In deze class wordt connectie gelegd met onze GraphQL endpoint en kan een bevraging worden uitgevoerd
"""
def __init__(self, endpoint):
self.endpoint = endpoint
self.token = None
self.headername = None
def execute(self, query, variables=None, return_json = True):
return self._send(query, variables, return_json)
def inject_token(self, token, headername='Authorization'):
self.token = token
self.headername = headername
def _send(self, query, variables, return_json = True):
data = {'query': query,
'variables': variables}
headers = {'Accept': 'application/json',
'Content-Type': 'application/json'}
if self.token is not None:
headers[self.headername] = '{}'.format(self.token)
req = urllib.request.Request(self.endpoint, json.dumps(data).encode('utf-8'), headers)
try:
response = urllib.request.urlopen(req)
if return_json:
return json.loads(response.read().decode('utf-8'))
else:
return response.read().decode('utf-8')
except urllib.error.HTTPError as e:
raise e
Import the above class into a new script and execute the following statements.
GRAPHQL_ENDPOINT = "https://labs.kadaster.nl/odysseyhackathon"
client = GraphQLClient(GRAPHQL_ENDPOINT)
graphql_query = """ query informatieVoorEenUOI {
bagnummeraanduiding(uoi: "NL.550e8400-e29b-na0a-0307-200000495314", peilDatum: "2020-11-13")
{
uoi
postcode
huisnummer
huisletter
huisnummertoevoeging
identificatiecode
}
}"""
result = client.execute(graphql_query)
print(result['data'])