Transcription de l’intervention de Colin aux Rencontres R d’Anglet !
Pourquoi ?
Il s’agit effectivement de la première question à se poser. Pourquoi avoir envie de parler de R et des API. Eh bien, pour plusieurs raisons :
- Parce que quand on cherche des données, on est bien souvent confronté à une API web
- Parce que quand on est adepte de R, on ne connaît pas forcément par cœur les protocoles HTTP
- Parce qu’un newbie qui se lance a parfois envie d’entendre une autre réponse que “Read the fuckin’ man“
- Parce que nous sommes tous d’anciens noobs, et qu’on aurait aimé trouver, quelque part, quelqu’un pour nous guider
En clair, une conférence que l’on aurait pu appeler : “Ces trucs que j’aurais voulu qu’on me dise quand je me suis lancé dans les API”.
C’est quoi une API ?
Contraction de Application Programming Interface, l’API est un protocole qui permet de faire communiquer un logiciel A (le fournisseur) et un logiciel B (le consommateur), en suivant une série de méthodes définies par A (des règles de langage, en quelque sorte). En théorie, on accède à une API en plongeant dans la documentation. En pratique, c’est souvent un peu plus compliqué…
Interroger une API
Pour “parler” avec une API, il faut utiliser une série de verbes précis — ce billet se concentrant sur la requête de données, nous verrons les deux les plus courants.
GET
: va “chercher” la ressource sur le serveur distantPOST
: va “poster” sur le serveur, qui analyse la requête afin de renvoyer une réponse
À noter qu’il en existe d’autres, comme PUT
, ou encore DELETE
…
Nous avons donc deux acteurs dans notre échange : un qui effectue la requête, et un qui renvoie une réponse. Attardons-nous un instant sur l’anatomie de cet échange. Il contiendra :
Côté requête
Une url
: l’adresse unique d’un emplacement sur le serveur interrogéUne méthode
: GET, POST, DELETE…Des headers
: les métainformations sur l’échangeUn corps
: les données échangées
Côté réponse
Un statut
: les informations sur l’état (200,404…)Des headers
: les métainformationsUn corps
: les données échangées
En pratique
Alors, dans la vraie vie, comment ça se passe ? Zoom sur quatre API.
GéoAPI
La GéoAPI, mise en ligne par Etalab, renvoie les informations géographiques des communes, départements, et régions de France. Cette API est simple d’utilisation : il suffit de parcourir la console, et de tester afin d’obtenir l’url à appeler dans notre requête — par exemple : “https://geo.api.gouv.fr/communes?codePostal=35200&fields=nom,code,codesPostaux,codeDepartement,codeRegion,population&format=json&geometry=centre“. Ensuite, la première étape est de tester cette url dans son navigateur web, qui renvoie un objet JSON. Parfait, il suffit maintenant de faire venir dans R avec fromJSON !
[pastacode lang=”R” manual=”%23%20Faire%20venir%20les%20donn%C3%A9es%20avec%20fromJSON%0Adata%20%3C-%20fromJSON(%22https%3A%2F%2Fgeo.api.gouv.fr%2Fcommunes%3FcodePostal%3D35200%26fields%3Dnom%2Ccode%2CcodesPostaux%2CcodeDepartement%2CcodeRegion%2Cpopulation%26format%3Djson%26geometry%3Dcentre%22)” message=”” highlight=”” provider=”manual”/]
Mais voilà, vous souhaitez construire une fonction qui fait cet appel, et c’est bien normal, vous avez besoin d’automatiser vos recherches. Alors, que faire ? Il suffit simplement de définir des paramètres, qui contiendront l’élément à faire varier (par exemple ici 35200), puis de les copier dans une url. En clair :
[pastacode lang=”R” manual=”%23%20Construire%20une%20fonction%20qui%20appelle%20l’API%0Aget_by_code%20%3C-%20function(query)%7B%0A%20%20url%20%3C-%20paste(%22https%3A%2F%2Fgeo.api.gouv.fr%2Fcommunes%3FcodePostal%3D%22%2Cquery%2C%20%22%26fields%3Dnom%2Ccode%2CcodesPostaux%2CcodeDepartement%2CcodeRegion%2Cpopulation%26format%3Djson%26geometry%3Dcentre%22%2C%20sep%20%3D%20%22%22)%0A%20%20result%20%3C-%20fromJSON(url)%0A%20%20return(result)%0A%7D%0Aget_by_code(%2235200%22)%0A” message=”” highlight=”” provider=”manual”/]
Plutôt que de passer par fromJSON, vous pouvez également découper cet appel avec httr.
[pastacode lang=”R” manual=”%23%20Appel%20de%20l’url%20avec%20GET%0Aresponse%20%3C-%20httr%3A%3AGET(url)%0Aresponse%0A%3E%20Response%20%5Bhttps%3A%2F%2Fgeo.api.gouv.fr%2Fcommunes%3FcodePostal%3D35200%26fields%3Dnom%2Ccode%2CcodesPostaux%2CcodeDepartement%2CcodeRegion%2Cpopulation%26format%3Djson%26geometry%3Dcentre%5D%0A%20%20Date%3A%202017-07-03%2012%3A50%0A%20%20Status%3A%20200%0A%20%20Content-Type%3A%20application%2Fjson%3B%20charset%3Dutf-8%0A%20%20Size%3A%20135%20B%0A%0A%23%20R%C3%A9cup%C3%A9ration%20du%20contenu%0Aresponse2%20%3C-%20response%24content%0Aresponse2%0A%0A%3E%20%20%5B1%5D%205b%207b%2022%206e%206f%206d%2022%203a%2022%2052%2065%206e%206e%2065%2073%2022%202c%2022%2063%206f%2064%2065%2022%203a%2022%0A%20%5B26%5D%2033%2035%2032%2033%2038%2022%202c%2022%2063%206f%2064%2065%2073%2050%206f%2073%2074%2061%2075%2078%2022%203a%205b%2022%2033%0A%20%5B51%5D%2035%2030%2030%2030%2022%202c%2022%2033%2035%2032%2030%2030%2022%202c%2022%2033%2035%2037%2030%2030%2022%205d%202c%2022%2063%0A%20%5B76%5D%206f%2064%2065%2044%2065%2070%2061%2072%2074%2065%206d%2065%206e%2074%2022%203a%2022%2033%2035%2022%202c%2022%2063%206f%2064%0A%5B101%5D%2065%2052%2065%2067%2069%206f%206e%2022%203a%2022%2035%2033%2022%202c%2022%2070%206f%2070%2075%206c%2061%2074%2069%206f%206e%0A%5B126%5D%2022%203a%2032%2031%2031%2033%2037%2033%207d%205d%0A%0A%23%20Transformation%20en%20contenu%20lisible%0Aresponse3%20%3C-%20rawToChar(response2)%0Aresponse3%0A%20%0A%3E%20%5B1%5D%20%22%5B%7B%5C%22nom%5C%22%3A%5C%22Rennes%5C%22%2C%5C%22code%5C%22%3A%5C%2235238%5C%22%2C%5C%22codesPostaux%5C%22%3A%5B%5C%2235000%5C%22%2C%5C%2235200%5C%22%2C%5C%2235700%5C%22%5D%2C%5C%22codeDepartement%5C%22%3A%5C%2235%5C%22%2C%5C%22codeRegion%5C%22%3A%5C%2253%5C%22%2C%5C%22population%5C%22%3A211373%7D%5D%22%0A%0A%23%20Depuis%20JSON%0A%0Aresponse4%20%3C-%20fromJSON(response3)%0Aresponse4%0A%0A%3E%20%20%20%20%20%20nom%20%20code%20%20%20%20%20%20%20%20codesPostaux%20codeDepartement%20codeRegion%20population%0A1%20Rennes%2035238%2035000%2C%2035200%2C%2035700%20%20%20%20%20%20%20%20%20%20%20%20%20%2035%20%20%20%20%20%20%20%20%2053%20%20%20%20%20211373%0A” message=”” highlight=”” provider=”manual”/]
Pourquoi tant de lignes de code alors que fromJSON()
suffit ? Tout simplement parce que, si vous souhaitez créer un package pour faire ces appels, il vous faudra pouvoir gérer les éventuelles erreurs HTTP, et renvoyer un message à l’utilisateur — ce que vous pouvez faire ici à l’étape 1.
HaveIBeenPwned
Votre adresse mail est-elle compromise ? C’est ce que cherche à tester HaveIBeenPwned. Ici, même chose que plus haut, un parcours de la doc vous permet de voir comment construire votre url requête.
[pastacode lang=”R” manual=”%23%20%C3%89tape%201%20%0A%0Adata%20%3C-%20fromJSON(%22https%3A%2F%2Fhaveibeenpwned.com%2Fapi%2Fv2%2Fbreachedaccount%2Ftest%40example.com%22)%0Adatatable(data%5B%2C1%3A4%5D)%0A%0A%23%20Construire%20sa%20requ%C3%AAte%20dans%20R%20%0A%0Aquery%20%3C-%20%22test%40example.com%22%0Aurl%20%3C-%20paste(%22https%3A%2F%2Fhaveibeenpwned.com%2Fapi%2Fv2%2Fbreachedaccount%2F%22%2Cquery%2C%20sep%20%3D%20%22%22)%0AfromJSON(url)” message=”” highlight=”” provider=”manual”/]
Mais voilà, que se passe-t-il si nous avons plusieurs emails à tester ?
[pastacode lang=”language-r” manual=”query%20%3C-%20list(%22test%40example.com%22%2C%20%22colin%40thinkr.fr%22%2C%20%22vincent%40thinkr.fr%22%2C%22diane%40thinkr.fr%22%2C%22romain%40thinkr.fr%22)%0A%0Alapply(query%2C%20FUN%20%3D%20function(x)%7B%0A%20%20url%20%3C-%20paste(%22https%3A%2F%2Fhaveibeenpwned.com%2Fapi%2Fv2%2Fbreachedaccount%2F%22%2Cx%2C%20sep%20%3D%20%22%22)%0A%20%20fromJSON(url)%0A%7D)%0A%0A%3E%20%20Error%20in%20open.connection(con%2C%20%22rb%22)%20%3A%20HTTP%20error%20429.%0A” message=”” highlight=”” provider=”manual”/]
Erreur 429… mais de quoi est-il question ? Il s’agit du code d’erreur HTTP de votre appel à l’API (souvenez-vous, nous vous disions tout à l’heure que chaque requête contenait un numéro explicitant le statut de l’échange). Ici, si nous faisons un tour dans la doc, nous constatons qu’il s’agit d’une erreur liée au volume de requêtes que nous envoyons. Une réponse que l’on obtient avec un simple cmd+F dans la doc 😉
Language Layer
Language Layer est une API qui vous permet de détecter la langue issue d’une chaîne de caractères. La différence avec les deux précédentes ? Une clé d’accès est nécessaire. Donc, direction une inscription, puis le tableau de bord pour récupérer le code.
Ici, les requêtes vont par définition être plus longues : à cause de la clé à ajouter dans l’url, mais aussi parce que les données envoyées seront contenues dans une chaîne plus longue. Alors, même s’il est tentant de se jeter sur la méthode fromJSON(url)
, nous sommes ici face à un cas où la construction par étape est beaucoup, beaucoup plus efficace.
Note : la clé d’API a été masquée
[pastacode lang=”R” manual=”%23%20Cr%C3%A9er%20deux%20variables%20%3A%20access_key%20et%20query%0Aaccess_key%20%3C-%20%22XXXX%22%0Aquery%20%3C-%20%22Anglet%20c’est%20fun%22%0A%23Les%20coller%20dans%20l’url%0Aurl%20%3C-%20paste(%22http%3A%2F%2Fapilayer.net%2Fapi%2Fdetect%3Faccess_key%20%3D%22%2C%20access_key%2C%20%22%26query%3D%22%2C%20query%2C%20sep%20%3D%20%22%22)%0A%23%20Effectuer%20la%20requ%C3%AAte%0Adata%20%3C-%20fromJSON(%22http%3A%2F%2Fapilayer.net%2Fapi%2Fdetect%3Faccess_key%3Dfd82b89719707d36fe030538c2985d24%26query%3DOn%2520est%2520bien%2520%25C3%25A0%2520Anglet%22)” message=”” highlight=”” provider=”manual”/]
Microsoft Computer Vision
Microsoft Computer Vision est une API de reconnaissance d’images — autrement dit, vous lui envoyez l’url, et le serveur vous retourne les informations qu’il trouve pour décrire cette image. Le tout, par un process un peu plus complexe que ce que nous avons vu jusqu’ici.
Première étape : nous devons faire une requête de type POST. En clair, c’est R qui envoie des données au serveur, qui lui retourne une réponse.
Mais voilà, ce n’est pas aussi simple que ça :
- Vous devrez poster sur une url spécifique, contenant les paramètres
- Votre corps de requête doit être au format JSON
- Vous devrez spécifier le Content-type
- Il faut envoyer sur un serveur précis, celui lié à votre compte
- Et bien sûr, vous avez besoin d’un clé d’accès
Et tout ça, au bon endroit ! Mais si vous avez bien suivi, vous saurez que le premier élément est contenu dans l’url de la requête, le second dans le body, et les trois derniers dans les headers. Alors, GO !
[pastacode lang=”R” manual=”%23%20Construire%20l’ensemble%20de%20la%20requ%C3%AAte%20POST%0A%0A%23L’url%20%C3%A0%20appeller%0Aurl%20%3C-%20%22https%3A%2F%2Fwestcentralus.api.cognitive.microsoft.com%2Fvision%2Fv1.0%2Fanalyze%3FvisualFeatures%3DTags%2CDescription%2CFaces%2CCategories%22%0A%0A%23%20Le%20JSON%20de%20requ%C3%AAte%0Arequest_body%20%3C-%20data.frame(url%20%3D%20’https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F865461055706644481%2FADoCCueR_400x400.jpg’)%0Arequest_body_json%20%3C-%20toJSON(request_body%2C%20auto_unbox%20%3D%20%22TRUE%22)%0Arequest_body_json%20%3C-%20gsub(%22%5C%5C%5B%7C%5C%5C%5D%22%2C%20%22%22%2C%20request_body_json)%0A%0A%23%20Le%20content-type%0AContenttype%20%3C-%20%22application%2Fjson%22%0A%0A%23Le%20serveur%20li%C3%A9%20%C3%A0%20votre%20compte%20%0AHost%20%3C-%20%22westcentralus.api.cognitive.microsoft.com%22%0A%0A%23%20L’API%20key%0Aapi_key%20%3C-%20%22XXX%22%0A%0A%23%20Et%20enfin%2C%20la%20requ%C3%AAte%0Aresult%20%3C-%20POST(url%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20body%20%3D%20request_body_json%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20add_headers(.headers%20%3D%20c(%22Content-Type%22%3DContenttype%2C%22Host%22%3DHost%2C%22Ocp-Apim-Subscription-Key%22%3Dapi_key)))%20%25%3E%25%0A%20%20content()” message=”” highlight=”” provider=”manual”/]
Pretty easy, n’est-ce pas ? Alors maintenant, à votre tour !
[…] lancer dans ses premières requêtes sur des API. Envie d’en savoir plus ? Rassurez-vous, le billet de blog est là […]
[…] Les API, un enfeR ? […]