Verwendung von Web-APIs in Python 3

Einführung

Mit einer API oderApplicationProgramInterface können Entwickler eine App in eine andere integrieren. Sie enthüllen auf begrenzte Weise einige der inneren Funktionen eines Programms.

Sie können APIs verwenden, um Informationen von anderen Programmen abzurufen oder Dinge zu automatisieren, die Sie normalerweise in Ihrem Webbrowser tun. Manchmal können Sie APIs verwenden, um Dinge zu tun, die Sie auf keine andere Weise tun können. Eine überraschende Anzahl von Web-Eigenschaften bietet webbasierte APIs neben der bekannteren Website oder mobilen App, einschließlich Twitter, Facebook, GitHub und DigitalOcean.

Wenn Sie sich durch einige Tutorials zuhow to code in Python 3 gearbeitet haben und mit der Syntax, Struktur und einigen integriertenfunctions von Python vertraut sind, können Sie Python-Programme schreiben, die Ihre Favoriten nutzen APIs.

In diesem Handbuch erfahren Sie, wie Sie Python mitDigitalOcean APIverwenden, um Informationen zu Ihrem DigitalOcean-Konto abzurufen. Dann schauen wir uns an, wie Sie das Gelernte aufGitHub’s API anwenden können.

Wenn Sie fertig sind, kennen Sie die Konzepte, die für alle Web-APIs gelten, und verfügen über einen schrittweisen Prozess und Arbeitscodebeispiele, mit denen Sie APIs von anderen Diensten testen können.

Voraussetzungen

Bevor Sie mit diesem Handbuch beginnen, benötigen Sie Folgendes:

[[Schritt-1 - - sich mit einer API vertraut machen]] == Schritt 1 - Machen Sie sich mit einer API vertraut

Der erste Schritt bei der Verwendung einer neuen API besteht darin, die Dokumentation zu finden und sich zurechtzufinden. Die DigitalOcean-API-Dokumentation beginnt beihttps://developers.digitalocean.com/. Um APIs für andere Dienste zu finden, suchen Sie nach dem Namen der Site und nach „API“. Nicht alle Dienste bewerben sie auf ihren Titelseiten.

Einige Dienste habenAPI wrappers. Ein API-Wrapper ist Code, den Sie auf Ihrem System installieren, um die Verwendung der APIs in der von Ihnen gewählten Programmiersprache zu vereinfachen. In diesem Handbuch werden keine Wrapper verwendet, da sie einen Großteil der Funktionsweise der APIs verbergen und häufig nicht alle Funktionen der API offenlegen. Wrapper können großartig sein, wenn Sie schnell etwas erledigen möchten. Wenn Sie jedoch genau wissen, was die APIs selbst tun können, können Sie entscheiden, ob die Wrapper für Ihre Ziele sinnvoll sind.

Schauen Sie sich zunächst die Einführung der DigitalOcean-API unterhttps://developers.digitalocean.com/documentation/v2/ an und versuchen Sie, nur die Grundlagen zum Senden einer Anfrage und zu den erwarteten Antworten zu verstehen. An diesem Punkt versuchen Sie nur drei Dinge zu lernen:

  1. Wie sieht eine Anfrage aus? Sind das alles nur URLs? Wie werden die Daten für detailliertere Anfragen formatiert? Es sind normalerweiseJSON oder Querystring-Parameter, wie sie ein Webbrowser verwendet, aber einige verwenden XML oder ein benutzerdefiniertes Format.

  2. Wie sieht eine Antwort aus? In den API-Dokumenten werden Beispielanfragen und -antworten angezeigt. Werden Sie JSON, XML oder eine andere Art von Antwort erhalten?

  3. Was steht in den Anforderungs- oder Antwortköpfen? Häufig enthalten die Anforderungsheader Ihr Authentifizierungstoken, und die Antwortheader enthalten aktuelle Informationen zu Ihrer Nutzung des Dienstes, z. B. wie nah Sie an einem Ratenlimit sind.

Die DigitalOcean-API verwendet HTTPmethods (manchmal alsverbs bezeichnet), um anzugeben, ob Sie versuchen, vorhandene Informationen zu lesen, neue Informationen zu erstellen oder etwas zu löschen. In diesem Teil der Dokumentation wird erläutert, welche Methoden für welche Zwecke verwendet werden. Im Allgemeinen ist eine GET-Anforderung einfacher als ein POST. Bis Sie hier fertig sind, werden Sie jedoch keinen großen Unterschied feststellen.

Im nächsten Abschnitt der API-Dokumentation wird erläutert, wie der Server auf Ihre Anforderungen reagiert. Im Allgemeinen ist eine Anforderung entweder erfolgreich oder schlägt fehl. Wenn dies fehlschlägt, ist die Ursache entweder ein Problem mit der Anforderung oder ein Problem auf dem Server. Alle diese Informationen werden mitHTTP status codes übermittelt, bei denen es sich um dreistellige Zahlen handelt, die in Kategorien unterteilt sind.

  • Die200-Serie bedeutet "Erfolg" - Ihre Anfrage war gültig und die Antwort folgt logischerweise daraus.

  • Die400-Serie bedeutet "schlechte Anfrage" - etwas stimmte nicht mit der Anfrage, sodass der Server sie nicht so verarbeitete, wie Sie es wollten. Häufige Ursachen für HTTP400-S-Level-Fehler sind schlecht formatierte Anforderungen und Authentifizierungsprobleme.

  • Die500-Serie bedeutet "Serverfehler" - Ihre Anfrage war möglicherweise in Ordnung, aber der Server konnte Ihnen aus Gründen, die außerhalb Ihrer Kontrolle liegen, derzeit keine gute Antwort geben. Diese sollten selten sein, aber Sie müssen sich der Möglichkeit bewusst sein, damit Sie sie in Ihrem Code verarbeiten können.

Ihr Code sollte immer den HTTP-Statuscode auf Antworten überprüfen, bevor Sie versuchen, etwas damit zu tun. Wenn Sie dies nicht tun, verlieren Sie Zeit bei der Fehlerbehebung mit unvollständigen Informationen.

Nachdem Sie eine allgemeine Vorstellung davon haben, wie Sie eine Anfrage senden und worauf Sie in der Antwort achten müssen, ist es an der Zeit, diese erste Anfrage zu senden.

[[Schritt-2 - Abrufen von Informationen aus der Web-API]] == Schritt 2 - Abrufen von Informationen aus der Web-API

Ihr DigitalOcean-Konto enthält einige Verwaltungsinformationen, die Sie möglicherweise nicht in der Web-Benutzeroberfläche gesehen haben. Eine API kann Ihnen eine andere Sicht auf vertraute Informationen geben. Wenn Sie diese alternative Ansicht sehen, können Sie sich manchmal Gedanken darüber machen, was Sie mit einer API tun möchten, oder Dienste und Optionen anzeigen, die Sie nicht kennen.

Beginnen wir mit der Erstellung eines Projekts für unsere Skripte. Erstellen Sie ein neues Verzeichnis für das Projekt mit dem Namenapis:

mkdir apis

Navigieren Sie dann in dieses neue Verzeichnis:

cd apis

Erstellen Sie eine neue virtuelle Umgebung für dieses Projekt:

python3 -m venv apis

Aktivieren Sie die virtuelle Umgebung:

source apis/bin/activate

Installieren Sie dann dierequests-Bibliothek, die wir in unseren Skripten verwenden, um HTTP-Anforderungen in unseren Skripten zu stellen:

pip install requests

Erstellen Sie bei konfigurierter Umgebung eine neue Python-Datei mit dem Namendo_get_account.py und öffnen Sie sie in Ihrem Texteditor. Starten Sie dieses Programm mitimporting libraries, um mit JSON- und HTTP-Anforderungen zu arbeiten.

do_get_account.py

import json
import requests

Dieseimport-Anweisungen laden Python-Code, mit dem wir mit dem JSON-Datenformat und dem HTTP-Protokoll arbeiten können. Wir verwenden diese Bibliotheken, da uns die Details zum Senden von HTTP-Anforderungen oder zum Parsen und Erstellen von gültigen JSON-Werten nicht interessieren. Wir wollen sie nur verwenden, um diese Aufgaben zu erfüllen. Alle unsere Skripte in diesem Tutorial beginnen so.

Als Nächstes möchten wir einigevariables einrichten, um Informationen zu speichern, die bei jeder Anforderung gleich sind. Dies erspart uns die erneute Eingabe und gibt uns einen einzigen Ort, an dem wir Aktualisierungen vornehmen können, falls sich etwas ändert. Fügen Sie diese Zeilen nach den Anweisungen vonimportzur Datei hinzu.

do_get_account.py

...
api_token = 'your_api_token'
api_url_base = 'https://api.digitalocean.com/v2/'

Die Variableapi_token ist eine Zeichenfolge, die Ihr DigitalOcean-API-Token enthält. Ersetzen Sie den Wert im Beispiel durch Ihr eigenes Token. Die Variableapi_url_base ist die Zeichenfolge, die jede URL in der DigitalOcean-API startet. Wir werden es später im Code nach Bedarf anhängen.

Als Nächstes müssen wir die HTTP-Anforderungsheader wie in den API-Dokumenten beschrieben einrichten. Fügen Sie diese Zeilen zur Datei hinzu, um eindictionary einzurichten, das Ihre Anforderungsheader enthält:

do_get_account.py

...
headers = {'Content-Type': 'application/json',
           'Authorization': 'Bearer {0}'.format(api_token)}

Dies setzt zwei Header gleichzeitig. Der HeaderContent-Typeweist den Server an, JSON-formatierte Daten im Hauptteil der Anforderung zu erwarten. Der Header vonAuthorizationmuss unser Token enthalten, daher verwenden wir die Python-Zeichenfolgenformatierungslogik, um die Variableapi_tokenbeim Erstellen der Zeichenfolge in die Zeichenfolge einzufügen. Wir hätten das Token hier als wörtliche Zeichenfolge einfügen können, aber das Trennen macht einige Dinge später einfacher:

  • Wenn Sie das Token ersetzen müssen, ist es einfacher zu erkennen, wo dies zu tun ist, wenn es sich um eine separate Variable handelt.

  • Wenn Sie Ihren Code für eine andere Person freigeben möchten, ist es einfacher, Ihr API-Token zu entfernen, und Ihr Freund kann leichter erkennen, wo er seinen Code ablegen kann.

  • Es ist selbstdokumentierend. Wenn das API-Token nur als String-Literal verwendet wird, kann es vorkommen, dass jemand, der Ihren Code liest, nicht versteht, wonach er sucht.

Nachdem wir diese Einrichtungsdetails behandelt haben, ist es an der Zeit, die Anfrage tatsächlich zu senden. Möglicherweise möchten Sie nur die Anforderungen erstellen und senden, aber es gibt einen besseren Weg. Wenn Sie diese Logik in eine Funktion integrieren, die das Senden der Anfrage und das Lesen der Antwort übernimmt, müssen Sie sich etwas klarer überlegen, was Sie tun. Außerdem erhalten Sie Code, mit dem Sie einfacher testen und wiederverwenden können. Das werden wir tun.

Diese Funktion verwendet die von Ihnen erstellten Variablen, um die Anforderung zu senden und die Kontoinformationen in einem Python-Wörterbuch zurückzugeben.

Um die Logik in diesem frühen Stadium klar zu halten, werden wir noch keine detaillierten Fehlerbehandlungen durchführen, aber wir werden dies bald genug hinzufügen.

Definieren Sie die Funktion, die die Kontoinformationen abruft. Es ist immer eine gute Idee, eine Funktion nach ihrer Funktion zu benennen: Diese Funktion erhält Kontoinformationen, daher nennen wir sieget_account_info:

do_get_account.py

...
def get_account_info():

    api_url = '{0}account'.format(api_url_base)

    response = requests.get(api_url, headers=headers)

    if response.status_code == 200:
        return json.loads(response.content.decode('utf-8'))
    else:
        return None

Wir erstellen den Wert fürapi_url mithilfe der Python-Formatierungsmethode für Zeichenfolgen, ähnlich wie wir sie in den Headern verwendet haben. Wir hängen die Basis-URL der API vor die Zeichenfolgeaccount, um die URLhttps://api.digitalocean.com/v2/account zu erhalten, die URL, die Kontoinformationen zurückgeben soll.

Die Variableresponse enthält ein Objekt, das von Pythonrequestsmodule erstellt wurde. Diese Zeile sendet die Anforderung an die URL, die wir mit den zu Beginn des Skripts definierten Headern erstellt haben, und gibt die Antwort von der API zurück.

Als Nächstes untersuchen wir den HTTP-Statuscode der Antwort.

Wenn es sich um200 handelt, eine erfolgreiche Antwort, verwenden wir dieloads-Funktion desjson-Moduls, um eine Zeichenfolge als JSON zu laden. Die Zeichenfolge, die wir laden, ist der Inhalt desresponse-Objektsresponse.content. Der Teil.decode('utf-8')teilt Python mit, dass dieser Inhalt mit dem UTF-8-Zeichensatz codiert wird, wie alle Antworten von der DigitalOcean-API. Das Moduljson erstellt daraus ein Objekt, das wir als Rückgabewert für diese Funktion verwenden.

Wenn die Antwortnot200 war, geben wirNone zurück. Dies ist ein spezieller Wert in Python, den wir beim Aufrufen dieser Funktion überprüfen können. Sie werden feststellen, dass wir derzeit nur Fehler ignorieren. Dies dient dazu, die Erfolgslogik klar zu halten. Wir werden in Kürze eine umfassendere Fehlerprüfung hinzufügen.

Rufen Sie nun diese Funktion auf, überprüfen Sie, ob sie eine gute Antwort erhalten hat, und drucken Sie die von der API zurückgegebenen Details aus:

do_get_account.py

...
account_info = get_account_info()

if account_info is not None:
    print("Here's your info: ")
    for k, v in account_info['account'].items():
        print('{0}:{1}'.format(k, v))

else:
    print('[!] Request Failed')

account_info = get_account_info() setzt die Variableaccount_info auf den Wert, der vom Aufruf aufget_account_info() zurückgekommen ist. Es handelt sich also entweder um den SonderwertNone oder um die Sammlung von Informationen über die Konto.

Wenn es nichtNone ist, drucken wir jede Information in einer eigenen Zeile aus, indem wir dieitems()-Methode verwenden, über die alle Python-Wörterbücher verfügen.

Andernfalls (dh wennaccount_infoNone ist) wird eine Fehlermeldung ausgegeben.

Lassen Sie uns hier eine Minute innehalten. Dieseif-Anweisung mit dem doppelten Negativ mag sich zunächst unangenehm anfühlen, ist jedoch eine verbreitete Python-Sprache. Seine Tugend besteht darin, den Code, der bei Erfolg ausgeführt wird, sehr nahe anconditional zu halten, anstatt Fehlerfälle zu behandeln.

Sie können es auch anders machen, und es kann eine gute Übung sein, den Code selbst zu schreiben. Anstelle vonif account_info is not None: können Sie mitif account_info is None: beginnen und sehen, wie der Rest zusammenfällt.

Speichern Sie das Skript und probieren Sie es aus:

python do_get_account.py

Die Ausgabe sieht ungefähr so ​​aus:

OutputHere's your info:
droplet_limit:25
email:[email protected]
status:active
floating_ip_limit:3
email_verified:True
uuid:123e4567e89b12d3a456426655440000
status_message:

Sie können jetzt Daten von einer API abrufen. Als Nächstes gehen wir zu etwas Interessanterem über: Verwenden einer API zum Ändern von Daten.

[[Schritt 3 - Ändern der Informationen auf dem Server]] == Schritt 3 - Ändern der Informationen auf dem Server

Nach dem Üben mit einer schreibgeschützten Anforderung ist es Zeit, Änderungen vorzunehmen. Sehen wir uns dies an, indem Sie Python und die DigitalOcean-API verwenden, um Ihrem DigitalOcean-Konto einen SSH-Schlüssel hinzuzufügen.

Schauen Sie sich zunächst die API-Dokumentation für SSH-Schlüssel an, die unterhttps://developers.digitalocean.com/documentation/v2/#ssh-keys verfügbar ist.

Über die API können Sie die aktuellen SSH-Schlüssel in Ihrem Konto auflisten und neue hinzufügen. Die Anforderung, eine Liste von SSH-Schlüsseln abzurufen, ähnelt der Anforderung, Kontoinformationen abzurufen. Die Antwort ist jedoch anders: Im Gegensatz zu einem Konto können Sie keinen, einen oder mehrere SSH-Schlüssel haben.

Erstellen Sie eine neue Datei für dieses Skript mit dem Namendo_ssh_keys.py und starten Sie sie genau wie die letzte. Importieren Sie die Modulejson undrequests, damit Sie sich nicht um die Details von JSON oder das HTTP-Protokoll kümmern müssen. Fügen Sie dann Ihr DigitalOcean-API-Token als Variable hinzu und richten Sie die Anforderungsheader in einem Wörterbuch ein.

do_ssh_keys.py

import json
import requests


api_token = 'your_api_token'
api_url_base = 'https://api.digitalocean.com/v2/'
headers = {'Content-Type': 'application/json',
           'Authorization': 'Bearer {0}'.format(api_token)}

Die Funktion, die wir erstellen, um die SSH-Schlüssel abzurufen, ähnelt der Funktion, mit der wir die Kontoinformationen abgerufen haben, aber dieses Mal werden wir Fehler direkter behandeln.

Zuerst führen wir den API-Aufruf durch und speichern die Antwort in der Antwortvariablenresponse. Dieapi_url sind jedoch nicht die gleichen wie im vorherigen Skript. Dieses Mal muss es aufhttps://api.digitalocean.com/v2/account/keys zeigen.

Fügen Sie diesen Code zum Skript hinzu:

do_ssh_keys.py

...
def get_ssh_keys():

    api_url = '{0}account/keys'.format(api_url_base)

    response = requests.get(api_url, headers=headers)

Fügen wir nun eine Fehlerbehandlung hinzu, indem wir den HTTP-Statuscode in der Antwort betrachten. Wenn es200ist, geben wir den Inhalt der Antwort wie zuvor als Wörterbuch zurück. Wenn es etwas anderes ist, drucken wir eine hilfreiche Fehlermeldung, die dem Typ des Statuscodes zugeordnet ist, und geben dannNone zurück.

Fügen Sie diese Zeilen zur Funktionget_ssh_keyshinzu:

do_ssh_keys.py

...

    if response.status_code >= 500:
        print('[!] [{0}] Server Error'.format(response.status_code))
        return None
    elif response.status_code == 404:
        print('[!] [{0}] URL not found: [{1}]'.format(response.status_code,api_url))
        return None
    elif response.status_code == 401:
        print('[!] [{0}] Authentication Failed'.format(response.status_code))
        return None
    elif response.status_code == 400:
        print('[!] [{0}] Bad Request'.format(response.status_code))
        return None
    elif response.status_code >= 300:
        print('[!] [{0}] Unexpected Redirect'.format(response.status_code))
        return None
    elif response.status_code == 200:
        ssh_keys = json.loads(response.content.decode('utf-8'))
        return ssh_keys
    else:
        print('[?] Unexpected Error: [HTTP {0}]: Content: {1}'.format(response.status_code, response.content))
    return None

Dieser Code behandelt sechs verschiedene Fehlerzustände, indem der HTTP-Statuscode in der Antwort angezeigt wird.

  • Ein Code von500 oder höher weist auf ein Problem auf dem Server hin. Diese sollten selten vorkommen und werden nicht durch Probleme mit der Anforderung verursacht. Wir drucken daher nur den Statuscode.

  • Ein Code von404 bedeutet "nicht gefunden", was wahrscheinlich auf einen Tippfehler in der URL zurückzuführen ist. Für diesen Fehler drucken wir den Statuscode und die URL, die dazu geführt hat, damit Sie sehen können, warum der Fehler aufgetreten ist.

  • Ein Code von401 bedeutet, dass die Authentifizierung fehlgeschlagen ist. Die wahrscheinlichste Ursache dafür ist ein falsches oder fehlendesapi_key.

  • Ein Code im Bereich von300 zeigt eine Umleitung an. Die DigitalOcean-API verwendet keine Weiterleitungen, daher sollte dies niemals passieren. Bei der Behandlung von Fehlern schadet es jedoch nicht, dies zu überprüfen. Viele Fehler werden durch Dinge verursacht, von denen der Programmierer dachte, dass sie niemals passieren sollten.

  • Ein Code von200 bedeutet, dass die Anforderung erfolgreich verarbeitet wurde. Dafür drucken wir nichts. Wir geben die ssh-Schlüssel einfach als JSON-Objekt zurück und verwenden dabei die gleiche Syntax wie im vorherigen Skript.

  • Wenn der Antwortcode etwas anderes war, geben wir den Statuscode als "unerwarteten Fehler" aus.

Das sollte alle Fehler behandeln, die wir wahrscheinlich durch den Aufruf der API bekommen. Zu diesem Zeitpunkt haben wir entweder eine Fehlermeldung und dasNone-Objekt oder wir haben Erfolg und ein JSON-Objekt, das null oder mehr SSH-Schlüssel enthält. Unser nächster Schritt ist, sie auszudrucken:

do_ssh_keys.py

...

ssh_keys = get_ssh_keys()

if ssh_keys is not None:
    print('Here are your keys: ')
    for key, details in enumerate(ssh_keys['ssh_keys']):
        print('Key {}:'.format(key))
        for k, v in details.items():
            print('  {0}:{1}'.format(k, v))
else:
    print('[!] Request Failed')

Da die Antwortlist (oder ein Array) von SSH-Schlüsseln enthält, möchten wir die gesamte Liste durchlaufen, um alle Schlüssel anzuzeigen. Wir verwenden hierfür dieenumerate-Methode von Python. Dies ähnelt der für Wörterbücher verfügbarenitems-Methode, funktioniert jedoch stattdessen mit Listen.

Wir verwendenenumerate und nicht nurfor loop, weil wir in der Lage sein möchten zu sagen, wie weit wir in der Liste für einen bestimmten Schlüssel sind.

Die Informationen jedes Schlüssels werden als Wörterbuch zurückgegeben. Daher verwenden wir denselbenfor k,v in details.items():-Code, den wir im vorherigen Skript für das Kontoinformationswörterbuch verwendet haben.

Führen Sie dieses Skript aus und Sie erhalten eine Liste der SSH-Schlüssel, die sich bereits in Ihrem Konto befinden.

python get_ssh_keys.py

Die Ausgabe sieht in etwa so aus, je nachdem, wie viele SSH-Schlüssel sich bereits in Ihrem Konto befinden.

OutputHere are your keys:
Kcy 0:
  id:280518
  name:work
  fingerprint:96:f7:fb:9f:60:9c:9b:f9:a9:95:01:5c:5c:2c:d5:a0
  public_key:ssh-rsa AAAAB5NzaC1yc2cAAAADAQABAAABAQCwgr9Fzc/YTD/V2Ka5I52Rx4I+V2Ka5I52Rx4Ir5LKSCqkQ1Cub+... sammy@work
Kcy 1:
  id:290536
  name:home
  fingerprint:90:1c:0b:ac:fa:b0:25:7c:af:ab:c5:94:a5:91:72:54
  public_key:ssh-rsa AAAAB5NzaC1yc2cAAAABJQAAAQcAtTZPZmV96P9ziwyr5LKSCqkQ1CubarKfK5r7iNx0RNnlJcqRUqWqSt... sammy@home

Jetzt, da Sie die SSH-Schlüssel in Ihrem Konto auflisten können, wird Ihr letztes Skript hier ein neues sein, das der Liste einen neuen Schlüssel hinzufügt.

Bevor wir einen neuen SSH-Schlüssel hinzufügen können, müssen wir einen generieren. Eine ausführlichere Beschreibung dieses Schritts finden Sie im TutorialHow to Set Up SSH Keys.

Für unsere Zwecke benötigen wir jedoch nur einen einfachen Schlüssel. Führen Sie diesen Befehl aus, um unter Linux, BSD oder MacOS einen neuen zu generieren. Sie können dies auf einem vorhandenen Droplet tun, wenn Sie möchten.

ssh-keygen -t rsa

Geben Sie die Datei ein, um den Schlüssel zu speichern, und geben Sie keine Passphrase ein, wenn Sie dazu aufgefordert werden.

OutputGenerating public/private rsa key pair.
Enter file in which to save the key (/home/sammy/.ssh/id_rsa): /home/sammy/.ssh/sammy
Created directory '/home/sammy/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/sammy/.ssh/sammy.
Your public key has been saved in /home/sammy/.ssh/sammy.pub.
...

Notieren Sie sich, wo die öffentliche Schlüsseldatei gespeichert wurde, da Sie sie für das Skript benötigen.

Starten Sie ein neues Python-Skript, nennen Sie esadd_ssh_key.py und starten Sie es wie die anderen:

add_ssh_key.py

import json
import requests


api_token = 'your_api_token'
api_url_base = 'https://api.digitalocean.com/v2/'
headers = {'Content-Type': 'application/json',
           'Authorization': 'Bearer {0}'.format(api_token)}

Wir werden eine Funktion verwenden, um unsere Anfrage zu stellen, aber diese wird etwas anders sein.

Erstellen Sie eine Funktion namensadd_ssh_key, die zwei Argumente akzeptiert: den Namen für den neuen SSH-Schlüssel und den Dateinamen des Schlüssels selbst auf Ihrem lokalen System. Die Funktion wirdread the file ausführen und anstelle vonGET eine HTTPPOST-Anforderung stellen:

add_ssh_key.py

...

def add_ssh_key(name, filename):

    api_url = '{0}account/keys'.format(api_url_base)

    with open(filename, 'r') as f:
        ssh_key = f.readline()

    ssh_key = {'name': name, 'public_key': ssh_key}

    response = requests.post(api_url, headers=headers, json=ssh_key)

Die Zeilewith open(filename, 'r') as f: öffnet die Datei im schreibgeschützten Modus, und die folgende Zeile liest die erste (und einzige) Zeile aus der Datei und speichert sie in der Variablenssh_key.

Als Nächstes erstellen wir ein Python-Wörterbuch mit dem Namenssh_key mit den Namen und Werten, die die API erwartet.

Wenn wir die Anfrage senden, gibt es ein bisschen mehr Neues. Es ist einPOST und keinGET, und wir müssen diessh_key im Hauptteil derPOST-Anforderung senden, die als JSON codiert ist. Dasrequests-Modul übernimmt die Details für uns. requests.post weist es an, die MethodePOST zu verwenden, und einschließlichjson=ssh_key weist es an, die Variablessh_key im Hauptteil der Anforderung zu senden, die als JSON codiert ist.

Laut API lautet die Antwort bei Erfolg HTTP201 anstelle von200, und der Hauptteil der Antwort enthält die Details des soeben hinzugefügten Schlüssels.

Fügen Sie der Funktionadd_ssh_keyden folgenden Fehlerbehandlungscode hinzu. Es ähnelt dem vorherigen Skript, außer dass wir diesmal nach dem Code201 anstelle von200 suchen müssen, um erfolgreich zu sein:

add_ssh_key.py

...
    if response.status_code >= 500:
        print('[!] [{0}] Server Error'.format(response.status_code))
        return None
    elif response.status_code == 404:
        print('[!] [{0}] URL not found: [{1}]'.format(response.status_code,api_url))
        return None
    elif response.status_code == 401:
        print('[!] [{0}] Authentication Failed'.format(response.status_code))
        return None
    elif response.status_code >= 400:
        print('[!] [{0}] Bad Request'.format(response.status_code))
        print(ssh_key )
        print(response.content )
        return None
    elif response.status_code >= 300:
        print('[!] [{0}] Unexpected redirect.'.format(response.status_code))
        return None
    elif response.status_code == 201:
        added_key = json.loads(response.content)
        return added_key
    else:
        print('[?] Unexpected Error: [HTTP {0}]: Content: {1}'.format(response.status_code, response.content))
        return None

Diese Funktion gibt wie die vorherigen entwederNone oder den Antwortinhalt zurück. Daher verwenden wir den gleichen Ansatz wie zuvor, um das Ergebnis zu überprüfen.

Rufen Sie anschließend die Funktion auf und verarbeiten Sie das Ergebnis. Übergeben Sie als zweites Argument den Pfad zu Ihrem neu erstellten SSH-Schlüssel:

add_ssh_key.py

...
add_response = add_ssh_key('tutorial_key', '/home/sammy/.ssh/sammy.pub')

if add_response is not None:
    print('Your key was added: ' )
    for k, v in add_response.items():
        print('  {0}:{1}'.format(k, v))
else:
    print('[!] Request Failed')

Führen Sie dieses Skript aus und Sie erhalten eine Antwort, die Sie darüber informiert, dass Ihr neuer Schlüssel hinzugefügt wurde.

python add_ssh_key.py

Die Ausgabe sieht ungefähr so ​​aus:

OutputYour key was added:
  ssh_key:{'id': 9458326, 'name': 'tutorial_key', 'fingerprint': '64:76:37:77:c8:c7:26:05:f5:7b:6b:e1:bb:d6:80:da', 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUtY9aizEcVJ65/O5CE6tY8Xodrkkdh9BB0GwEUE7eDKtTh4NAxVjXc8XdzCLKtdMwfSg9xwxSi3axsVWYWBUhiws0YRxxMNTHCBDsLFTJgCFC0JCmSLB5ZEnKl+Wijbqnu2r8k2NoXW5GUxNVwhYztXZkkzEMNT78TgWBjPu2Tp1qKREqLuwOsMIKt4bqozL/1tu6oociNMdLOGUqXNrXCsOIvTylt6ROF3a5UnVPXhgz0qGbQrSHvCEfuKGZ1kw8PtWgeIe7VIHbS2zTuSDCmyj1Nw1yOTHSAqZLpm6gnDo0Lo9OEA7BSFr9W/VURmTVsfE1CNGSb6c6SPx0NpoN sammy@tutorial-test'}

Wenn Sie vergessen haben, die Bedingung "Erfolg" zu ändern, um nach HTTP201 anstelle von200 zu suchen, wird ein Fehler angezeigt, der Schlüssel wurde jedoch weiterhin hinzugefügt. Ihre Fehlerbehandlung hätte Ihnen mitgeteilt, dass der Statuscode201 war. Sie sollten dies als Mitglied der200-Serie erkennen, was auf Erfolg hinweist. Dies ist ein Beispiel dafür, wie die grundlegende Fehlerbehandlung die Fehlerbehebung vereinfachen kann.

Wenn Sie den Schlüssel mit diesem Skript erfolgreich hinzugefügt haben, führen Sie ihn erneut aus, um zu sehen, was passiert, wenn Sie versuchen, einen bereits vorhandenen Schlüssel hinzuzufügen.

Die API sendet eine HTTP422-Antwort zurück, die Ihr Skript in eine Meldung übersetzt, die besagt, dass der SSH-Schlüssel in Ihrem Konto bereits verwendet wird.

Output[!] [422] Bad Request
{'name': 'tutorial_key', 'public_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUtY9aizEcVJ65/O5CE6tY8Xodrkkdh9BB0GwEUE7eDKtTh4NAxVjXc8XdzCLKtdMwfSg9xwxSi3axsVWYWBUhiws0YRxxMNTHCBDsLFTJgCFC0JCmSLB5ZEnKl+Wijbqnu2r8k2NoXW5GUxNVwhYztXZkkzEMNT78TgWBjPu2Tp1qKREqLuwOsMIKt4bqozL/1tu6oociNMdLOGUqXNrXCsOIvTylt6ROF3a5UnVPXhgz0qGbQrSHvCEfuKGZ1kw8PtWgeIe7VIHbS2zTuSDCmyj1Nw1yOTHSAqZLpm6gnDo0Lo9OEA7BSFr9W/VURmTVsfE1CNGSb6c6SPx0NpoN sammy@tutorial-test'}
b'{"id":"unprocessable_entity","message":"SSH Key is already in use on your account"}'
[!] Request Failed

Führen Sie nun das Skript vonget_ssh_keys.pyerneut aus und Sie sehen Ihren neu hinzugefügten Schlüssel in der Liste.

Mit kleinen Änderungen können Sie mit diesen beiden Skripten Ihrem DigitalOcean-Konto jederzeit schnell neue SSH-Schlüssel hinzufügen. Verwandte Funktionen in dieser API ermöglichen es Ihnen, einen bestimmten Schlüssel mithilfe seiner eindeutigen Schlüssel-ID oder seines Fingerabdrucks umzubenennen oder zu löschen.

Schauen wir uns eine andere API an und sehen, wie sich die soeben erlernten Fähigkeiten übersetzen lassen.

[[Schritt-4 - Arbeiten mit einer anderen API]] == Schritt 4 - Arbeiten mit einer anderen API

GitHub hat auch eine API. Alles, was Sie über die Verwendung der DigitalOcean-API gelernt haben, ist direkt auf die Verwendung der GitHub-API anwendbar.

Machen Sie sich mit der GitHub-API genauso vertraut wie mit DigitalOcean. Suchen Sie nachAPI documentation und überfliegen Sie den AbschnittOverview. Sie werden sofort feststellen, dass die GitHub-API und die DigitalOcean-API einige Gemeinsamkeiten aufweisen.

Zunächst werden Sie feststellen, dass alle API-URLs einen gemeinsamen Stamm haben:https://api.github.com/. Sie wissen, wie Sie dies als Variable in Ihrem Code verwenden, um das Fehlerpotential zu optimieren und zu reduzieren.

Die GitHub-API verwendet wie DigitalOcean JSON als Anforderungs- und Antwortformat, sodass Sie wissen, wie diese Anforderungen gestellt und die Antworten verarbeitet werden.

Die Antworten enthalten Informationen zu Ratenbeschränkungen in den HTTP-Antwortheadern, wobei fast dieselben Namen und genau dieselben Werte wie bei DigitalOcean verwendet werden.

GitHub verwendet OAuth zur Authentifizierung und Sie können Ihr Token in einem Anforderungsheader senden. Die Details dieses Tokens unterscheiden sich ein wenig, aber die Art und Weise, wie es verwendet wird, ist identisch mit der Vorgehensweise, die Sie mit der DigitalOcean-API durchgeführt haben.

Es gibt auch einige Unterschiede. GitHub empfiehlt die Verwendung eines Anforderungsheaders, um die Version der API anzugeben, die Sie verwenden möchten. Sie wissen, wie Sie in Python Header zu Anforderungen hinzufügen.

GitHub möchte auch, dass Sie in Anfragen eine eindeutigeUser-Agent-Zeichenfolge verwenden, damit diese Sie leichter finden können, wenn Ihr Code Probleme verursacht. Sie würden dies auch mit einer Kopfzeile behandeln.

Die GitHub-API verwendet dieselben HTTP-Anforderungsmethoden, verwendet jedoch für bestimmte Vorgänge auch eine neue Methode namensPATCH. Die GitHub-API verwendetGET zum Lesen von Informationen,POST zum Hinzufügen eines neuen Elements undPATCH zum Ändern eines vorhandenen Elements. DiesePATCH-Anforderung ist die Art von Dingen, nach denen Sie in der API-Dokumentation Ausschau halten möchten.

Nicht alle GitHub-API-Aufrufe erfordern eine Authentifizierung. Beispielsweise können Sie eine Liste der Repositorys eines Benutzers abrufen, ohne ein Zugriffstoken zu benötigen. Erstellen wir ein Skript, um diese Anfrage zu stellen und die Ergebnisse anzuzeigen.

Wir vereinfachen die Fehlerbehandlung in diesem Skript und verwenden nur eine Anweisung, um alle möglichen Fehler zu behandeln. Sie benötigen nicht immer Code, um jeden Fehlertyp einzeln zu behandeln. Es ist jedoch eine gute Angewohnheit, Fehlerzustände zu beheben, wenn Sie sich nur daran erinnern, dass die Dinge nicht immer so laufen, wie Sie es erwarten.

Erstellen Sie eine neue Datei mit dem Namengithub_list_repos.py in Ihrem Editor und fügen Sie den folgenden Inhalt hinzu, der ziemlich vertraut aussehen sollte:

github_list_repos.py

import json
import requests


api_url_base = 'https://api.github.com/'
headers = {'Content-Type': 'application/json',
           'User-Agent': 'Python Student',
           'Accept': 'application/vnd.github.v3+json'}

Die Importe sind die gleichen, die wir verwendet haben. Inapi_url_base beginnen alle GitHub-APIs.

In den Kopfzeilen sind zwei der optionalen GitHub-Erwähnungen in der Übersicht enthalten, sowie eine, die besagt, dass wir in unserer Anfrage JSON-formatierte Daten senden.

Auch wenn dies ein kleines Skript ist, definieren wir dennoch eine Funktion, um unsere Logik modular zu halten und die Logik für die Anforderung zu kapseln. Oft werden Ihre kleinen Skripte zu größeren. Daher ist es hilfreich, diesbezüglich gewissenhaft vorzugehen. Fügen Sie eine Funktion namensget_repos hinzu, die einen Benutzernamen als Argument akzeptiert:

github_list_repos.py

...
def get_repos(username):

    api_url = '{}orgs/{}/repos'.format(api_url_base, username)

    response = requests.get(api_url, headers=headers)

    if response.status_code == 200:
        return (response.content)
    else:
        print('[!] HTTP {0} calling [{1}]'.format(response.status_code, api_url))
        return None

Innerhalb der Funktion erstellen wir die URL ausapi_url_base, dem Namen des Benutzers, an dem wir interessiert sind, und den statischen Teilen der URL, die GitHub mitteilen, dass wir die Repository-Liste wünschen. Anschließend überprüfen wir den HTTP-Statuscode der Antwort, um sicherzustellen, dass er200 (erfolgreich) war. Wenn es erfolgreich war, geben wir den Antwortinhalt zurück. Wenn dies nicht der Fall ist, drucken wir den tatsächlichen Statuscode und die von uns erstellte URL aus, damit wir eine Vorstellung davon haben, wo wir möglicherweise einen Fehler gemacht haben.

Rufen Sie nun die Funktion auf und übergeben Sie den gewünschten GitHub-Benutzernamen. In diesem Beispiel verwenden wiroctokit. Dann drucken Sie die Ergebnisse auf dem Bildschirm aus:

github_list_repos.py

...
repo_list = get_repos('octokit')

if repo_list is not None:
    print(repo_list)
else:
    print('No Repo List Found')

Speichern Sie die Datei und führen Sie das Skript aus, um die Repositorys für den von Ihnen angegebenen Benutzer anzuzeigen.

python github_list_repos.py

In der Ausgabe werden viele Daten angezeigt, da die Antwort in diesem Beispiel nicht als JSON analysiert wurde und die Ergebnisse nicht nach bestimmten Schlüsseln gefiltert wurden. Verwenden Sie dazu das, was Sie in den anderen Skripten gelernt haben. Sehen Sie sich die Ergebnisse an, die Sie erhalten, und prüfen Sie, ob Sie den Repository-Namen ausdrucken können.

Das Schöne an diesen GitHub-APIs ist, dass Sie direkt in Ihrem Webbrowser auf die Anforderungen zugreifen können, für die Sie keine Authentifizierung benötigen. Auf diese Weise können Sie die Antworten mit denen vergleichen, die Sie in Ihren Skripten sehen. Versuchen Sie,https://api.github.com/orgs/octokit/repos in Ihrem Browser zu besuchen, um die Antwort dort zu sehen.

Inzwischen können Sie die Dokumentation lesen und den Code schreiben, der zum Senden spezifischerer Anforderungen zur Unterstützung Ihrer eigenen Ziele mit der GitHub-API erforderlich ist.

Den vollständigen Code für alle Beispiele finden Sie in diesem Lernprogramm inthis repository on GitHub.

Fazit

In diesem Lernprogramm haben Sie gelernt, wie Sie Web-APIs für zwei verschiedene Dienste mit leicht unterschiedlichen Stilen verwenden. Sie haben erkannt, wie wichtig es ist, Fehlerbehandlungscode einzuschließen, um das Debuggen zu vereinfachen und Skripts robuster zu machen. Sie haben die Python-Modulerequests undjson verwendet, um Sie von den Details dieser Technologien zu isolieren und Ihre Arbeit zu erledigen, und Sie haben die Anforderungs- und Antwortverarbeitung in einer Funktion zusammengefasst, um Ihre Skripte modularer zu gestalten.

Darüber hinaus haben Sie jetzt einen wiederholbaren Prozess, um neue Web-APIs zu erlernen:

  1. Suchen Sie die Dokumentation und lesen Sie die Einführung, um die Grundlagen der Interaktion mit der API zu verstehen.

  2. Fordern Sie bei Bedarf ein Authentifizierungstoken an, und schreiben Sie ein modulares Skript mit grundlegender Fehlerbehandlung, um eine einfache Anforderung zu senden, auf Fehler zu antworten und die Antwort zu verarbeiten.

  3. Erstellen Sie die Anforderungen, mit denen Sie die gewünschten Informationen vom Service erhalten.

Zementieren Sie nun dieses neu gewonnene Wissen und suchen Sie eine andere API oder sogar eine andere Funktion einer der APIs, die Sie hier verwendet haben. Ein eigenes Projekt wird dazu beitragen, das, was Sie hier gelernt haben, zu festigen.