5 façons de faire des requêtes HTTP en Ruby

February 24, 2021
Rédigé par
Révisé par

5 façons de faire des requêtes HTTP en Ruby

Bonjour et bienvenue dans cet article. Aujourd’hui nous allons voir ensemble comment faire des requêtes HTTP en Ruby de cinq façons différentes.

Mais avant de nous plonger dans le code, je voulais juste prendre une minute pour partager avec vous ma joie d’avoir écrit ce tutoriel.

Pour l’écriture de cet article, j’ai tout fait avec de simples fichiers .rbet je ne le savais pas mais ça m’avait manqué de m’éloigner de mon framework favori - RubyOnRails - et de toute sa magie et de revenir aux basiques de ce qu’est Ruby.

Et le meilleur dans tout ça ? Les basiques fonctionnent aussi dans les cas plus complexes, donc je vous montrerai comment intégrer tout ça dans votre framework Ruby préféré en fin d’article.

Prérequis

Pour suivre ce tutoriel, vous aurez besoin de:

  • Ruby installé sur votre machine. J’utilise Ruby dans sa dernière version, actuellement 3.0.0 et je gère mes installations et versions avec rvm sur OSX mais faites comme bon vous semble.
  • Un éditeur de texte. J’utilise sublime text ou vim mais votre éditeur préféré fera parfaitement l’affaire.

Ce que l’on va accomplir aujourd’hui

Nous allons faire des requêtes HTTP, POST et GET en utilisant cinq méthodes différentes pour arriver à nos fins. Nous allons coder en Ruby et pour chaque requête nous allons créer un fichier avec une extension .rb et exécuter ce fichier depuis notre console à l’aide de la commande ruby comme suit :

$ ruby fichier.rb

Ce que l’on va voir ensemble

On va faire un petit tour d’horizon des librairies Ruby suivantes :

Requêtes GET

Nous utiliserons l’API photo du jour de la NASA, APOD.

Cette API renvoie, aux requêtes réussies, une réponse en JSON avec un code HTTP de réponse 200.

Notre but sera d’afficher le corps de la réponse body dans la console comme suit.

Note sur les clefs d’API : Nous pouvons ici nous permettre d’utiliser la clef d’API DEMO_KEY mise à disposition par la NASA car nous n’allons faire que quelques requêtes et ne risquons pas d’atteindre les limites des quotas. Si vous prévoyez un usage un peu plus intensif de l’API, prenez votre propre clef d’API.

{
  "date": "2019-07-20",
  "explanation": "Have you seen a panorama from another world lately? ...",
  "hdurl": "https://apod.nasa.gov/apod/image/1907/a11pan1040226lftsm.jpg",
  "media_type": "image",
  "service_version": "v1",
  "title": "Apollo 11 Landing Panorama",
  "url": "https://apod.nasa.gov/apod/image/1907/a11pan1040226lftsm600.jpg"
}

Requêtes POST

Nous utiliserons JSONPlaceholder, un outil de démonstration pour les API pour faire nos requêtes POST.

Nous allons simuler la création de nouveaux articles avec pour titre foo, comme corps d’article bar et définir un userID à 1. Bien sûr c’est de la fausse donnée à but éducatif. Dans le monde réel nous pourrions créer un article ayant pour titre 5 façons de faire des requêtes HTTP en Ruby et ayant comme corps le texte de l'article que vous êtes en train de lire actuellement.

Aucun besoin de clef d’API ici, vous devez juste vous attendre à voir une réponse similaire à ce qui suit dans votre console :

{
  "title": "foo",
  "body": "bar",
  "userID": "1",
  "id": 101
}

Le standard: net/HTTP

Net/HTTP est une classe de Ruby. Le plus souvent elle est utilisée avec URI.

Requête GET de base

# nethttp.rb
require 'uri'
require 'net/http'

uri = URI('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY')
res = Net::HTTP.get_response(uri)
puts res.body if res.is_a?(Net::HTTPSuccess)
$ ruby nethttp.rb

Ici nous disons à URI quelle est l’URL que nous voulons requêter, puis utilisons la méthode get_response de la classe Net::HTTP.

Ensuite nous vérifions que la requête ait été un succès et affichons le résultat dans la console si c’est le cas.

Paramètres séparés

# nethttp2.rb
require 'uri'
require 'net/http'

uri = URI('https://api.nasa.gov/planetary/apod')
params = { :api_key => 'your_api_key' }
uri.query = URI.encode_www_form(params)

res = Net::HTTP.get_response(uri)
puts res.body if res.is_a?(Net::HTTPSuccess)

Ici nous faisons la même chose que précédemment, mais nous passons les paramètres séparément dans un hash. C’est une bonne pratique lorsque nous devons créer des paramètres complexes ou contenant des informations venant de différentes sources.

Le hash est un objet très commun en Ruby et peut aider à rendre la lecture du code vraiment plus simple. N’hésitez pas à en faire usage.

Une fois nos paramètres définis dans notre hash, nous les passons à la fonction encode_www_form de la librairie URI, ce qui à pour effet de transposer notre objet Ruby hash en un format compatible pour le web. Ensuite nous faisons la même chose que précédemment pour la requête, la validation et l’affichage.

Requête POST

# nethttp3.rb
require 'uri'
require 'net/http'

uri = URI('https://jsonplaceholder.typicode.com/posts')
res = Net::HTTP.post_form(uri, 'title' => 'foo', 'body' => 'bar', 'userID' => 1)
puts res.body  if res.is_a?(Net::HTTPSuccess)

Pour cette requête, nous utilisons la méthode post_form de la classe Net::HTTP et passons en premier paramètre notre uri et ensuite nos paramètres title,body et userID sous le format clé valeur.

Puis nous vérifions et affichons le résultat comme vu sur les requêtes précédentes.

Bien sûr, n'hésitez pas à vous plonger dans la documentation pour en savoir plus sur toutes les possibilités et vous pouvez aussi consulter ce cheat sheet. Pour les cas d'usage les plus complexes, vous pouvez jeter un œil au wrapper OpenURI qui englobe ce que l’on vient de voir ainsi que deux autres classes utiles.

httparty: Make requests fun again!

httparty est une gem populaire lorsqu'il s’agit de faire des requêtes. Installez la avec :

$ gem install httparty
# httparty.rb
require 'httparty'

response = HTTParty.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY')
puts response.body if response.code == 200

Pour cette requête, nous avons juste besoin de dire à httparty la méthode que nous voulons utiliser, ici get, et lui passer l’UL complète en paramètre.

L’objet envoyé par httparty en réponse contient un tas de méthodes utiles.

Dans le cas présent nous utilisons la méthode code pour voir si l’API nous à bien renvoyé un code 200. Si c’est le cas, nous afficherons le contenu de la méthode body.

Mais ce ne sont pas les seules possibilités. Par exemple, response.parsed_response vous renverra le corps de la réponse en JSON parsé.

Requête POST, avec classe s’il vous plaît !

Ce que je vais vous montrer ici est une implémentation commune de cette gem, mais n’est en aucun cas une obligation. Il est possible d’utiliser la gem dans une classe créée pour répondre à nos besoins. Et oui, ça aussi nous pouvons le faire dans un fichier .rb tout simple !

# httparty2.rb
require "httparty"

class PostManager
  include HTTParty
  base_uri 'https://jsonplaceholder.typicode.com'

  def initialize()

  end

  def create_post(title, body, user_id)
    params = { body: { title: title, body: body, userID: user_id } }
    self.class.post("/posts", params).parsed_response
  end
end

post_manager = PostManager.new()
p post_manager.create_post("foo", "bar", 1)

Avec ce code, nous créons une classe PostManager et initialisons notre variable de classe base_uri à l’adresse de l’API à laquelle nous souhaitons faire des requêtes.

Cette classe comporte une méthode create_post qui accepte trois paramètres: le title le bodyet l’userID que nous avons déjà vus.

Puis nous utilisons la méthode post sur l’objet self.class, et lui passons les paramètres que nous avons reçus en entrée.

Maintenant que la classe est créée, nous pouvons en créer une nouvelle instance avec PostManager.new() et utiliser la méthode de classe create_post, en lui passant nos arguments nécessaires à la création de notre article de test.

Vous avez peut-être aussi remarqué que la classe comporte une méthode initialize. C’est un pattern commun en Ruby. Nous n’en avons pas l’usage ici mais c’est vraiment pratique dans des cas plus complexes.

Besoin d’idées pour enrichir cette classe ?

Vous pourriez ajouter une méthode  read_post pour faire des requêtes avec la méthode get et avoir des informations sur un post ou en créer une pour supprimer des posts, qui serait nommée delete_post et utiliserait la méthode delete.

Bonus

httparty embarque une interface en ligne de commande - CLI. Ce qui veut dire qu’une fois la gem installée vous pouvez l’utiliser directement dans votre console:

$ httparty votre_url

HTTP (The Gem! a.k.a. http.rb)

http.rb est une autre gem connue. Vous pouvez l’installer avec :

$ gem install http
# http.rb
require "http"

response = HTTP.get("https://api.nasa.gov/planetary/apod", :params => {:api_key => "DEMO_KEY"})
p response.parse

Ici nous passons l’URL puis les paramètres dans un hashparams à la méthode get de HTTP.

Utiliser .parse sur l’objet de réponse de la requête, parse le JSON reçu en réponse et le renvoie sous forme de hash, que nous affichons dans la console.

Requête POST

# http2.rb
require "http"

response = HTTP.post("https://jsonplaceholder.typicode.com/posts", :form => {'title' => 'foo', 'body' => 'bar', 'userID' => 1})
p response.parse

Bonus gestion de réponses

Nous avons utilisé la méthode parse à chaque fois pour gérer les réponses car nous savions par avance qu’elles seraient au format JSON. Voici deux autres méthodes utiles pour d’autres formats de données :

  • to_s. Oui, la méthode Ruby qui transforme les objets en string peut être appelée pour “stringifier” tout le contenu du corps de la réponse. À utiliser comme suit: response.body.to_s.
  • readpartial: cette méthode est très utile pour lire les documents html ligne par ligne. Elle s'utilise en appelant response.body.readpartial autant de fois que nécessaire pour parcourir l’intégralité des parties du document html reçu en réponse. Plus d’informations ici.

HTTPX le concurrent

La différence majeure entre http et les autres gems présentées ici est sa prise en charge par défaut du protocole HTTP2, ce qui en fait un très bon outil pour les requêtes concurrentes. Pour l’installation :

$ gem install httpx
# httpx.rb
require "httpx"

response = HTTPX.get("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY")
puts response.body if response.status == 200

Pour les fonctionnalités basiques httpx fonctionne comme la plupart des autres, il suffit de lui donner l’URL complète avec les paramètres et utiliser la méthode du verbe HTTP que l’on souhaite utiliser, ici get.

Requête POST

# httpx2.rb
require "httpx"

response = HTTPX.post("https://jsonplaceholder.typicode.com/posts", :json => {'title' => 'foo', 'body' => 'bar', 'userID' => 1})
puts response.body if response.status == 201

Pour cette requête post, nous passons les paramètres dans un hash nommé json qui les transmettra dans ce format de données lors de la requête. Puis nous afficherons le body de la réponse si le statut de la réponse est un code HTTP 201, ce qui signifie conformément au standard: créé.

Requêtes GET simultanées

# httpx3.rb
require 'httpx'

base_url = "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY"
response, response2 = HTTPX.get(base_url, base_url + "&date=2019-07-20")
puts response.body if response.status == 200
puts response2.body if response2.status == 200

La première chose que l’on fait ici est de stocker l’URL complète de l’API de la NASA avec le paramètre api_key=DEMO_KEY dans la variable base_url.

Puis nous disons à httpx de faire deux requêtes simultanées, une à l’URL que nous avons déjà requêtée, et une autre à cette url mais cette fois avec un paramètre supplémentaire: une date arbitraire.

Puis nous affichons dans la console le body des deux réponses que nous venons d’obtenir.

C’est l’usage de base des fonctionnalités concurrentielles de httpx mais vous vous en doutez, il est capable de bien plus si besoin.

Faraday

La dernière des gems populaires que nous allons voir aujourd’hui est Faraday. Installation :

$ gem install faraday
# faraday.rb
require "faraday"

response = Faraday.get("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY")
p response.body if response.status == 200

Si vous avez suivi jusqu’ici vous avez probablement deviné ce qu’il se passe ici. En utilisant la méthode get de Faraday avec comme paramètre l’URL de l’API de la NASA, on obtient une réponse dont on affiche le body dans la console si le statut HTTP de la requête est un code 200.

Requête POST avec paramètres encodés

# faraday2.rb
require "faraday"
require 'uri'

params = {title: "foo", body: "bar", userID: 1}
encoded_params = URI.encode_www_form(params)
response = Faraday.post("https://jsonplaceholder.typicode.com/posts", encoded_params)
p response.body if response.status == 201

Ici les paramètres sont encodés à l’aide de URI.encode_www_form, puis nous faisons la requête post.

URI est une librairie standard de Ruby, et vous avez peut être remarqué que nous l'avons déjà utilisée avec net/HTTP au début de cet article.

Requête POST avec bloc do

# faraday3.rb
require "faraday"

response = Faraday.post "https://jsonplaceholder.typicode.com/posts" do |request|
  request.body = URI.encode_www_form({title: "foo", body: "bar", userID: 1})
end
p response.body if response.status == 201

Une autre façon de passer des paramètres supplémentaires à notre requête Faraday est d’utiliser un bloc do.

Ici on utilise la méthode bodypour passer nos paramètres encodés mais plusieurs autres méthodes sont disponibles dont request.headers['Content-Type'] = 'application/json' pour définir le type de contenu attendu via les headers - ici du JSON - ou encore request.params.

La raison pour laquelle Faraday est populaire, c’est ses middlewares. Ils fournissent beaucoup de fonctions pour traiter l’authentification, les formats xml et yml et un tas d’autres choses utiles.

Utiliser ces solutions dans n’importe quel framework basé sur Ruby

Pour utiliser les gems et librairies dont on vient de parler dans Ruby on Rails, Sinatra, Hanami… etc, vous pouvez juste enlever la ligne de code require X et ajouter dans votre Gemfile :

gem 'X'

N’oubliez pas de lancer la commande $ bundle install dans votre console après chaque édit de votre Gemfile.

Pour conclure

Toutes les solutions dont on a parlé aujourd’hui sont relativement équivalentes pour faire des requêtes simples. Leurs différences se remarquent dès que l’on va vers des usages avancés.

Lorsque vous décidez laquelle utiliser dans votre projet, gardez en tête les problèmes techniques auxquels ces solutions répondent dans leur conception même.

Bien sûr il y aurait tant d'autres choses à dire à propos de chaque gem et solution dont on a parlé et pour en connaître toutes les capacités, lisez les documentations et expérimentez par vous même en codant.

Personnellement j’utilise httparty, principalement parce que c’était déjà populaire quand j’ai appris le Ruby, que la librairie est simple à utiliser et qu’il y a beaucoup d’exemples dans des articles et sur Stack Overflow. Et aussi parce que j’aime énormément faire la fête ? Peut être...

Je suis aussi d’un œil l’évolution de httpx parce que le projet est encore assez jeune mais offre des possibilités intéressantes.

Vous voulez vous aérer l’esprit avant de retourner à vos requêtes ? Vous pouvez apprendre à télécharger les fichiers image en Ruby ou jouer un peu avec WhatsApp.

 

 

Valériane Venance est Developer Evangelist chez Twilio. Contactez-la sur vvenance@twilio.com ou sur Twitter si vous codez des projets cool en Ruby!