Les API, un enfeR ?

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 distant
  • POST : 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’échange
  • Un corps : les données échangées

Côté réponse

  • Un statut : les informations sur l’état (200,404…)
  • Des headers : les métainformations
  • Un 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 ! 

# Faire venir les données avec fromJSON
data <- fromJSON("https://geo.api.gouv.fr/communes?codePostal=35200&fields=nom,code,codesPostaux,codeDepartement,codeRegion,population&format=json&geometry=centre")

 

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 :

# Construire une fonction qui appelle l'API
get_by_code <- function(query){
  url <- paste("https://geo.api.gouv.fr/communes?codePostal=",query, "&fields=nom,code,codesPostaux,codeDepartement,codeRegion,population&format=json&geometry=centre", sep = "")
  result <- fromJSON(url)
  return(result)
}
get_by_code("35200")

Plutôt que de passer par fromJSON, vous pouvez également découper cet appel avec httr. 

# Appel de l'url avec GET
response <- httr::GET(url)
response
> Response [https://geo.api.gouv.fr/communes?codePostal=35200&fields=nom,code,codesPostaux,codeDepartement,codeRegion,population&format=json&geometry=centre]
  Date: 2017-07-03 12:50
  Status: 200
  Content-Type: application/json; charset=utf-8
  Size: 135 B

# Récupération du contenu
response2 <- response$content
response2

>  [1] 5b 7b 22 6e 6f 6d 22 3a 22 52 65 6e 6e 65 73 22 2c 22 63 6f 64 65 22 3a 22
 [26] 33 35 32 33 38 22 2c 22 63 6f 64 65 73 50 6f 73 74 61 75 78 22 3a 5b 22 33
 [51] 35 30 30 30 22 2c 22 33 35 32 30 30 22 2c 22 33 35 37 30 30 22 5d 2c 22 63
 [76] 6f 64 65 44 65 70 61 72 74 65 6d 65 6e 74 22 3a 22 33 35 22 2c 22 63 6f 64
[101] 65 52 65 67 69 6f 6e 22 3a 22 35 33 22 2c 22 70 6f 70 75 6c 61 74 69 6f 6e
[126] 22 3a 32 31 31 33 37 33 7d 5d

# Transformation en contenu lisible
response3 <- rawToChar(response2)
response3
 
> [1] "[{\"nom\":\"Rennes\",\"code\":\"35238\",\"codesPostaux\":[\"35000\",\"35200\",\"35700\"],\"codeDepartement\":\"35\",\"codeRegion\":\"53\",\"population\":211373}]"

# Depuis JSON

response4 <- fromJSON(response3)
response4

>      nom  code        codesPostaux codeDepartement codeRegion population
1 Rennes 35238 35000, 35200, 35700              35         53     211373

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.

# Étape 1 

data <- fromJSON("https://haveibeenpwned.com/api/v2/breachedaccount/[email protected]")
datatable(data[,1:4])

# Construire sa requête dans R 

query <- "[email protected]"
url <- paste("https://haveibeenpwned.com/api/v2/breachedaccount/",query, sep = "")
fromJSON(url)

Mais voilà, que se passe-t-il si nous avons plusieurs emails à tester ?

query <- list("[email protected]", "[email protected]", "[email protected]","[email protected]","[email protected]")

lapply(query, FUN = function(x){
  url <- paste("https://haveibeenpwned.com/api/v2/breachedaccount/",x, sep = "")
  fromJSON(url)
})

>  Error in open.connection(con, "rb") : HTTP error 429.

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

# Créer deux variables : access_key et query
access_key <- "XXXX"
query <- "Anglet c'est fun"
#Les coller dans l'url
url <- paste("http://apilayer.net/api/detect?access_key =", access_key, "&query=", query, sep = "")
# Effectuer la requête
data <- fromJSON("http://apilayer.net/api/detect?access_key=fd82b89719707d36fe030538c2985d24&query=On%20est%20bien%20%C3%A0%20Anglet")

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 !

# Construire l'ensemble de la requête POST

#L'url à appeller
url <- "https://westcentralus.api.cognitive.microsoft.com/vision/v1.0/analyze?visualFeatures=Tags,Description,Faces,Categories"

# Le JSON de requête
request_body <- data.frame(url = 'https://pbs.twimg.com/profile_images/865461055706644481/ADoCCueR_400x400.jpg')
request_body_json <- toJSON(request_body, auto_unbox = "TRUE")
request_body_json <- gsub("\\[|\\]", "", request_body_json)

# Le content-type
Contenttype <- "application/json"

#Le serveur lié à votre compte 
Host <- "westcentralus.api.cognitive.microsoft.com"

# L'API key
api_key <- "XXX"

# Et enfin, la requête
result <- POST(url,
               body = request_body_json,
               add_headers(.headers = c("Content-Type"=Contenttype,"Host"=Host,"Ocp-Apim-Subscription-Key"=api_key))) %>%
  content()

Pretty easy, n’est-ce pas ? Alors maintenant, à votre tour !


À propos de l'auteur

Colin Fay

Colin Fay

Data scientist & R Hacker


Commentaires


À lire également