Ruby invia una richiesta JSON


86

Come invio una richiesta JSON in ruby? Ho un oggetto JSON ma non penso di poterlo fare .send. Devo fare in modo che javascript invii il modulo?

O posso usare la classe net / http in ruby?

Con header - content type = json e body l'oggetto json?

Risposte:


77
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

8
Mi piace il tuo suggerimento di utilizzare l'URI per gestire il nome host e la porta, che altrimenti è piuttosto noioso. Ma ti sei dimenticato di impostare uri.path in Post.new (...):req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
ArnauOrriols

1
Risposta più semplice e pulita. Questo è fantastico.
joelc

http.request(req).read_bodyper leggere il corpo della risposta. Grande!
iGian

1
Sono abbastanza sicuro che sia cambiato nella 2.4.1 ma mio dio. Questa sintassi è grossolana. Sa di avere l'URI di Post.new () quindi perché devi ripassare i valori, divisi, in start (). Schifoso. Non c'è da stupirsi che ci siano così tanti altri pacchetti in ruby ​​che si occupano di http.
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

Quale eccezione deve essere specificata
mio

7
Per le richieste https basta aggiungere: http.use_ssl = true.
Skill M2

16

HTTParty lo rende un po 'più semplice penso (e funziona con json nidificato ecc., Che non sembra funzionare in altri esempi che ho visto.

require 'httparty'
HTTParty.post("http://localhost:3000/api/v1/users", body: {user: {email: 'user1@example.com', password: 'secret'}}).body

6

esempio di vita reale, notifica all'API Airbrake di una nuova distribuzione tramite 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)

Appunti:

nel caso in cui esegui l'autenticazione tramite l'intestazione del set di intestazioni di autorizzazione req['Authorization'] = "Token xxxxxxxxxxxx" o http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html


... ma onestamente questo è cool e tutti, ma in tempo reale dal vivo vorrei solo usare HTTParty stackoverflow.com/a/14491995/473040 :) ... soprattutto se avete a che fare con https movimentazione
equivalent8

richiedere uri è inutile in quanto è già richiesto da net / http
noraj

@ equivalent8: "nella vita reale userei solo HTTParty" - cioè, a meno che tu non stia costruendo una gemma snella, o altrimenti non desideri un'altra dipendenza. :)
Sergio Tulentsev

@SergioTulentsev d'accordo ... a meno che tu non stia costruendo gem / lib (o microservizio basato su Ruby) dove non vuoi introdurre dipendenze non necessarie;)
equivalente

5

Un semplice esempio di richiesta POST json per coloro che ne hanno bisogno ancora più semplice di quello a cui Tom si collega:

require 'net/http'

uri = URI.parse("http://www.example.com/search.json")
response = Net::HTTP.post_form(uri, {"search" => "Berlin"})

19
Sembra che dovrebbe funzionare, ma post_form traduce i parametri nella sintassi? Key = value & key = value. Se vuoi fare un POST con il corpo della richiesta impostato su una stringa JSON, penso che tu abbia bisogno di una soluzione diversa.
Ben Gotow

Questo non funziona con json profondamente annidato. Qualsiasi cosa oltre il primo livello diventa una stringa.
neoneye

Non sembra solo. Funziona. È semplice sicuro. ma per cose semplici come l'esempio che ho dato funziona perfettamente
Christoffer

4
Questa non è fondamentalmente una richiesta JSON. Questo è un corpo con codifica URL. Non c'è JSON. Anche l'intestazione dice altrettanto. Questo non funziona con nessun esempio, mai.
raylu

4
Questa risposta non è corretta. È un POST in mime / multipart, a un URL che dice "json".
John Haugeland,

4

È il 2020 - nessuno dovrebbe più usare Net::HTTPe tutte le risposte sembrano dirlo, usa una gemma di livello più alto come Faraday - Github


Detto questo, quello che mi piace fare è un wrapper attorno alla chiamata API HTTP, qualcosa che si chiama come

rv = Transporter::FaradayHttp[url, options]

perché questo mi consente di falsificare le chiamate HTTP senza dipendenze aggiuntive, ad esempio:

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

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

Dove il falsario assomiglia a questo

So che esistono framework di mocking / stubbing HTTP, ma almeno quando ho cercato l'ultima volta non mi hanno permesso di convalidare le richieste in modo efficiente ed erano solo per HTTP, non ad esempio per scambi TCP grezzi, questo sistema mi permette di avere un framework unificato per tutte le comunicazioni API.


Supponendo che tu voglia solo convertire rapidamente e in modo sporco un hash in json, invia il json a un host remoto per testare un'API e analizzare la risposta a ruby, questo è probabilmente il modo più veloce senza coinvolgere gemme aggiuntive:

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

Si spera che sia ovvio, ma non usarlo in produzione.


Non puoi farlo utilizzando l'autenticazione NTLM. Quindi Net :: HTTP è ancora l'unico che ha una libreria che lo supporta.
Rhuan

3
Non sono d'accordo con l' Net::HTTPaffermazione "nessuno dovrebbe usare "
JellicleCat

1
Downvoted a causa di nobody should be using Net::HTTP any more@bbozo
Patricio Sard

3

Funziona su ruby ​​2.4 HTTPS Post con oggetto JSON e il corpo della risposta scritto.

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

2

Mi piace questo client di richiesta http leggero chiamato `unirest '

gem install unirest

utilizzo:

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

1

L'api net / http può essere difficile da usare.

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

Questo codice non funziona. Devi inizializzare Net :: HTTP con #start in questo modo:Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |client|
Tyler

Funziona con ruby ​​2.3.7p456 (2018-03-28 revisione 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'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.