Lies in den Artikel rein und unten bekommst Du ein unschlagbares Angebot!
Wer Kunden und Bestellungen mit einer Access-Datenbank verwaltet oder gegebenenfalls auch mit einer Excel-Tabelle, möchte vielleicht Zeit sparen und die Etiketten für den Versand von Lieferungen an seine Kunden automatisieren. Das gelingt mit den verschiedenen Webservices von DHL. Wir haben bereits einmal eine solche Lösung vorgestellt, aber DHL hat seine Schnittstellen für die Erstellung von Versandetiketten aktualisiert. In diesem Artikel schauen wir uns an, wie die neuen Schnittstellen funktionieren: Welche Daten benötige ich? Welche URL muss für den Zugriff verwendet werden? In welcher Form übergebe ich beispielsweise die Adressdaten an den Webservice?
Voraussetzung für die Verwendung der Lösung
Wenn wir die Webservices von DHL für die Erstellung von Versandetiketten nutzen wollen, sind einige Voraussetzungen zu erfüllen. Als Erstes benötigen wir ein Konto als Geschäftskunde bei DHL. Wie Du dieses anlegst, wollen wir hier nicht im Detail beschreiben. Wir wollen Dir aber zumindest den Link zum Geschäftskundenportal mit auf den Weg geben:
https://www.dhl.de/de/geschaeftskunden.html
Nach der Anmeldung benötigen wir später Deine Zugangsdaten für Dein Kundenkonto, also Benutzername und Kennwort.
Als Zweites benötigst Du ein Entwicklerkonto bei DHL. Dazu besuchst Du die folgende Adresse und erstellst einen Account:
https://developer.dhl.com/
Damit können wir bereits starten.
App erstellen
Nachdem wir einen Entwickler-Account erstellt haben, benötigen wir eine App. Wozu brauchen wir diese? Weil eine App uns einen API Key und ein API Secret liefert, mit dem wir auf die API-Schnittstelle zugreifen können. Also klicken wir, nachdem wir den Developer Account erstellt haben, auf die Schaltfläche App erstellen (siehe Bild 1).
Bild 1: App anlegen für weitere Daten
Dies führt uns zu der Seite aus Bild 2, wo wir den Namen der App und eine Beschreibung eingeben. Außerdem wählen wir hier bereits die API aus, die wir in dieser App verwenden wollen – in diesem Fall Parcel DE Shipping (Post & Parcel Germany).
Bild 2: Angeben von App-Name und Beschreibung sowie Auswahl der APIs
Im nächsten Schritt wählen wir weiter unten aus, ob wir die API zunächst testen oder direkt produktiv einsetzen wollen. Wir entscheiden uns zunächst für den Testbetrieb (siehe Bild 3).
Bild 3: Angabe, ob die App zum Testen oder produktiv genutzt werden soll
Nach diesem Schritt erstellen wir schließlich mit einem Klick auf App erstellen die App (siehe Bild 4).
Bild 4: Erstellen der App
Die App wird nun in der Übersicht angezeigt, wo wir mit einem Klick auf den Namen der App die Detailseite öffnen können (siehe Bild 5). Außerdem können wir die App hier löschen oder Analysedaten anzeigen.
Bild 5: Ein Klick auf den App-Namen zeigt die Details an.
Diese liefert uns unter Credentials die gesuchten Informationen – den API Key und das API Secret (siehe Bild 6). Diese können wir mit einem Klick auf den Link Show key jeweils einblenden.
Bild 6: Anzeige von API Key und API Secret
Bevor es weitergeht: Produktiv-Version
Wenn wir schon auf dieser Seite sind, können wir auch gleich die Produktiv-Version der API hinzufügen. Wenn wir die API Parcel DE Shipping erneut auswählen, wird unter Environment direkt Production angeboten. Dieses behalten wir bei und klicken auf die Schaltfläche zum Hinzufügen (siehe Bild 7).
Bild 7: API produktiv machen
Dies wird jedoch nicht direkt freigegeben, sondern wir erhalten die Meldung, dass sich die API im Status Pending befindet.
Als wir die produktive Version hinzugefügt haben, dauerte die Freigabe allerdings nur wenige Minuten. Es empfiehlt sich jedoch, die ersten Tests zunächst einmal mit der Sandbox-Version durchzuführen.
Informationen über die API suchen
Bevor wir den Zugriff auf eine REST Api programmieren können, benötigen wir einige Informationen – zum Beispiel die URL, an die wir die Anfrage schicken, die Art der Authentifizierung und die dafür notwendigen Zugangsdaten, die verschiedenen API-Funktionen und deren Syntax.
Dazu wechseln wir von der Seite https://developer.dhl.com per Klick auf den Link Browse Shipping APIs zu den gesuchten APIs.
Hier finden wir eine Liste aller API, die wir durch Auswahl verschiedener Kriterien auf die Einträge aus Bild 8 begrenzen.
Bild 8: APIs für den Versand
All diese APIs sind entweder mit der deutschen Bezeichnung Post & Paket Deutschland oder der englischen Übersetzung Post & Parcel Germany markiert, also gehen wir davon aus, dass wir diese über die von uns gewählte, gleichnamige API nutzen können (siehe Bild 8).
Mit dieser API können wir beispielsweise die folgenden Aufgaben erledigen:
- Erstellung von Paketmarken für Privatkunden für den Inlands- und internationalen Versand (Absenderadresse in Deutschland)
- Herunterladen erstellter Versandetiketten
- Herunterladen von mobilen Paketmarken entweder als QR-Code (PNG) oder Wallet-Datei
- Die Zahlungsfunktion wird sicher über die Web-Schnittstelle von DHL während des Checkouts bereitgestellt
- Erstellung von Zoll- und Exportdokumenten
Programmierung der API
Wir starten mit der Programmierung der API mit einem einfachen Beispiel. Dazu wollen wir zunächst die Sandbox nutzen, also einen Testserver.
Einfachste Abfrage: Version ermitteln
Es ist immer schön, eine kleine Test-API zu haben, mit der man erstmal den grundlegenden Zugriff testen kann – bevor es dann ans Eingemachte geht und wir kompliziertere und umfangreichere Daten hin- und herschicken.
Also freuen wir uns, dass es eine API gibt, die einfach Versionsinformationen zurückliefert.
Diese rufen wir mit der folgenden einfachen Funktion auf:
Public Function APIVersionAbfragen() As String Dim strMethod As String Dim strResponse As String Dim lngStatus As Long strMethod = "GET" lngStatus = HTTPRequest(GetURL(False), _ strMethod, , , False, strResponse) Select Case lngStatus Case 200 Debug.Print GetJSONDOM(strResponse, True) Case Else Debug.Print GetJSONDOM(strResponse, True) End Select End Function
Natürlich ist das nicht alles, es hängt noch eine weitere Funktion namens HTTPRequest dahinter, die den eigentlichen API-Zugriff durchführt.
Diese sehen wir in Listing 1. Die Funktion erwartet die folgenden Parameter:
Public Function HTTPRequest(strURL As String, Optional strMethod As String = "POST", _ Optional strContentType As String = "application/json", Optional strData As String, _ Optional strResponse As String, Optional bolProductive As Boolean) As Integer Dim objHTTP As ServerXMLHTTP60 Set objHTTP = New MSXML2.ServerXMLHTTP60 With objHTTP .Open strMethod, strURL, False .setRequestHeader "Accept", "application/json" .setRequestHeader "Content-Type", "application/json; charset=UTF-8" .setRequestHeader "CharSet", "utf-8" .setRequestHeader "dhl-api-key", GetAPIKey .setRequestHeader "Authorization", "Basic " & Base64Encode(GetUsername(bolProductive) & ":" _ & GetPassword(bolProductive)) If Not Len(strData) = 0 Then .setRequestHeader "Body", strData End If .send strData strResponse = .responseText HTTPRequest = .status End With End Function
Listing 1: Die Funktion HTTPRequest führt den eigentlichen API-Aufruf durch.
- strURL: Nimmt die Basis-URL der Rest-API entgegen.
- strMethod: Nimmt die Methode entgegen, zum Beispiel POST, GET oder PUT.
- strContentType: Nimmt die Art des Contents entgegen, hier application/json.
- strData: Nimmt eine zu übermittelnde JSON-Datei entgegen.
- strResponse: Liefert die Antwort der Rest-API.
- bolProductive: Erwartet die Angabe, ob die Sandbox- oder die Produktions-API aufgerufen werden soll.
Um nun die Version der Rest-API zu ermitteln, starten wir mit dem Aufruf der Prozedur APIVersionAbfragen. Diese legt die Methode mit GET fest und übermittelt die mit GetURL(False) geholte URL. Die Funktion GetURL erwartet den Wert True oder False, je nachdem, ob die Produktiv- oder die Sandboxumgebung genutzt werden soll:
Public Function GetURL(Optional bolProductive As Boolean) If bolProductive = True Then GetURL = "https://api-eu.dhl.com/" _ & "parcel/de/shipping/v2/" Else GetURL = "https://api-sandbox.dhl.com/" _ & "parcel/de/shipping/v2/" End If End Function
Außerdem übergeben wir noch den Parameter strResponse, mit dem wir die Antwort der Rest-API entgegennehmen. Die Antwort geben wir schließlich sowohl für den Erfolgsfall als auch für den Fall eines Fehlers im Direktbereich des VBA-Editors aus – genau genommen das mit der Funktion GetJSONDOM bearbeitete Ergebnis. Wie diese funktioniert, haben wir bereits in den Artikeln Mit JSON arbeiten (www.vbentwickler.de/361) und JSON-Dokumente per Objektmodell zusammenstellen (www.vbentwickler.de/412) beschrieben.
Das Ergebnis sieht schließlich wie in Bild 9 aus. Hier sehen wir die Ausdrücke, mit denen wir direkt auf die Werte des mit der Funktion ParseJSON ermittelten Objekts zugreifen können.
Bild 9: Ergebnis der Versionsabfrage
Erstellung von Versandmarken testen
Nachdem der Zugriff auf die Version funktioniert hat, gehen wir einen Schritt weiter und schauen uns direkt die Hauptfunktion an. Diese wiederum testen wir mit der folgenden Prozedur, die wie folgt aussieht und gar nicht so kompliziert aussieht:
Public Sub Test_APIOrder() Dim strResponse As String Dim lngStatus As Long Dim strData As String Dim strPathPDF As String strPathPDF = CurrentProject.Path & "\test.pdf" strData = JSONBeispielsendung If APIOrder(strData, strPathPDF, strResponse, _ lngStatus, True, False) = True Then MsgBox "Erfolgreich" OpenDocument strPathPDF Else MsgBox "Nicht erfolgreich" & vbCrLf & vbCrLf _ & strResponse End If End Sub
Das liegt daran, dass wir darin eine weitere Funktion namens JSONBeispielsendung aufrufen, die uns das komplette JSON-Dokument mit den Daten für die Sendung zusammenstellt – inklusive Absender- und Empfängeradresse und den Details der Sendung wie die Abmessungen und das Gewicht (siehe Listing 2).
Public Function JSONBeispielsendung() As String Dim strJSON As String strJSON = strJSON & "{" & vbCrLf strJSON = strJSON & " ""shipments"": [" & vbCrLf strJSON = strJSON & " {" & vbCrLf strJSON = strJSON & " ""product"": ""V01PAK""," & vbCrLf strJSON = strJSON & " ""billingNumber"": ""33333333330102""," & vbCrLf strJSON = strJSON & " ""refNo"": ""Order No. 1234""," & vbCrLf strJSON = strJSON & " ""shipper"": {" & vbCrLf strJSON = strJSON & " ""name1"": ""Minhorst und Minhorst GmbH""," & vbCrLf strJSON = strJSON & " ""addressStreet"": ""Borkhofer Str. 17""," & vbCrLf strJSON = strJSON & " ""postalCode"": ""47137""," & vbCrLf strJSON = strJSON & " ""city"": ""Duisburg""," & vbCrLf strJSON = strJSON & " ""country"": ""DEU""," & vbCrLf strJSON = strJSON & " ""email"": ""andre@minhorst.com""," & vbCrLf strJSON = strJSON & " ""phone"": ""+ 123456789""" & vbCrLf strJSON = strJSON & " }," & vbCrLf strJSON = strJSON & " ""consignee"": {" & vbCrLf strJSON = strJSON & " ""name1"": ""Maria Musterfrau""," & vbCrLf strJSON = strJSON & " ""addressStreet"": ""Kurt-Schumacher-Str. 20""," & vbCrLf strJSON = strJSON & " ""additionalAddressInformation1"": ""Apartment 107""," & vbCrLf strJSON = strJSON & " ""postalCode"": ""53113""," & vbCrLf strJSON = strJSON & " ""city"": ""Bonn""," & vbCrLf strJSON = strJSON & " ""country"": ""DEU""," & vbCrLf strJSON = strJSON & " ""email"": ""maria@musterfrau.de""," & vbCrLf strJSON = strJSON & " ""phone"": ""+ 987654321""" & vbCrLf strJSON = strJSON & " }," & vbCrLf strJSON = strJSON & " ""details"": {" & vbCrLf strJSON = strJSON & " ""dim"": {" & vbCrLf strJSON = strJSON & " ""uom"": ""mm""," & vbCrLf strJSON = strJSON & " ""height"": 100," & vbCrLf strJSON = strJSON & " ""length"": 200," & vbCrLf strJSON = strJSON & " ""width"": 150" & vbCrLf strJSON = strJSON & " }," & vbCrLf strJSON = strJSON & " ""weight"": {" & vbCrLf strJSON = strJSON & " ""uom"": ""g""," & vbCrLf strJSON = strJSON & " ""value"": 500" & vbCrLf strJSON = strJSON & " }" & vbCrLf strJSON = strJSON & " }" & vbCrLf strJSON = strJSON & " }" & vbCrLf strJSON = strJSON & " ]" & vbCrLf strJSON = strJSON & "}" & vbCrLf JSONBeispielsendung = strJSON End Function
Listing 2: Diese Funktion stellt das JSON-Dokument mit den Paketdaten zusammen.
Danach ruft die die Funktion APIOrder auf, der sie alle notwendigen Variablen übergibt – diese beschreiben wir im Anschluss mit der Funktion APIOrder.
Funktion zum Ausführen der API-Funktion Order
Die Funktion APIOrder erwartet die folgenden Parameter (siehe Listing 3):
Public Function APIOrder(strData As String, strPathPDF As String, Optional strResponse As String, _ Optional lngStatus As Long, Optional bolValidate As Boolean, Optional bolProductive As Boolean) As String Dim strMethod As String Dim strURL As String Dim objJSON As Object Dim strFile As String strURL = GetURL(bolProductive) & "orders" If bolValidate = True Then strURL = strURL & "?validate=true" End If strMethod = "POST" lngStatus = HTTPRequest(strURL, strMethod, , strData, strResponse, bolProductive) Select Case lngStatus Case 200 Debug.Print GetJSONDOM(strResponse, True) Set objJSON = ParseJson(strResponse) If bolValidate = False Then strFile = objJSON.Item("items").Item(1).Item("label").Item("b64") WriteFileFromBytes strPathPDF, DecodeBase64(strFile) End If APIOrder = True Case Else Debug.Print GetJSONDOM(strResponse, True) APIOrder = False End Select Inzwischenablage strResponse End Function
Listing 3: Die Funktion APIOrder übergibt den Request an die Funktion HTTPRequest und wertet die Antwort aus.
- strData: JSON-Dokument mit den Daten für die DHL-Versandmarke
- strPathPDF: Pfad, unter dem das erzeugte PDF-Dokument gespeichert werden soll
- strResponse: Antwort des API-Aufrufs
- lngStatus: Status des Aufrufs
- bolValidate: Gibt an, ob der Aufruf nur der Validierung dienen soll. Der Wert False sorgt dafür, dass der Aufruf nur getestet wird.
- bolProductive: Gibt an, ob die Sandbox- oder die Produktiv-API genutzt werden soll.
Die Funktion legt als Methode POST und als URL die URL fest, die der mit bolProductive festgelegten Plattform entspricht. Wenn der Parameter bolValidate True ist, hängt sie noch den Ausdruck ?validate=true an die URL an, damit nur ein Test der API gefahren wird. Dann ruft sie HTTPRequest auf und übergibt die notwendigen Parameter. Liefert diese den Status 200 zurück, gibt sie testweise das Ergebnis im Direktbereich aus. Außerdem erstellt sie mit der Funktion ParseJson in objJSON ein Objekt auf Basis der zurückgelieferten Antwort. Erfolgt der Aufruf nicht zum Validieren, sondern direkt zum Abfragen der Versandmarke, greifen wir nachfolgend auf das als Zeichenkette kodierte PDF-Dokument zu. Dieses schreibt die Funktion dann mit der Funktion WriteFileFromBytes in eine Datei mit dem Dateinamen aus strPathPDF.
Die frisch erstellte Versandmarke ruft die Funktion OpenDocument auf, um das Dokument wie in Bild 10 anzuzeigen.
Bild 10: Beispiel für eine frisch erstellte Versandmarke