Möchtest Du den gesamten Artikel lesen? Und vielleicht sogar den Artikel im PDF-Format und die Beispieldateien herunterladen? Dann hole Dir den Artikel gleich hier - völlig kostenlos!
Bild 1: Öffnen des Builder Hubs
Das Datenbanksystem Airtable bietet eine Menge Funktionen an, aber offeriert leider keine direkte Schnittstelle, mit der man direkt etwa von Access auf die enthaltenen Daten zugreifen kann. Es gibt zwar kostenpflichtige ODBC-Schnittstellen von Drittanbietern, aber wir wollen den Zugriff selbst programmieren. Wie für moderne SaaS-Tools üblich, bietet auch Airtable eine Rest-API als Schnittstelle für den Zugriff auf die Daten an. Diese wollen wir im vorliegenden Artikel untersuchen und zeigen, wie wir auf die enthaltenen Daten zugreifen und Informationen aus einer lokalen Datenbank in eine Airtable-Datenbank schreiben können.
Der erste Schritt für den Zugriff auf eine Rest-API ist immer die Ermittlung des dazu notwendigen API-Schlüssels. Diesen holen wir uns nach dem Anmelden auf airtable.com, indem wir zunächst oben rechts auf den Button für unser Konto klicken und aus dem nun erscheinenden Menü den Eintrag Builder Hub auswählen (siehe Bild 1).
Bild 1: Öffnen des Builder Hubs
Danach landen wir im Builder Hub, wo wir über den Menübefehl Persönliche Zugangstoken eine Schaltfläche namens Token erstellen einblenden können (siehe Bild 2).
Bild 2: Anlegen eines Tokens
Persönlicher Zugangstoken
Neben dem persönlichen Zugangstoken gibt es noch OAuth-Token. Für das Synchronisieren einer Access-Datenbank mit einer Airtable-Datenbank ist das persönliche Zugangstoken die beste Lösung.
Das OAuth-Token benötigen wir nur, wenn wir eine App entwickeln, mit der wir im Namen andere Benutzer auf deren Airtable-Datenbanken zugreifen wollen.
Bereiche für das Token festlegen
Nach dem Anlegen des persönlichen Tokens legen wir fest, für welche Bereiche dieses Token gelten soll. Diese wählen wir aus, indem wir die Liste der verfügbaren Bereiche mit einem Klick auf Einen Bereich hinzufügen öffnen und dort die gewünschten Bereiche hinzufügen (siehe Bild 3).
Bild 3: Hinzufügen von Bereichen
Wir wollen ausgiebig experimentieren, also fügen wir die Bereiche aus Bild 4 hinzu.
Bild 4: Alle notwendigen Bereiche
Anschließend wollen wir noch festlegen, auf welche Datenbanken in unserer Airtable-Instanz sich die hinzugefügten Berechtigungen auswirken sollen. Das erledigen wir im gleichen Bereich weiter unten, wo wir mit einem Klick auf Alle Ressourcen hinzufügen direkt alle Datenbanken gleichzeitig freischalten oder mit Eine Base hinzufügen gezielt eine Datenbank für den Zugriff auswählen (siehe Bild 5).
Bild 5: Hinzufügen der Datenbank, auf die wir zugreifen wollen
Nun wird das Token erstellt und wir können es aus dem nun erscheinenden Dialog in die Zwischenablage kopieren (siehe Bild 6).
Bild 6: Das fertige Token
Achtung: Das Token können wir nur einmalig abrufen. Also fügen wir es direkt als Wert einer Konstanten namens cStrAPIToken in ein neues VBA-Modul im VBA-Projekt der Datenbank ein, von der aus wir auf die Airtable-Datenbank zugreifen wollen.
Im gleichen Zuge legen wir auch direkt noch eine weitere Konstante für die Basis-URL für die Rest-API-Zugriffe fest:
Private Const cStrBaseURL As String = "https://api.airtable.com/v0/" Private Const cStrAPIToken As String = "pat6TTvfq5Uq8avqs.7baxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxc7553910b58"
ID der Airtable-Datenbank ermitteln
Außerdem benötigen wir die ID der Airtable-Datenbank, mit der wir arbeiten wollen. Dazu öffnen wir die folgende URL unter der wir auch noch andere wichtige Informationen finden:
https://airtable.com/developers/web/api/introduction
Hier sehen wir alle Datenbanken des aktuellen Kontos (siehe Bild 7). Also klicken wir die gewünschte Datenbank an.
Bild 7: Übersicht der Airtable-Datenbanken
Anschließend erscheint eine Ansicht, die unscheinbar in einem Absatz die ID der zu verwendenden Datenbank enthält (siehe Bild 8).
Bild 8: Ermitteln der ID der Datenbank
Auch diese kopieren wir zunächst in die Zwischenablage und fügen sie als Wert einer weiteren Konstanten namens cStrBaseID ein:
Private Const cStrBaseID As String = "appxxxxxxxxxxxxxxx" ''Kundenverwaltung
Achtung: Wir benötigen die ID ohne den abschließenden Punkt.
Beispiele für die verschiedenen Datenbankoperationen
Danach schauen wir uns diese Seite genauer an. Links in der Übersichtsleiste sehen wir nämlich die Tabellen unserer Datenbank (siehe Bild 9). Öffnen wir einen dieser Einträge, sehen wir Untereinträge, die nach dem Anklicken weitere Informationen liefern – zum Beispiel, wie man Datensätze der jeweiligen Tabelle ausgibt, einzelne Datensätze ermittelt, diese erstellt, aktualisiert oder löscht.
Bild 9: Beispiele für die verschiedenen Datenbank-Operationen
Auf der rechten Seite sehen wir eine Beschreibung und den notwendigen JSON-Code, den wir mit dem jeweiligen Aufruf der Rest-API übergeben müssen.
Liste der Tabellen ermitteln
Mit der Rest-API können wir verschiedene Informationen unserer Airtable-Datenbank abrufen. Bevor wir in das Abfragen, Bearbeiten oder Löschen von Daten aus Airtable-Tabellen einsteigen, ermitteln wir erst einmal die grundlegenden Informationen der in der Datenbank enthaltenen Tabellen.
Dazu verwenden wir die Prozedur GetAirtableTables aus Listing 1. Hier erstellen wir ein Objekt des Typs XMLHTTP60, mit dem wir auf die Rest-API zugreifen. Wir stellen in strURL die Adresse für den Zugriff auf unsere Datenbank zusammen, wobei wir die ID der Datenbank aus der oben definierten Konstanten cStrBaseID integrieren. Die URL sieht nun beispielsweise wie folgt aus:
Sub GetAirtableTables() Dim objXMLHTTP As MSXML2.XMLHTTP60 Dim objJSON As Object Dim strURL As String Dim i As Integer Set objXMLHTTP = New MSXML2.XMLHTTP60 strURL = cStrBaseURL & "meta/bases/" & cStrBaseID & "/tables" objXMLHTTP.Open "GET", strURL, False objXMLHTTP.setRequestHeader "Authorization", "Bearer " & cStrAPIToken objXMLHTTP.send Debug.Print GetJSONDOM(objXMLHTTP.responseText, True) Set objJSON = ParseJson(objXMLHTTP.responseText) Debug.Print "TabelleID:" & vbTab & vbTab & vbTab & vbTab & vbTab & "Tabellenname:" For i = 1 To objJSON.Item("tables").Count Debug.Print objJSON.Item("tables").Item(i).Item("id"), objJSON.Item("tables").Item(i).Item("name") Next i End Sub
Listing 1: Prozedur zum Auslesen aller Tabellen der Airtable-Datenbank
https://api.airtable.com/v0//meta/bases/app...RrJh/tables
Das API-Token aus cStrAPIToken übergeben wie mit dem RequestHeader namens Authorization. Dann starten wir den Aufruf und erhalten das Ergebnis mit objXMLHTTP.Response im JSON-Format.
Dieses verarbeiten wir mit der Funktion ParseJson aus dem Modul mdlJSON in ein Objekt aus Dictionary– und Collection-Elementen, auf das wir dann zugreifen können. Damit wir wissen, wie wir auf die enthaltenen Elemente zugreifen können, geben wir diese mit der GetJSONDOM-Funktion im Direktbereich aus. Dadurch sehen wir, dass wir auf die Tabellendaten beispielsweise wie folgt zugreifen können:
objJson.Item("tables").Item(1).Item("id"): tblMUktvNEo0FPRYb objJson.Item("tables").Item(1).Item("name"): Bestellungen
Daraus können wir eine For…Next-Schleife ableiten, um die Werte für die Felder id und name auszulesen und einzeln im Direktbereich auszugeben. Das Ergebnis sieht wie folgt aus:
TabelleID: Tabellenname: tblMUktvNEo0FPRYb Bestellungen
Damit haben wir nun auch die ID der Tabelle, mit der wir in den folgenden Abschnitten auf die Tabelle Bestellungen zugreifen und diese auslesen, bearbeiten oder um neue Datensätze ergänzen können.
Grundlegender Aufbau eines Aufrufs der Rest-API für den Tabellenzugriff
Airtable stellt eine Basis-URL für den Zugriff auf die Tabellendaten einer Airtable-Datenbank zur Verfügung.
Wir erstellen eine Basisfunktion mit verschiedenen Parametern, um alle Operationen abzudecken. Den ersten Teil dieser Funktion finden wir in Listing 2. Hier sehen wir zunächst die Parameter der Funktion:
Public Function Airtable_CRUD(strTable As String, strMethod As String, strRequest As String, _ Optional strId As String, Optional strResponse As String, Optional intErrorNumber As Integer, _ Optional strErrorDescription As String , ParamArray varParameters() As Variant) As Boolean Dim strURL As String Dim objRequest As MSXML2.XMLHTTP60 strURL = "https://api.airtable.com/v0/" & cStrBaseID & "/" & strTable If Not Len(strId) = 0 Then strURL = strURL & "/" & strId End If If Not IsMissing(varParameters) Then strURL = strURL & "?" & ParseParameters(varParameters) End If Set objRequest = New MSXML2.XMLHTTP60 With objRequest .Open strMethod, strURL, False .setRequestHeader "Authorization", "Bearer " & cStrAPIToken .setRequestHeader "Content-Type", "application/json" .send strRequest End With strResponse = objRequest.responseText intErrorNumber = objRequest.status ...
Listing 2: Funktion zum Erstellen, Aktualisieren, Lesen und Löschen von Datensätzen in Tabellen (Teil 1)
- strTable: Nimmt den Namen der zu bearbeitenden oder zu lesenden Tabelle entgegen.
- strMethod: Nimmt die Methode für die auszuführende Operation entgegen. Die zu verwendenden Werte inklusive weiterer benötigter Informationen beschreiben wir weiter unten.
- strRequest: JSON-Dokument mit dem Inhalt der gewünschten Änderung, also zum Beispiel der Daten für den anzulegenden Datensatz oder eines zu ändernden Datensatzes
- strId: ID des zu bearbeitenden oder zu löschenden Datensatzes
- strResponse: Antwort der Rest-API, falls eine geliefert wird
- intErrorNumber: Fehlernummer beziehungsweise Statuswert. Im Erfolgsfall 200, die übrigen Werte sind im Code beschrieben.
- strErrorDescription: Beschreibung des Fehlers, falls der Statuswert nicht 200 lautet.
- varParameters: Paramarray, das die Name-Wert-Paare für eventuelle URL-Parameter enthält.
Die Funktion stellt im ersten Schritt die URL für den Zugriff auf die Rest-API zusammen. Diese besteht aus der Basis-URL (cStrBaseURL), der ID für die zu verwendende Datenbank (cStrBaseID), einem Slash und dem Namen der Tabelle oder der ID der Tabelle – hier verwenden wir der Einfachheit halber den Namen.
Die Verwendung der ID hätte den Vorteil, dass wir in der Datenbank auch einmal den Namen der Tabelle ändern könnten und der Code immer noch funktioniert. Die IDs haben wir zuvor mit der Prozedur GetAirtableTables ermittelt. Die URL könnte nun wie folgt aussehen:
https://api.airtable.com/v0/app...RrJh/Bestellungen
Wenn wir einen vorhandenen Datensatz bearbeiten oder löschen wollen, können wir den Parameter strID verwenden. Damit übergeben wir die ID des zu bearbeitenden Datensatzes.
Diese bekommen wir, indem wir den Datensatz zunächst abfragen. Auch dazu sehen wir uns später ein Beispiel an.
Die ID aus strID hängen wir, soweit vorhanden, im nächsten Schritt an die URL an. Die URL zum Bearbeiten oder Löschen eines Datensatzes würde wie folgt aussehen:
https://api.airtable.com/v0/app...RrJh/Bestellungen/recElpIemkgW9bBQC
Danach folgt die Verarbeitung eventueller Parameter. Wie wir einen solchen Parameter zusammenstellen, beschreiben wir weiter unten.
Da wir auch mehrere Parameter übergeben können, verwenden wir dazu ein ParamArray. Wir prüfen im nächsten Schritt mit IsMissung, ob varParameters Parameter enthält. Ist das der Fall, parsen wir diese in der Funktion ParseParameters, die wir im Anschluss beschreiben.
Nun erstellen wir ein Objekt des Typs MSXML2.XMLHTTP. Seiner Open-Funktion übergeben wir die Methode aus strMethod (also GET, POST, PUT oder DELETE), die vorher zusammengestellte URL und den Wert False für den Parameter varAsync, damit der Aufruf asynchron ausgeführt und der Code erst nach dem Beenden des Aufrufs weiterläuft.
Für das XMLHTTP60-Objekt legen wir nun mit setRequestHeader das Authentifizierungstoken fest sowie den Inhaltstyp, hier application/json.
Schließlich senden wir den Aufruf mit der send-Methode ab. Diese erhält den Wert des Parameters strRequest. Diesen benötigen wir nur, wenn wir beispielsweise Änderungen an einem Datensatz durchführen oder einen Datensatz hinzufügen wollen. strRequest füllen wir dann vor dem Aufruf mit einem JSON-Dokument, das die Werte für den zu ändernden oder anzulegenden Datensatz enthält – mehr dazu in den Beispielen weiter unten.
Die Antwort erhalten wir mit dem responseText-Parameter von objXMLHTTP60.
Außerdem liefert status eine Information darüber, ob der Aufruf erfolgreich war (200) oder ob ein Fehler ausgelöst wurde – beispielsweise durch ein ungültiges JSON-Dokument in strRequest, eine ungültige URL oder einen anderen Fehler.
Den Wert der Eigenschaft status werten wir im zweiten Teil der Funktion aus Listing 3 in einer ersten Select Case-Bedingung aus, die zunächst prüft, ob status den Wert 200 (erfolgreicher Aufruf, Rückgabewert True) oder einen anderen Wert enthält (Rückgabewert False).
.... Select Case objRequest.status Case 200 Airtable_CRUD = True Case Else Select Case objRequest.status Case 400 strErrorDescription = "Bad Request. The request encoding is invalid; the request can''t be " _ & "parsed as a valid JSON." Case 401 strErrorDescription = "Unauthorized. Accessing a protected resource without authorization " _ & "or with invalid credentials." Case 402 strErrorDescription = "Payment Required. The account associated with the API key making " _ & "requests hits a quota that can be increased by upgrading the Airtable account plan." Case 403 strErrorDescription = "Forbidden. Accessing a protected resource with API credentials that " _ & "don''t have access to that resource." Case 404 strErrorDescription = "Not Found. Route or resource is not found. This error is returned " _ & "when the request hits an undefined route, or if the resource doesn''t exist (e.g. has " _ & "been deleted)." Case 413 strErrorDescription = "Request Entity Too LargeThe request exceeded the maximum allowed " _ & "payload size. You shouldn''t encounter this under normal use." Case 422 strErrorDescription = "Invalid Request. The request data is invalid. This includes most of " _ & "the base-specific validations. You will receive a detailed error message and code " _ & "pointing to the exact issue." Case 429 strErrorDescription = "Too Many Requests. The API is limited to 5 requests per second per " _ & "base. You will receive a 429 status code and a message ''Rate limit exceeded. Please " _ & "try again later'' and will need to wait 30 seconds before subsequent requests will " _ & "succeed. To learn more about rate limits, please visit our Rate Limits guide." Case 500 strErrorDescription = "Internal Server ErrorThe server encountered an unexpected condition." Case 502 strErrorDescription = "Bad GatewayAirtable ''s servers are restarting or an unexpected outage is " _ & "in progress. You should generally not receive this error, and requests are safe to retry." Case 503 strErrorDescription = "Service UnavailableThe server could not process your request in time. " _ & "The server could be temporarily unavailable, or it could have timed out processing " _ & "your request. You should retry the request with backoffs." End Select Airtable_CRUD = False End Select Set objRequest = Nothing End Function
Listing 3: Funktion zum Erstellen, Aktualisieren, Lesen und Löschen von Datensätzen in Tabellen (Teil 2)
In diesem Fall folgt eine zweite Select Case-Bedingung, in der wir den Fehlercode auswerten und in den Rückgabeparameter strErrorDescription eintragen.
Parameter für das Auflisten von Datensätzen
Wenn wir eine Liste von Datensätzen ermitteln wollen, übergeben wir für den Parameter strMethod den Wert GET. Außerdem können wir über varParameters mit Name-Wert-Paaren weitere Einstellungen für das Ermitteln der gewünschten Datensätze festlegen. Diese lauten folgendermaßen:
- fields: Hiermit können wir angegeben, welche Feldinhalte zurückgegeben werden sollen. Beispiel: fields=Name liefert nur die Daten des Feldes Name zurück. Wenn wir zwei Felder erhalten wollen, geben wir diese als zwei Parameter an: “fields=Name”, “fields=Produkt”.
- filterByFormula: Hier geben wir einen Filterausdruck an. Ein Beispiel lautet: {Name} = ”Visual Basic Entwickler”. Dieser muss URL-kodiert werden, sodass zusammen mit dem Parameternamen anschließend ein Ausdruck wie dieser herauskommt: filterByFormula=%7BName%7D%20%3D%20%27Visual%20Basic%20Entwickler%27
- maxRecords: Hiermit geben wir die maximale Anzahl zurückzuliefernder Datensätze an, zum Beispiel maxRecords=5.
- pageSize: Dies gibt die Anzahl der Einträge pro zurückgelieferter Seite an, zum Beispiel pageSize=10. Der Standardwert lautet 100. Dies ist auch der maximale Wert.
- sort: Gibt an, in welcher Reihenfolge die Einträge sortiert werden. Der Wert für sort lautet beispielsweise [{field: “Name”, direction: “desc”}] für eine absteigende Sortierung nach dem Inhalt des Feldes Name. Auch dies muss wieder URL-kodiert werden, sodass sich insgesamt dieser Ausdruck ergeben würde: sort=sort%5B0%5D%5Bfield%5D=Name und sort%5B0%5D%5Bdirection%5D=desc.
Wenn wir beispielsweise nur den Wert eines Feldes zurückgeben wollen, verwenden wir die folgenden Parameter:
"sort[0][field]=Firma", "sort[0][direction]=asc"
Diese müssen wir noch parsen, was wir in der Funktion ParseParameters erledigen (siehe Listing 4). Diese nimmt das ParamArray aus varParameters als einfachen Variant-Parameter entgegen.
Public Function CreateParameters(ByVal varParameters As Variant) Dim varParameter As Variant Dim lngPosEqual As Long Dim strParameterName As String Dim strParameterValue As String Dim strParameters As String For Each varParameter In varParameters lngPosEqual = InStr(1, varParameter, "=") strParameterName = Left(varParameter, lngPosEqual - 1) strParameterValue = Mid(varParameter, lngPosEqual + 1) strParameterName = Replace(strParameterName, "fields", "fields%5B%5D") varParameter = strParameterName & "=" & URLEncode_UTF8(strParameterValue) strParameters = strParameters & "&" & varParameter Next varParameter CreateParameters = strParameters End Function
Listing 4: Funktion zum Zusammenstellen und Kodieren der Parameterwerte
Sie durchläuft jedes Element aus varParameters in einer For Each-Schleife. Darin ermitteln wir die Position des Gleichheitszeichens und speichern sie in lngPosEqual. Mit der Left-Funktion lesen wir den Inhalt des aktuellen Parameters aus varParameter aus, der sich vor dem Gleichheitszeichen befindet, und speichern ihn in strParameterName. Mit der Mid-Funktion holen wir den Wert des Parameters hinter dem Gleichheitszeichen und schreiben ihn in strParameterValue.
Lautet der Parametername fields, hängen wir mit %5B%5D noch den Code für ein öffnendes und ein schließendes Paar eckiger Klammern an ([]).
Schließlich stellen wir den Parameter in varParameter aus strParameterName und dem kodierten Wert aus strParameterValue zusammen und hängen ihn an die Liste der Parameter in strParameters an.
Nach dem Durchlaufen aller Parameter geben wir strParameters als Funktionsergebnis zurück.
Funktionen der Rest-API für Tabellen und Tabellendaten
Die Rest-API stellt die folgenden Funktionen für den Zugriff auf die Tabellendaten bereit:
- Datensätze auflisten
- Datensatz ermitteln
- Datensatz erstellen
- Datensatz aktualisieren
- Datensatz löschen
Für diese Funktionen sind verschiedene Parameter erforderlich, die wir in den folgenden Abschnitten erläutern.
Daten der Tabelle Bestellungen abrufen
Damit sind wir nun grundsätzlich gerüstet, die Daten der Tabelle Bestellungen aus der Airtable-Datenbank abzurufen.
Dazu benötigen wir nur noch den passenden Aufruf der weitere oben bereits vorgestellten Funktion Airtable_CRUD.
Diese rufen wir wie in der folgenden Beispielprozedur auf:
Public Sub Test_Airtable_ListRecords() Dim strRequest As String Dim strResponse As String Dim intErrorNumber As Integer Dim strErrorDescription As String Dim strID As String If Airtable_CRUD("Bestellungen", "GET", strRequest, _ strID, strResponse, intErrorNumber, _ strErrorDescription) = True Then Debug.Print GetJSONDOM(strResponse, True) Else MsgBox strErrorDescription & vbCrLf & vbCrLf _ & strResponse, vbCritical, "Fehler " _ & intErrorNumber End If End Sub
Hier übergeben wir die folgenden Parameterwerte:
- strTable: Bestellungen
- strMethod: GET (da wir Daten holen wollen)
- strResponse: Variable zur Rückgabe des Ergebnisses
- intErrorNumber: Variable für eventuelle Fehlernummern
- strErrorDescription: Variable für eventuelle Fehlermeldungen
Damit erhalten wir zunächst die Ausgabe der Funktion GetJSONDOM für den Wert aus strResponse, die für den ersten der zurückgelieferten Datensätze wie in Listing 5 aussieht.
objJson.Item("records").Item(1).Item("id"): recElpIemkgW9bBQC objJson.Item("records").Item(1).Item("createdTime"): 2025-10-09T19:22:45.000Z objJson.Item("records").Item(1).Item("fields").Item("Name"): Access [basics] 31.12.2024 objJson.Item("records").Item(1).Item("fields").Item("Bestelldatum"): 2024-12-31T20:22:00.000Z objJson.Item("records").Item(1).Item("fields").Item("Produkt"): Access [basics] objJson.Item("records").Item(1).Item("fields").Item("Firma"): Test GmbH objJson.Item("records").Item(1).Item("fields").Item("Vorname"): Lisa objJson.Item("records").Item(1).Item("fields").Item("Nachname"): Schmitz objJson.Item("records").Item(1).Item("fields").Item("Straße"): Teststr. 2 objJson.Item("records").Item(1).Item("fields").Item("PLZ"): 80899 objJson.Item("records").Item(1).Item("fields").Item("Ort"): München objJson.Item("records").Item(1).Item("fields").Item("Land"): Deutschland objJson.Item("records").Item(1).Item("fields").Item("Anrede"): Frau objJson.Item("records").Item(1).Item("fields").Item("E-Mail"): lisa@schmitz.de objJson.Item("records").Item(1).Item("fields").Item("Bestellstatus"): Eingegangen
Listing 5: Ergebnis des Abrufs der Tabelleninhalte für den ersten at
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
den kompletten Artikel im PDF-Format mit Beispieldatenbank
diesen und alle anderen Artikel mit dem Jahresabo