Ruby sendet JSON-Anfrage

85

Wie sende ich eine JSON-Anfrage in Ruby? Ich habe ein JSON-Objekt, aber ich glaube nicht, dass ich es einfach tun kann .send. Muss ich das Formular von Javascript senden lassen?

Oder kann ich die net / http-Klasse in Ruby verwenden?

Mit header - content type = json und body das json Objekt?

Andy
quelle

Antworten:

75
uri = URI('https://myapp.com/api/v1/resource')
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
req.body = {param1: 'some value', param2: 'some other value'}.to_json
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
  http.request(req)
end
CarelZA
quelle
7
Ich mag Ihren Vorschlag, URI zu verwenden, um den Hostnamen und den Port zu verarbeiten, was ansonsten ziemlich mühsam ist. Aber Sie haben vergessen, uri.path in Post.new (...) zu setzen:req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
ArnauOrriols
1
Einfachste und sauberste Antwort. Das ist toll.
Joel
http.request(req).read_bodyum den Antworttext zu lesen. Toll!
iGian
1
Ich bin mir ziemlich sicher, dass es in 2.4.1 geändert wurde, aber mein Gott. Diese Syntax ist grob. Es weiß, dass es den URI von Post.new () hat. Warum müssen Sie also die Werte in start () neu aufteilen? Brutto. Kein Wunder, dass es in Ruby so viele andere Pakete gibt, die sich mit http befassen.
Rambatino
50
require 'net/http'
require 'json'

def create_agent
    uri = URI('http://api.nsa.gov:1337/agent')
    http = Net::HTTP.new(uri.host, uri.port)
    req = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
    req.body = {name: 'John Doe', role: 'agent'}.to_json
    res = http.request(req)
    puts "response #{res.body}"
rescue => e
    puts "failed #{e}"
end
neoneye
quelle
Welche Ausnahme sollte angegeben werden
Mio
7
Für https-Anfragen fügen Sie einfach Folgendes hinzu: http.use_ssl = true.
Fähigkeit M2
17

HTTParty macht dies meiner Meinung nach etwas einfacher (und funktioniert mit verschachteltem JSON usw., was in anderen Beispielen, die ich gesehen habe, nicht zu funktionieren schien.

require 'httparty'
HTTParty.post("http://localhost:3000/api/v1/users", body: {user: {email: '[email protected]', password: 'secret'}}).body
Brian Armstrong
quelle
6

Beispiel aus der Praxis : Benachrichtigen Sie die Airbrake-API über eine neue Bereitstellung über NetHttps

require 'uri'
require 'net/https'
require 'json'

class MakeHttpsRequest
  def call(url, hash_json)
    uri = URI.parse(url)
    req = Net::HTTP::Post.new(uri.to_s)
    req.body = hash_json.to_json
    req['Content-Type'] = 'application/json'
    # ... set more request headers 

    response = https(uri).request(req)

    response.body
  end

  private

  def https(uri)
    Net::HTTP.new(uri.host, uri.port).tap do |http|
      http.use_ssl = true
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end
  end
end

project_id = 'yyyyyy'
project_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
url = "https://airbrake.io/api/v4/projects/#{project_id}/deploys?key=#{project_key}"
body_hash = {
  "environment":"production",
  "username":"tomas",
  "repository":"https://github.com/equivalent/scrapbook2",
  "revision":"live-20160905_0001",
  "version":"v2.0"
}

puts MakeHttpsRequest.new.call(url, body_hash)

Anmerkungen:

Für den Fall, dass Sie die Authentifizierung über den Autorisierungsheader-Set-Header req['Authorization'] = "Token xxxxxxxxxxxx" oder http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html durchführen

Äquivalent8
quelle
... aber ehrlich gesagt ist das cool und alles andere als im wirklichen Leben würde ich einfach HTTParty stackoverflow.com/a/14491995/473040 verwenden :) ... besonders wenn Sie sich mit https-Handling beschäftigen
Äquivalent8
uri zu benötigen ist nutzlos, da es bereits von net / http
noraj
@ äquivalent8: "Im wirklichen Leben würde ich nur HTTParty verwenden" - das heißt, es sei denn, Sie erstellen ein schlankes Juwel oder möchten auf andere Weise keine weitere Abhängigkeit. :)
Sergio Tulentsev
@SergioTulentsev stimmen zu ... es sei denn, Sie erstellen gem / lib (oder Ruby-basierten Microservice), wo Sie keine unnötigen Abhängigkeiten einführen möchten;)
äquivalent8
4

Ein einfaches Beispiel für eine json POST-Anfrage für diejenigen, die es noch einfacher benötigen als das, worauf Tom verlinkt:

require 'net/http'

uri = URI.parse("http://www.example.com/search.json")
response = Net::HTTP.post_form(uri, {"search" => "Berlin"})
Christoffer
quelle
19
Das sieht so aus, als ob es funktionieren sollte, aber post_form übersetzt die Parameter in die Syntax? Key = value & key = value. Wenn Sie einen POST mit einem auf eine JSON-Zeichenfolge festgelegten Anforderungshauptteil durchführen möchten, benötigen Sie meiner Meinung nach eine andere Lösung.
Ben Gotow
Dies funktioniert nicht mit tief verschachteltem JSON. Alles, was über die erste Ebene hinausgeht, wird zu einer Zeichenfolge.
Neoneye
Sieht nicht nur so aus. Es klappt. Es ist einfach sicher. aber für einfache Dinge wie das Beispiel, das ich gegeben habe, funktioniert es gut
Christoffer
4
Dies ist grundsätzlich keine JSON-Anfrage. Dies ist ein urlencodierter Körper. Es gibt keinen JSON. Der Header sagt sogar so viel. Dies funktioniert mit keinem Beispiel.
Raylu
4
Diese Antwort ist falsch. Es ist ein POST in Mime / Multipart, zu einer URL, die "json" darin sagt.
John Haugeland
4

Es ist 2020 - niemand sollte Net::HTTPmehr verwenden und alle Antworten scheinen dies zu sagen. Verwenden Sie ein höherwertiges Juwel wie Faraday - Github


Das heißt, was ich gerne mache, ist ein Wrapper um den HTTP-API-Aufruf, so etwas heißt

rv = Transporter::FaradayHttp[url, options]

weil dies mir erlaubt, HTTP-Aufrufe ohne zusätzliche Abhängigkeiten zu fälschen, dh:

  if InfoSig.env?(:test) && !(url.to_s =~ /localhost/)
    response_body = FakerForTests[url: url, options: options]

  else
    conn = Faraday::Connection.new url, connection_options

Wo die Fälscher so etwas wie sieht diese

Ich weiß, dass es HTTP-Mocking / Stubbing-Frameworks gibt, aber zumindest als ich das letzte Mal nachforschte, erlaubten sie mir nicht, Anforderungen effizient zu validieren, und sie waren nur für HTTP, nicht zum Beispiel für rohen TCP-Austausch, dieses System ermöglicht mir ein einheitliches Framework für die gesamte API-Kommunikation.


Angenommen, Sie möchten einen Hash nur schnell und schmutzig in JSON konvertieren, senden Sie den JSON an einen Remote-Host, um eine API zu testen und die Antwort auf Ruby zu analysieren. Dies ist wahrscheinlich der schnellste Weg, ohne zusätzliche Edelsteine ​​zu verwenden:

JSON.load `curl -H 'Content-Type:application/json' -H 'Accept:application/json' -X POST localhost:3000/simple_api -d '#{message.to_json}'`

Hoffentlich ist das selbstverständlich, aber verwenden Sie dies nicht in der Produktion.

bbozo
quelle
2
Lol, warum all die Hasser? :) Der Beitrag gibt eindeutig an, dass es nicht für die Produktion oder einen anderen ernsthaften Zweck bestimmt ist, aber es ist der schnellste Weg, einen JSON-API-Aufruf einzurichten, um zu sehen, wie sich ein Dienst verhält
bbozo
Sie können dies nicht mit der NTLM-Authentifizierung tun. Net :: HTTP ist also immer noch das einzige Unternehmen, das über eine Bibliothek verfügt, die dies unterstützt.
Rhuan
1
Nicht einverstanden mit der Net::HTTPBehauptung "Niemand sollte verwenden "
JellicleCat
Wegen des nobody should be using Net::HTTP any more@bbozo
Patricio Sard
3

Dies funktioniert auf Ruby 2.4 HTTPS Post mit JSON-Objekt und dem ausgeschriebenen Antworttext.

require 'net/http' #net/https does not have to be required anymore
require 'json'
require 'uri'

uri = URI('https://your.secure-url.com')
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
  request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
  request.body = {parameter: 'value'}.to_json
  response = http.request request # Net::HTTPResponse object
  puts "response #{response.body}"
end
szabcsee
quelle
2

Ich mag diesen leichten http-Anfrage-Client namens "unirest".

gem install unirest

Verwendung:

response = Unirest.post "http://httpbin.org/post", 
                        headers:{ "Accept" => "application/json" }, 
                        parameters:{ :age => 23, :foo => "bar" }

response.code # Status code
response.headers # Response headers
response.body # Parsed body
response.raw_body # Unparsed body
tokhi
quelle
1

Die net / http-API kann schwierig zu bedienen sein.

require "net/http"

uri = URI.parse(uri)

Net::HTTP.new(uri.host, uri.port).start do |client|
  request                 = Net::HTTP::Post.new(uri.path)
  request.body            = "{}"
  request["Content-Type"] = "application/json"
  client.request(request)
end
Moriarty
quelle
Dieser Code funktioniert nicht. Sie müssen Net :: HTTP mit #start wie folgt initialisieren:Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |client|
Tyler
Funktioniert mit Ruby 2.3.7p456 (28.03.2018, Revision 63024) [universal.x86_64-darwin18]
Moriarty
0
data = {a: {b: [1, 2]}}.to_json
uri = URI 'https://myapp.com/api/v1/resource'
https = Net::HTTP.new uri.host, uri.port
https.use_ssl = true
https.post2 uri.path, data, 'Content-Type' => 'application/json'
phil pirozhkov
quelle