5 Möglichkeiten für HTTP-Anfragen in Ruby

February 24, 2021
Autor:in:
Prüfer:in:
Phil Nash
Twilion

5 Möglichkeiten für HTTP-Anfragen in Ruby


Hallo und Danke fürs Lesen! Dieser Blogpost ist eine Übersetzung von 5 ways to make HTTP requests in Ruby. Während wir unsere Übersetzungsprozesse verbessern, würden wir uns über Dein Feedback an help@twilio.com freuen, solltest Du etwas bemerken, was falsch übersetzt wurde. Wir bedanken uns für hilfreiche Beiträge mit Twilio Swag :)

Hallo und willkommen zu diesem Artikel! Heute zeige ich fünf Möglichkeiten für HTTP-Anfragen in Ruby.

Bevor wir mit dem Schreiben von Code beginnen, muss ich zum Ausdruck bringen, wie froh ich darüber bin, dass ich dieses Tutorial schreiben durfte. Ruby on Rails ist das Framework, dass ich am liebsten verwende. Und wie es sich für einen richtigen Fan gehört, nutze ich es so gut wie immer.

Die Rückbesinnung auf einfache Dinge wie HTTP-Anfragen führte dazu, dass ich wieder einfache .rb-Dateien schrieb und ausführte. Großartig, wie spielend einfach das dank der Leistung von Ruby ging. Oftmals schweifen wir mit Rails doch weit von den Grundlagen der Programmiersprache ab.

Das Beste an den Klassikern ist jedoch ihre Funktionalität in komplexeren Umgebungen. Ich kann hier also demonstrieren, wie man bei .rb-Dateien vorgeht, in allen anderen auf Ruby basierenden Frameworks funktioniert es aber genauso gut.

Nun wird es aber Zeit, dass wir uns die 5 Möglichkeiten für HTTP-Anfragen in beliebigen auf Ruby basierenden Programmen ansehen.

Voraussetzungen

Für dieses Tutorial ist Folgendes notwendig:

  • Auf dem Rechner muss Ruby installiert sein. Ich verwende die neueste Version 3.0.0 von Ruby und rvm auf OSX, aber jede andere Version funktioniert auch.
  • ein Texteditor Ich verwende sublime text oder vim, alle anderen können aber auch verwendet werden.

Das ist unser Ziel

Wir erstellen mit fünf unterschiedlichen Methoden GET- und POST-Anfragen. Wir nutzen plain Ruby und erstellen für jede Anfrage eine Datei mit .rb-Erweiterung. Diese führen wir in unserer Konsole mit diesem Ruby-Befehl aus

$ ruby file.rb

Das erwartet uns

Wir unternehmen eine kleine Tour durch die folgenden Ruby-Bibliotheken:

GET-Anfragen

Wir nutzen die API NASA's picture of the dayAPOD.

Die API sendet die Antwort auf erfolgreiche Anfragen im JSON-Format mit dem Antwortcode 200. Unsere Konsole zeigt daraufhin den Response-Body an.

Hinweis zu API-Schlüsseln: Wir verwenden hier den von der NASA bereitgestellten Schlüssel DEMO_KEY, da wir nur ein paar Anfragen erstellen und damit nicht die Nutzungsobergrenze der API erreichen werden. Ist eine Überschreitung abzusehen, ist ein API-Schlüssel notwendig.

{
  "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"
}

POST-Anfragen

Für POST-Anfragen erstellen wir Artikel mit JSONPlaceholder, einem Demo-Tool für API-Anfragen.

Wir werden die Erstellung neuer Artikel mit title foo, body bar und userID auf 1 simulieren. Das sind natürlich alles fingierte Daten, die wir zu Lernzwecken nutzen.

Einen API-Schlüssel brauchen wir nicht. Die Konsole zeigt auch ohne Schlüssel eine Ausgabe an, die dieser hier ähnelt:

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

Der Standard: net/HTTP

Net/HTTP ist eine standardmäßige Ruby-Klasse und wird meistens zusammen mit URI verwendet.

Einfache GET-Anfrage

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

An dieser Stelle sagen wir URI, welche URL wir anfragen möchten. Dies ist eine URL, da https:// angegeben ist. Dann nutzen wir die Methode get_response aus der Bibliothek Net::HTTP.

Zum Schluss prüfen wir, ob die Anfrage erfolgreich war. Wenn dem so ist, drucken wir dann das Ergebnis in der Konsole aus.

Getrennte params

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

Wir gehen hier genauso vor wie zuvor, allerdings fügen wir params getrennt als Hash ein. Das ist sehr praktisch, wenn params aus verschiedenen Quellen bezogen werden oder es einfach zu viele werden. Hashes sind ein oft verwendetes Objekt in Ruby und leicht zu formatieren, um den Code lesbar zu machen – also einfach ausprobieren!

Nachdem wir unsere params definiert haben, legen wir für unsere params für uri.query fest, dass wir in einem Format web-kompatiblen Format kodieren und encode_www_form verwenden. Mehr unterscheidet sich nicht.

POST-Anfrage

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

Für diese Anfrage nutzen wir die Methode post_form von Net::HTTP und geben unsere params nach uri in einer Schlüsselwertform an. Anschließend drucken wir den Response-Body aus, wenn die Anfrage erfolgreich war.

Wer noch tiefer in das Thema eintauchen möchte, dem lege ich natürlich die Dokumentation ans Herz. Außerdem ist dieses Cheat Sheet perfekt für einen schnellen Einstieg. Für eine komplexere Verwendung bietet sich der OpenURI wrapper an, der zwei weitere nützliche Bibliotheken umfasst.

httparty: Anfragen und Spaß dabei!

httparty ist ein beliebtes Gem für Anfragen. Am besten sofort installieren mit

$ 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

Für diese Anfrage müssen wir httparty nur sagen, wie wir get an dieser Stelle verwenden möchten, dazu geben wir einfach nur die komplette URL ein.

Das Antwortobjekt von httparty enthält zahlreiche praktische Methoden. Hier verwenden wir die Methode code, um zu überprüfen, ob die Anfrage erfolgreich war. Falls dem so ist, verwenden wir die Methode body, um den JSON-Body auszudrucken, den uns die NASA-API zurückgesendet hat. Aber das war längst noch nicht alles. response.parsed_response gibt beispielsweise JSON in geparster Form zurück.

POST-Anfrage, einmal ganz klassisch!

Eine oft verwendete aber komplett optionale Implementierung des Gems ist die Erstellung einer Klasse. Bevor Fragen aufkommen – ja, das geht mit nur einer .rb-Datei.

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

Hier erstellen wir eine PostManager-Klasse und setzen base_uri auf die Basis-URL der API, an die sich die Anfrage richten soll.

Diese Klasse nutzt die Methode create_post mit 3 Parametern: title, body und userID, die wir bereits zuvor gesehen haben.

Wir verwenden dann die Methode post in self.class unter Eingabe der Parameter, die wir aus der Methodeninitialisierung erhalten haben.

Nun müssen wir mit PostManager.new() nur noch eine neue Instanz dieser Klasse erstellen.

Ach ja, und die Methode create_post mit unseren Argumenten verwenden.

Wir sehen, dass die Klasse auch eine initialize-Methode enthält, die wir für den Aufbau komplexerer Anwendungsfälle nutzen können.

Wir können natürlich auch weitere Methoden hinzufügen. Hier ist es sinnvoll, read_post unter Verwendung einer get-Methode oder eine delete_post-Methode unter Verwendung der delete-Methode hinzuzufügen. Der Kreativität sind hier keine Grenzen gesetzt.

Hier noch ein kleines Extra!

httparty bietet eine CLI, die wir nach der Installation des Gems direkt in unserer Konsole verwenden können:

$ httparty your_url

HTTP (The Gem! alias http.rb)

http.rb ist ein weiteres Gem. Am besten sofort installieren mit

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

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

Wir nutzen die Methode get von HTTP und geben unsere URL sowie die params als Hash unter dem Namen params ein.

Mit .parse für unser Antwortobjekt wird JSON in einen Hash geparst.

POST-Anfrage

# http2.rb
require "http"

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

Zusätzliche Antwortreaktionen

Ich möchte darauf hinweisen, dass die von uns gedruckten Antworten mit .parse geparst wurden, weil sie JSON waren und uns dies bekannt war. Es gibt aber noch weitere praktische Methoden, um den Response-Body zu verändern.

  • to_s. Der Aufruf der Ruby-Methode des to-Strings packt die gesamte Inhaltsantwort in einen String, wenn response.body.to_s verwendet wird.
  • readpartial: sehr praktisch zum Lesen von html-Dokumenten Zeile für Zeile. Verwende es als response.body.readpartial. Wir müssen diese Methode bei jedem Chunk im html-Dokument aufrufen. Mehr Infos dazu gibt es hier.

Der Konkurrent: HTTPX

Was httpx von anderen Gems unterscheidet, ist seine standardmäßige HTTP2-Eigenschaft – einfach großartig beim Pipelining und bei Konkurrenzanfragen. Am besten sofort installieren mit

$ 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

httpx ist in seinen grundlegenden Funktionen ziemlich gradlinig. Wir geben die komplette URL mit params ein und nutzen die Objektmethode, die nach dem HTTP-Verb benannt ist, das wir verwenden möchten.

POST-Anfrage

# 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

In dieser POST-Anfrage verwenden wir die Methode post von HTTPX und stellen die params in einem Hash bereit.

Wir drucken den Body, wenn der Response-Status 201 ist, was im HTTP-Standard erstellt bedeutet.

Mehrere, gleichzeitige GET-Anfragen

# 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

Hier speichern wir die Basis-URL der NASA-API mit unserem API-Schlüssel und sagen HTTPX, dass es zwei GET-Anfragen gleichzeitig ausführen soll: eine für die URL, die wir bereits angefragt haben, und eine weitere für dieselbe URL mit dem zusätzlichen Parameter „date“. So erhalten wir Informationen zum Bild des Tages zu genau dem Datum, das wir als Parameter eingegeben haben.

Anschließend drucken wir die beiden gerade abgerufenen Response-Bodys in unserer Konsole.

Diese Basisanwendung kann auf jeden Fall bei Bedarf erweitert werden.

Faraday

Ein weiteres Gem, das häufig genutzt wird, ist Faraday. Nutzt Folgendes zur 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

Wenn du mir bis hierhin folgen konntest, kannst du sicher schon ahnen, was hier passiert. Wir verwenden die get -Methode von Faraday mit der API-URL der NASA und drucken den Response-Body, wenn der Code 200 lautet.

Wie in der Konsole zu erkennen, wird der Body im Design nicht als JSON behandelt, sondern als String angezeigt.

POST-Anfrage mit URI-codierten Parametern

# 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

Wir definieren unsere params als Hash. Anschließend stellen wir encoded_params auf unsere params ein, die in einer web-kompatiblen Form unter Verwendung der Methode encode_www_form aus URI codiert werden.

URI ist eine standardmäßige Ruby-Bibliothek, die wir bereits kennengelernt haben, als wir net/HTTP verwendet haben. Dann nutzen wir die Methode Faraday.post und drucken die Response aus.

POST-Anfrage mit do-Block

# 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

Weitere Einstellungen für unsere Faraday-Anfragen können wir mit dem do-Block eingeben.

Wir verwenden das Objekt, das im do-Block erstellt wurde, zur Nutzung der .body-Objektmethode zum Hinzufügen unserer mit URI codierten params.

Es gibt weitere nützliche Methoden zur Einstellung des Inhaltstyps der Anfrage, wie das hier verwendete request.headers['Content-Type'] = 'application/json', oder request.params.

Der Grund für die Beliebtheit von Faraday ist die verfügbare Middleware. Wir können damit viele nützliche Funktionen in Sachen Authentifizierung, xml- und yml-Formate und weitere spannende Sachen nutzen. Am besten, du siehst dir das hier genauer an.

Anwendung in allen auf das Ruby-Framework basierenden Anwendungen

Für die Nutzung der oben genannten Methoden in Ruby on Rails, Sinatra, Hanami usw. müssen wir nur die require X-Linie entfernen und stattdessen das Gemfile unserer Anwendung hinzufügen:

gem 'X'

Wir dürfen natürlich nicht vergessen, $ bundle install in unserer Konsole auszuführen, wenn wir unser Gemfile bearbeiten.

Fazit

Alle hier aufgeführten Lösungen sind für einfache Anfragen bestens geeignet. Der Unterschied zwischen ihnen zeigt sich erst auf einem fortgeschrittenen Anwendungsniveau.

Wir dürfen nicht vergessen, dass sie alle für bestimmte Bedürfnisse entwickelt wurden, daher sind die Spezifikationen im Design wohl ausschlaggebend bei der Entscheidung für oder gegen eine dieser Lösungen, wenn die Anwendungsfälle komplexer werden.

Klar, es gibt noch so viel mehr zu diesen hier vorgestellten Gems und ihren hier nicht erwähnten Funktionen zu erfahren, aber dazu kannst du mehr in den ausführlichen Dokumentationen erfahren. 

Ich verwende httparty am häufigsten, weil es bereits weitverbreitet war, als ich Ruby erlernte. Es war benutzerfreundlich und einfach zu verstehen, außerdem findet man tonnenweise Beispiele in StackOverflow. Soll ich mal ganz ehrlich sein? Ich wurde geködert, und zwar mit dem Slogan: „Es gibt nur eine Party: httparty! Mit Open End!“

Httpx behalte ich auch im Auge, weil das Gem zwar noch etwas in den Kinderschuhen steckt, aber schon interessante Funktionen zu bieten hat.

Wie wäre es mit etwas frischem Wind, bevor es mit Anfragen weitergeht? Dann erfahre, wie du Bilddateien herunterladen kannst oder mit WhatsApp und Ruby spielen kannst!

Valériane Venance ist Developer Evangelist bei Twilio. Sie ist über vvenance@twilio.com oder auf Twitter zu erreichen und stets an coolen, mit Ruby konfigurierten Sachen interessiert. Sie freut sich über deine Nachrichten.