Recherche de site Web

Comment utiliser les API Web dans Python 3


Introduction

Une API, ou Application Program Interface, permet aux développeurs d'intégrer une application avec une autre. Elle expose certaines des fonctionnalités internes d'un programme de manière limitée.

Vous pouvez utiliser des API pour obtenir des informations d'autres programmes ou pour automatiser des tâches que vous effectuez normalement dans votre navigateur web. Parfois, vous pouvez utiliser des API pour faire des choses que vous ne pouvez tout simplement pas faire autrement. Un nombre surprenant de propriétés web proposent des API basées sur le web aux côtés des sites web ou applications mobiles plus familiers, y compris Twitter, Facebook, GitHub et DigitalOcean.

Si vous avez suivi quelques tutoriels sur la façon de coder en Python 3 et que vous êtes à l'aise avec la syntaxe, la structure et certaines fonctions intégrées de Python, vous pouvez écrire des programmes Python qui tirent parti de vos API préférées.

Dans ce guide, vous apprendrez comment utiliser Python avec l'API de DigitalOcean pour récupérer des informations sur votre compte DigitalOcean. Ensuite, nous verrons comment vous pouvez appliquer ce que vous avez appris à l'API de GitHub.

Lorsque vous aurez terminé, vous comprendrez les concepts communs aux API web, et vous aurez un processus étape par étape ainsi que des exemples de code fonctionnels que vous pouvez utiliser pour essayer les API d'autres services.

Conditions préalables

Avant de commencer ce guide, vous aurez besoin des éléments suivants :

  • Un environnement de développement local pour Python 3. Vous pouvez suivre Comment installer et configurer un environnement de programmation local pour Python 3 pour configurer tout ce dont vous avez besoin.
  • Un éditeur de texte avec lequel vous êtes à l'aise. Si vous n'avez pas encore de préféré, choisissez-en un avec mise en surbrillance de la syntaxe. Notepad++ pour Windows, BBEdit pour macOS, et Sublime Text ou Atom pour n'importe quelle plateforme sont tous de bons choix.
  • Un compte DigitalOcean et une clé API. Les premiers paragraphes de Comment utiliser l'API v2 de DigitalOcean montrent comment faire cela.

Étape 1 — Se familiariser avec une API

La première étape pour utiliser une nouvelle API est de trouver la documentation et de se repérer. La documentation de l'API DigitalOcean commence à https://developers.linux-console.net/. Pour trouver des API pour d'autres services, recherchez le nom du site et "API" — tous les services ne les mettent pas en avant sur leur page d'accueil.

Certain services ont des wrappers API. Un wrapper API est un code que vous installez sur votre système pour faciliter l'utilisation des API dans votre langage de programmation choisi. Ce guide n'utilise pas de wrappers car ils cachent une grande partie du fonctionnement interne des API et ne révèlent souvent pas tout ce que l'API peut faire. Les wrappers peuvent être excellents lorsque vous souhaitez réaliser quelque chose rapidement, mais avoir une compréhension solide de ce que les API elles-mêmes peuvent faire vous aidera à décider si les wrappers ont du sens pour vos objectifs.

Tout d'abord, consultez l'introduction à l'API DigitalOcean sur https://developers.linux-console.net/documentation/v2/ et essayez de comprendre uniquement les bases sur la façon d'envoyer une demande et ce à quoi s'attendre dans la réponse. À ce stade, vous essayez d'apprendre seulement trois choses :

  1. À quoi ressemble une requête ? Sont-elles toutes juste des URL ? Pour des requêtes plus détaillées, comment les données sont-elles formatées ? C'est généralement du JSON ou des paramètres de chaîne de requête comme un navigateur web, mais certains utilisent du XML ou un format personnalisé.
  2. À quoi ressemble une réponse ? Les documents de l'API montreront des exemples de requêtes et de réponses. Allez-vous recevoir JSON, XML ou un autre type de réponse ?
  3. Que contient les en-têtes de requête ou de réponse ? Souvent, les en-têtes de requête incluent votre jeton d'authentification, et les en-têtes de réponse fournissent des informations actuelles sur votre utilisation du service, telles que votre proximité par rapport à une limite de taux.

L'API DigitalOcean utilise des méthodes HTTP (parfois appelées verbes) pour indiquer si vous essayez de lire des informations existantes, de créer de nouvelles informations ou de supprimer quelque chose. Cette partie de la documentation explique quelles méthodes sont utilisées et à quelles fins. En général, une requête GET est plus simple qu'un POST, mais une fois que vous aurez terminé ici, vous ne remarquerez pas beaucoup de différence.

La section suivante de la documentation de l'API traite de la manière dont le serveur répondra à vos demandes. En général, une demande réussit ou échoue. Lorsqu'elle échoue, la cause est soit quelque chose de mauvais avec la demande, soit un problème sur le serveur. Toutes ces informations sont communiquées en utilisant des codes d'état HTTP, qui sont des nombres à 3 chiffres divisés en catégories.

  • La série 200 signifie « succès » — votre demande était valide, et la réponse est ce qui en découle logiquement.
  • La série 400 signifie "mauvaise requête" — quelque chose n'allait pas avec la requête, donc le serveur ne l'a pas traitée comme vous le souhaitiez. Parmi les causes courantes des erreurs de niveau HTTP 400, on trouve des requêtes mal formées et des problèmes d'authentification.
  • La série 500 signifie "erreur du serveur" - votre demande a peut-être été correcte, mais le serveur n'a pas pu vous fournir une bonne réponse pour des raisons qui échappent à votre contrôle. Ces erreurs devraient être rares, mais vous devez être conscient de cette possibilité afin de pouvoir les gérer dans votre code.

Votre code doit toujours vérifier le code de statut HTTP pour toute réponse avant d'essayer de faire quoi que ce soit avec. Si vous ne faites pas cela, vous vous retrouverez à perdre du temps à résoudre des problèmes avec des informations incomplètes.

Maintenant que vous avez une idée générale de la façon d'envoyer une demande et de ce qu'il faut rechercher dans la réponse, il est temps d'envoyer cette première demande.

Étape 2 — Obtention d'informations à partir de l'API Web

Votre compte DigitalOcean inclut des informations administratives que vous n'avez peut-être pas vues dans l'interface Web. Une API peut vous donner une vue différente d'informations familières. Le simple fait de voir cette vue alternative peut parfois susciter des idées sur ce que vous pourriez vouloir faire avec une API, ou révéler des services et des options que vous ne connaissiez pas.

Commençons par créer un projet pour nos scripts. Créez un nouveau répertoire pour le projet appelé apis :

  1. mkdir apis

Puis naviguez dans ce nouveau répertoire :

  1. cd apis

Créez un nouvel environnement virtuel pour ce projet :

  1. python3 -m venv apis

Activez le virtualenv :

  1. source apis/bin/activate

Ensuite, installez la bibliothèque requests, que nous utiliserons dans nos scripts pour effectuer des requêtes HTTP :

  1. pip install requests

Avec l'environnement configuré, créez un nouveau fichier Python appelé do_get_account.py et ouvrez-le dans votre éditeur de texte. Commencez ce programme en important des bibliothèques pour travailler avec JSON et les requêtes HTTP.

import json
import requests

Ces instructions import chargent du code Python qui nous permet de travailler avec le format de données JSON et le protocole HTTP. Nous utilisons ces bibliothèques car nous ne sommes pas concernés par les détails sur la façon d'envoyer des requêtes HTTP ou de parser et créer du JSON valide ; nous voulons juste les utiliser pour accomplir ces tâches. Tous nos scripts dans ce tutoriel commenceront comme ça.

Ensuite, nous voulons définir quelques variables pour contenir des informations qui seront les mêmes dans chaque requête. Cela nous évite de devoir les taper encore et encore, et nous donne un endroit unique pour effectuer des mises à jour en cas de changement. Ajoutez ces lignes au fichier, après les déclarations import.

...
api_token = 'your_api_token'
api_url_base = 'https://api.linux-console.net/v2/'

La variable api_token est une chaîne qui contient votre jeton API DigitalOcean. Remplacez la valeur dans l'exemple par votre propre jeton. La variable api_url_base est la chaîne qui commence chaque URL dans l'API DigitalOcean. Nous l'ajouterons au besoin plus tard dans le code.

Ensuite, nous devons configurer les en-têtes de requête HTTP comme le décrivent les documents de l'API. Ajoutez ces lignes au fichier pour configurer un dictionnaire contenant vos en-têtes de requête :

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

Cela définit deux en-têtes à la fois. L'en-tête Content-Type indique au serveur de s'attendre à des données au format JSON dans le corps de la requête. L'en-tête Authorization doit inclure notre jeton, nous utilisons donc la logique de formatage de chaînes de Python pour insérer notre variable api_token dans la chaîne lors de sa création. Nous aurions pu mettre le jeton ici sous forme de chaîne littérale, mais le séparer rend plusieurs choses plus faciles par la suite :

  • Si vous devez remplacer le jeton, il est plus facile de voir où le faire quand il s'agit d'une variable séparée.
  • Si vous voulez partager votre code avec quelqu'un, il est plus facile de supprimer votre jeton API, et plus facile pour votre ami de voir où mettre le sien.
  • C'est auto-documenté. Si le token API est utilisé uniquement comme une chaîne littérale, alors quelqu'un lisant votre code peut ne pas comprendre ce qu'il regarde.

Maintenant que nous avons couvert ces détails de configuration, il est temps d'envoyer réellement la demande. Votre tendance peut être de simplement commencer à créer et à envoyer les demandes, mais il existe une meilleure façon de procéder. Si vous mettez cette logique dans une fonction qui gère l'envoi de la demande et la lecture de la réponse, vous devrez réfléchir un peu plus clairement à ce que vous faites. Vous obtiendrez également un code qui rend le test et la réutilisation plus simples. C'est ce que nous allons faire.

Cette fonction utilisera les variables que vous avez créées pour envoyer la demande et renvoyer les informations du compte dans un dictionnaire Python.

Afin de garder la logique claire à cette étape précoce, nous ne ferons pas encore de gestion des erreurs détaillée, mais nous l'ajouterons rapidement.

Définissez la fonction qui récupère les informations du compte. C'est toujours une bonne idée de nommer une fonction d'après ce qu'elle fait : celle-ci obtient les informations du compte, donc nous l'appellerons get_account_info :

...
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

Nous construisons la valeur pour api_url en utilisant la méthode de formatage de chaîne de Python, de manière similaire à comment nous l'avons utilisée dans les en-têtes ; nous ajoutons l'URL de base de l'API devant la chaîne account pour obtenir l'URL https://api.linux-console.net/v2/account, l'URL qui devrait renvoyer les informations sur le compte.

La variable response contient un objet créé par le module Python requests. Cette ligne envoie la requête à l'URL que nous avons créée avec les en-têtes que nous avons définis au début du script et renvoie la réponse de l'API.

Ensuite, nous examinons le code d'état HTTP de la réponse.

S'il s'agit de 200, une réponse réussie, nous utilisons alors la fonction loads du module json pour charger une chaîne sous forme de JSON. La chaîne que nous chargeons est le contenu de l'objet response, response.content. La partie .decode('utf-8') indique à Python que ce contenu est encodé en utilisant le jeu de caractères UTF-8, comme toutes les réponses de l'API DigitalOcean le seront. Le module json crée un objet à partir de cela, que nous utilisons comme valeur de retour pour cette fonction.

Si la réponse n'était pas 200, alors nous retournons None, qui est une valeur spéciale en Python que nous pouvons vérifier lorsque nous appelons cette fonction. Vous remarquerez que nous ignorons simplement les erreurs à ce stade. Cela permet de garder la logique de “succès” claire. Nous ajouterons bientôt un contrôle d'erreurs plus complet.

Maintenant, appelez cette fonction, vérifiez pour vous assurer qu'elle a reçu une bonne réponse, puis imprimez les détails que l'API a retournés :

...
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() assigne la variable account_info à ce qui est retourné par l'appel à get_account_info(), donc cela sera soit la valeur spéciale None, soit ce sera la collection d'informations sur le compte.

S'il n'est pas None, alors nous imprimons chaque morceau d'information sur sa propre ligne en utilisant la méthode items() que tous les dictionnaires Python possèdent.

Sinon (c'est-à-dire si account_info est None), nous imprimons un message d'erreur.

Faisons une pause ici pendant une minute. Cette instruction if avec la double négation peut sembler maladroite au début, mais c'est un idiome Python courant. Sa vertu réside dans le fait de garder le code qui s'exécute en cas de succès très proche de la condition plutôt qu'après le traitement des cas d'erreur.

Vous pouvez le faire dans l'autre sens si vous préférez, et cela peut être un bon exercice d'écrire ce code vous-même. Au lieu de if account_info is not None:, vous pourriez commencer par if account_info is None: et voir comment le reste s'assemble.

Enregistrez le script et essayez-le :

  1. python do_get_account.py

La sortie ressemblera à quelque chose comme ceci :

Here's your info: 
droplet_limit:25
email:sammy@linux-console.net
status:active
floating_ip_limit:3
email_verified:True
uuid:123e4567e89b12d3a456426655440000
status_message:

Vous savez maintenant comment récupérer des données d'une API. Ensuite, nous allons passer à quelque chose d'un peu plus intéressant : utiliser une API pour modifier des données.

Étape 3 — Modifier les informations sur le serveur

Après avoir pratiqué avec une requête en lecture seule, il est temps de commencer à apporter des modifications. Explorons cela en utilisant Python et l'API DigitalOcean pour ajouter une clé SSH à votre compte DigitalOcean.

Tout d'abord, jetez un œil à la documentation de l'API pour les clés SSH, disponible à l'adresse https://developers.linux-console.net/documentation/v2/#ssh-keys.

L'API vous permet de lister les clés SSH actuelles sur votre compte, et vous permet également d'en ajouter de nouvelles. La demande pour obtenir une liste de clés SSH est assez similaire à celle pour obtenir des informations sur le compte. Cependant, la réponse est différente : contrairement à un compte, vous pouvez avoir zéro, une ou plusieurs clés SSH.

Créez un nouveau fichier pour ce script appelé do_ssh_keys.py, et commencez-le exactement comme le dernier. Importez les modules json et requests afin de ne pas avoir à vous soucier des détails du JSON ou du protocole HTTP. Ensuite, ajoutez votre jeton API DigitalOcean en tant que variable et configurez les en-têtes de requête dans un dictionnaire.

import json
import requests


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

La fonction que nous allons créer pour obtenir les clés SSH est similaire à celle que nous avons utilisée pour obtenir des informations sur le compte, mais cette fois nous allons gérer les erreurs de manière plus directe.

Tout d'abord, nous ferons l'appel API et stockerons la réponse dans une variable de réponse response. L'api_url ne sera pas le même que dans le script précédent ; cette fois, il doit pointer vers https://api.linux-console.net/v2/account/keys.

Ajoutez ce code au script :

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

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

Ajoutons maintenant une gestion des erreurs en examinant le code de statut HTTP dans la réponse. S'il est 200, nous retournerons le contenu de la réponse sous forme de dictionnaire, comme nous l'avons fait auparavant. Si c'est autre chose, nous afficherons un message d'erreur utile associé au type de code de statut, puis nous retournerons None.

Ajoutez ces lignes à la fonction get_ssh_keys :

...

    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

Ce code gère six conditions d'erreur différentes en examinant le code d'état HTTP dans la réponse.

  • Un code de 500 ou supérieur indique un problème sur le serveur. Ceux-ci devraient être rares et ne sont pas causés par des problèmes avec la demande, donc nous n'imprimons que le code d'état.
  • Un code 404 signifie « non trouvé », ce qui provient probablement d'une faute de frappe dans l'URL. Pour cette erreur, nous imprimons le code d'état et l'URL qui y a conduit afin que vous puissiez voir pourquoi cela a échoué.
  • Un code de 401 signifie que l'authentification a échoué. La cause la plus probable est une api_key incorrecte ou manquante.
  • Un code dans la plage 300 indique une redirection. L'API DigitalOcean n'utilise pas de redirections, donc cela ne devrait jamais arriver, mais tant que nous gérons les erreurs, il n'est pas inutile de vérifier. Beaucoup de bogues sont causés par des choses que le programmeur pensait ne jamais arriver.
  • Un code de 200 signifie que la demande a été traitée avec succès. Pour cela, nous ne printons rien. Nous retournons simplement les clés ssh sous forme d'objet JSON, en utilisant la même syntaxe que celle utilisée dans le script précédent.
  • Si le code de réponse était autre, nous imprimons le code d'état comme une « erreur inattendue ».

Cela devrait gérer toutes les erreurs que nous sommes susceptibles de rencontrer en appelant l'API. À ce stade, nous avons soit un message d'erreur et l'objet None, soit du succès et un objet JSON contenant zéro ou plusieurs clés SSH. Notre prochaine étape est de les imprimer :

...

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')

Parce que la réponse contient une liste (ou tableau) de clés SSH, nous voulons parcourir toute la liste afin de voir toutes les clés. Nous utilisons la méthode enumerate de Python pour cela. C'est similaire à la méthode items disponible pour les dictionnaires, mais elle fonctionne avec des listes à la place.

Nous utilisons enumerate et pas seulement une boucle for, car nous voulons pouvoir savoir à quel point nous sommes dans la liste pour une clé donnée.

Les informations de chaque clé sont renvoyées sous forme de dictionnaire, donc nous utilisons le même code for k,v in details.items(): que celui que nous avons utilisé dans le dictionnaire d'informations du compte dans le script précédent.

Exécutez ce script et vous obtiendrez une liste des clés SSH déjà présentes sur votre compte.

  1. python get_ssh_keys.py

La sortie ressemblera à quelque chose comme ceci, en fonction du nombre de clés SSH que vous avez déjà sur votre compte.

Here 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

Maintenant que vous pouvez lister les clés SSH de votre compte, votre dernier script ici sera celui qui ajoute une nouvelle clé à la liste.

Avant de pouvoir ajouter une nouvelle clé SSH, nous devons en générer une. Pour un traitement plus complet de cette étape, consultez le tutoriel Comment configurer des clés SSH.

Pour nos besoins, cependant, nous avons juste besoin d'une clé simple. Exécutez cette commande pour en générer une nouvelle sur Linux, BSD ou MacOS. Vous pouvez le faire sur un Droplet existant, si vous le souhaitez.

  1. ssh-keygen -t rsa

Lorsque vous y êtes invité, entrez le fichier pour enregistrer la clé et ne fournissez pas de phrase de passe.

Generating 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.
...

Prenez note de l'endroit où le fichier de clé publique a été enregistré, car vous en aurez besoin pour le script.

Démarrez un nouveau script Python et appelez-le add_ssh_key.py, et commencez-le comme les autres :

import json
import requests


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

Nous utiliserons une fonction pour faire notre demande, mais celle-ci sera légèrement différente.

Créez une fonction appelée add_ssh_key qui acceptera deux arguments : le nom à utiliser pour la nouvelle clé SSH, et le nom du fichier de la clé elle-même sur votre système local. La fonction lira le fichier et effectuera une requête HTTP POST, au lieu d'une GET :

...

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)

La ligne with open(filename, 'r') as f: ouvre le fichier en mode lecture seule, et la ligne qui suit lit la première (et seule) ligne du fichier, la stockant dans la variable ssh_key.

Ensuite, nous créons un dictionnaire Python appelé ssh_key avec les noms et les valeurs que l'API attend.

Cependant, lorsque nous envoyons la requête, il y a un peu plus de nouveauté. C'est un POST plutôt qu'un GET, et nous devons envoyer la ssh_key dans le corps de la requête POST, codée en tant que JSON. Le module requests gérera les détails pour nous ; requests.post lui indique d'utiliser la méthode POST, et le fait d'inclure json=ssh_key lui indique d'envoyer la variable ssh_key dans le corps de la requête, codée en tant que JSON.

Selon l'API, la réponse sera HTTP 201 en cas de succès, au lieu de 200, et le corps de la réponse contiendra les détails de la clé que nous venons d'ajouter.

Ajoutez le code de gestion des erreurs suivant à la fonction add_ssh_key. C'est similaire au script précédent, sauf que cette fois, nous devons rechercher le code 201 au lieu de 200 pour le succès :

...
    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

Cette fonction, comme les précédentes, renvoie soit None, soit le contenu de la réponse, nous utilisons donc la même approche qu'auparavant pour vérifier le résultat.

Ensuite, appelez la fonction et traitez le résultat. Passez le chemin vers votre clé SSH nouvellement créée comme deuxième argument :

...
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')

Exécutez ce script et vous recevrez une réponse vous informant que votre nouvelle clé a été ajoutée.

  1. python add_ssh_key.py

La sortie ressemblera à quelque chose comme ceci :

Your 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'}

Si vous avez oublié de changer la condition de "succès" pour chercher le code HTTP 201 au lieu de 200, vous verrez une erreur signalée, mais la clé aura tout de même été ajoutée. Votre gestion des erreurs vous aurait dit que le code de statut était 201. Vous devriez reconnaître cela comme un membre de la série 200, qui indique un succès. C'est un exemple de la façon dont la gestion des erreurs de base peut simplifier le dépannage.

Une fois que vous avez ajouté avec succès la clé avec ce script, exécutez-le à nouveau pour voir ce qui se passe lorsque vous essayez d'ajouter une clé qui est déjà présente.

L'API renverra une réponse HTTP 422, que votre script traduira par un message disant “La clé SSH est déjà utilisée sur votre compte.”

[!] [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

Maintenant, exécutez à nouveau votre script get_ssh_keys.py et vous verrez votre clé nouvellement ajoutée dans la liste.

Avec quelques modifications mineures, ces deux scripts pourraient être un moyen rapide d'ajouter de nouvelles clés SSH à votre compte DigitalOcean chaque fois que vous en avez besoin. Les fonctions associées de cette API vous permettent de renommer ou de supprimer une clé spécifique en utilisant son identifiant de clé unique ou son empreinte.

Regardons une autre API et voyons comment les compétences que vous venez d'apprendre se traduisent.

Étape 4 — Travailler avec une autre API

GitHub a aussi une API. Tout ce que vous avez appris sur l'utilisation de l'API DigitalOcean est directement applicable à l'utilisation de l'API GitHub.

Familiarisez-vous avec l'API GitHub de la même manière que vous l'avez fait avec DigitalOcean. Recherchez la documentation de l'API et parcourez la section Présentation. Vous constaterez immédiatement que l'API GitHub et l'API DigitalOcean présentent certaines similarités.

Tout d'abord, vous remarquerez qu'il y a une racine commune à toutes les URL de l'API : https://api.github.com/. Vous savez comment l'utiliser comme une variable dans votre code pour rationaliser et réduire le potentiel d'erreurs.

L'API de GitHub utilise JSON comme format de requête et de réponse, tout comme DigitalOcean, donc vous savez comment effectuer ces requêtes et gérer les réponses.

Les réponses incluent des informations sur les limites de taux dans les en-têtes de réponse HTTP, en utilisant presque les mêmes noms et exactement les mêmes valeurs que DigitalOcean.

GitHub utilise OAuth pour l'authentification, et vous pouvez envoyer votre jeton dans un en-tête de requête. Les détails de ce jeton sont un peu différents, mais la manière dont il est utilisé est identique à celle que vous avez déjà utilisée avec l'API de DigitalOcean.

Il y a aussi quelques différences. GitHub encourage l'utilisation d'un en-tête de requête pour indiquer la version de l'API que vous souhaitez utiliser. Vous savez comment ajouter des en-têtes aux requêtes en Python.

GitHub veut également que vous utilisiez une chaîne User-Agent unique dans vos requêtes, afin qu'ils puissent vous trouver plus facilement si votre code cause des problèmes. Vous gérerez cela avec un en-tête également.

L'API GitHub utilise les mêmes méthodes de requête HTTP, mais utilise également une nouvelle appelée PATCH pour certaines opérations. L'API GitHub utilise GET pour lire des informations, POST pour ajouter un nouvel élément, et PATCH pour modifier un élément existant. Cette requête PATCH est le type de chose à surveiller dans la documentation de l'API.

Toutes les appels à l'API GitHub ne nécessitent pas d'authentification. Par exemple, vous pouvez obtenir une liste des dépôts d'un utilisateur sans avoir besoin d'un jeton d'accès. Créons un script pour effectuer cette demande et afficher les résultats.

Nous allons simplifier la gestion des erreurs dans ce script et utiliser une seule instruction pour gérer toutes les erreurs possibles. Vous n'avez pas toujours besoin de code pour gérer chaque type d'erreur séparément, mais c'est une bonne habitude de faire quelque chose avec les conditions d'erreur, ne serait-ce que pour vous rappeler que les choses ne se passent pas toujours comme vous l'attendez.

Créez un nouveau fichier appelé github_list_repos.py dans votre éditeur et ajoutez le contenu suivant, qui devrait vous sembler assez familier :

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'}

Les importations sont les mêmes que celles que nous avons utilisées. Le api_url_base est l'endroit où toutes les API de GitHub commencent.

Les en-têtes incluent deux des options mentionnées par GitHub dans leur aperçu, plus celui qui indique que nous envoyons des données au format JSON dans notre requête.

Bien que ceci soit un petit script, nous allons tout de même définir une fonction afin de garder notre logique modulaire et d'encapsuler la logique pour effectuer la requête. Souvent, vos petits scripts évolueront vers des plus grands, donc il est utile d'être diligent à ce sujet. Ajoutez une fonction appelée get_repos qui accepte un nom d'utilisateur comme argument :

...
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

À l'intérieur de la fonction, nous construisons l'URL à partir de api_url_base, le nom de l'utilisateur qui nous intéresse, et les parties statiques de l'URL qui indiquent à GitHub que nous voulons la liste des dépôts. Ensuite, nous vérifions le code d'état HTTP de la réponse pour nous assurer qu'il était 200 (succès). Si c'était réussi, nous renvoyons le contenu de la réponse. Si ce n'était pas le cas, alors nous imprimons le code d'état réel et l'URL que nous avons construite afin d'avoir une idée de l'endroit où nous avons pu nous tromper.

Maintenant, appelez la fonction et passez le nom d'utilisateur GitHub que vous souhaitez utiliser. Nous utiliserons octokit pour cet exemple. Ensuite, imprimez les résultats à l'écran :

...
repo_list = get_repos('octokit')

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

Enregistrez le fichier et exécutez le script pour voir les dépôts de l'utilisateur que vous avez spécifié.

  1. python github_list_repos.py

Vous verrez beaucoup de données dans la sortie car nous n'avons pas analysé la réponse en tant que JSON dans cet exemple, ni avons-nous filtré les résultats pour des clés spécifiques. Utilisez ce que vous avez appris dans les autres scripts pour le faire. Regardez les résultats que vous obtenez et voyez si vous pouvez imprimer le nom du dépôt.

Une chose agréable à propos de ces API GitHub, c'est que vous pouvez accéder aux requêtes pour lesquelles vous n'avez pas besoin d'authentification directement dans votre navigateur web. Cela vous permet de comparer les réponses à ce que vous voyez dans vos scripts. Essayez de visiter https://api.github.com/orgs/octokit/repos dans votre navigateur pour voir la réponse.

À présent, vous savez comment lire la documentation et écrire le code nécessaire pour envoyer des demandes plus spécifiques afin de soutenir vos propres objectifs avec l'API GitHub.

Vous pouvez trouver le code complet pour tous les exemples de ce tutoriel dans ce dépôt sur GitHub.

Conclusion

Dans ce tutoriel, vous avez appris à utiliser des API Web pour deux services différents avec des styles légèrement différents. Vous avez vu l'importance d'inclure du code de gestion des erreurs pour faciliter le débogage et rendre les scripts plus robustes. Vous avez utilisé les modules Python requests et json pour vous isoler des détails de ces technologies et simplement réaliser votre travail, et vous avez encapsulé le traitement des demandes et des réponses dans une fonction pour rendre vos scripts plus modulaires.

Et ce n'est pas tout, vous avez maintenant un processus répétable à suivre lorsque vous apprenez une nouvelle API web :

  1. Trouvez la documentation et lisez l'introduction pour comprendre les fondamentaux de la façon d'interagir avec l'API.
  2. Obtenez un jeton d'authentification si vous en avez besoin, et écrivez un script modulaire avec une gestion d'erreurs basique pour envoyer une requête simple, répondre aux erreurs et traiter la réponse.
  3. Créez les demandes qui vous permettront d'obtenir les informations que vous souhaitez desservir.

Maintenant, consolidez ce savoir nouvellement acquis et trouvez une autre API à utiliser, ou même une autre fonctionnalité de l'une des API que vous avez utilisées ici. Un projet personnel vous aidera à solidifier ce que vous avez appris ici.