Ruby mengirim permintaan JSON

86

Bagaimana cara mengirim permintaan JSON di ruby? Saya memiliki objek JSON tetapi saya rasa saya tidak bisa melakukannya .send. Apakah saya harus meminta javascript untuk mengirimkan formulir?

Atau dapatkah saya menggunakan kelas net / http di ruby?

Dengan header - content type = json dan body objek json?

Andy
sumber

Jawaban:

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
CarelZA
sumber
8
Saya menyukai saran Anda untuk menggunakan URI untuk menangani nama host dan porta, yang sebaliknya cukup membosankan. Tetapi Anda lupa menyetel uri.path di Post.new (...):req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
ArnauOrriols
1
Respons paling sederhana dan paling bersih. Ini bagus.
joelc
http.request(req).read_bodyuntuk membaca isi respons. Bagus!
iGian
1
Saya cukup yakin itu berubah di 2.4.1 tapi Tuhan. Sintaks itu kasar. Ia tahu ia memiliki URI dari Post.new () jadi mengapa Anda harus mengalikan kembali nilainya, berpisah, di start (). Kotor. Tidak heran ada begitu banyak paket lain di ruby ​​yang berhubungan dengan 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
neoneye
sumber
Pengecualian mana yang harus ditentukan
Mio
7
Untuk permintaan https cukup tambahkan: http.use_ssl = true.
Keterampilan M2
16

HTTParty membuat ini sedikit lebih mudah menurut saya (dan bekerja dengan json bersarang dll, yang sepertinya tidak berfungsi dalam contoh lain yang pernah saya lihat.

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

contoh kehidupan nyata, beri tahu Airbrake API tentang penerapan baru melalui 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)

Catatan:

jika Anda melakukan otentikasi melalui header set header Otorisasi req['Authorization'] = "Token xxxxxxxxxxxx" atau http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html

setara8
sumber
... tapi sejujurnya ini keren dan semuanya tetapi secara langsung saya hanya akan menggunakan HTTParty stackoverflow.com/a/14491995/473040 :) ... terutama jika Anda berurusan dengan penanganan https
ekuivalen8
membutuhkan uri tidak berguna karena sudah disyaratkan oleh net / http
noraj
@ ekuivalen8: "dalam kehidupan nyata saya hanya akan menggunakan HTTParty" - yaitu, kecuali Anda sedang membangun permata lean, atau tidak menginginkan ketergantungan lain. :)
Sergio Tulentsev
@SergioTulentsev setuju ... kecuali jika Anda sedang membangun permata / lib (atau Ruby MICROSERVICE berdasarkan) di mana Anda tidak ingin memperkenalkan dependensi yang tidak perlu;)
equivalent8
5

Contoh permintaan json POST sederhana bagi mereka yang membutuhkannya bahkan lebih sederhana daripada yang ditautkan oleh Tom:

require 'net/http'

uri = URI.parse("http://www.example.com/search.json")
response = Net::HTTP.post_form(uri, {"search" => "Berlin"})
Christoffer
sumber
19
Tampaknya ini berfungsi, tetapi post_form menerjemahkan parameter ke dalam sintaks? Key = value & key = value. Jika Anda ingin melakukan POST dengan tubuh permintaan diatur ke string JSON, saya rasa Anda memerlukan solusi yang berbeda.
Ben Gotow
Ini tidak berfungsi dengan json bersarang dalam. Apa pun yang melampaui tingkat pertama menjadi string.
neoneye
Tidak hanya seperti itu. Berhasil. Itu pasti sederhana. tetapi untuk hal-hal sederhana seperti contoh yang telah saya berikan berfungsi dengan baik
Christoffer
4
Ini pada dasarnya bukan permintaan JSON. Ini adalah badan dengan kode url. Tidak ada JSON. Headernya bahkan mengatakan sebanyak itu. Ini tidak akan pernah berhasil dengan contoh apa pun.
raylu
4
Jawaban ini salah. Ini adalah POST di mime / multipart, ke url yang bertuliskan "json" di dalamnya.
John Haugeland
4

Ini tahun 2020 - tidak ada yang boleh menggunakan Net::HTTPlagi dan semua jawaban sepertinya mengatakan demikian, gunakan permata yang lebih tinggi seperti Faraday - Github


Yang mengatakan, yang ingin saya lakukan adalah membungkus panggilan api HTTP, sesuatu yang disebut seperti

rv = Transporter::FaradayHttp[url, options]

karena ini memungkinkan saya untuk memalsukan panggilan HTTP tanpa ketergantungan tambahan, yaitu:

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

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

Dimana si penipu terlihat seperti ini

Saya tahu ada kerangka kerja HTTP mocking / stubbing, tetapi setidaknya ketika saya meneliti terakhir kali mereka tidak mengizinkan saya untuk memvalidasi permintaan secara efisien dan mereka hanya untuk HTTP, bukan misalnya untuk pertukaran TCP mentah, sistem ini memungkinkan saya untuk memiliki kerangka kerja terpadu untuk semua komunikasi API.


Dengan asumsi Anda hanya ingin cepat & kotor mengonversi hash ke json, kirim json ke host jarak jauh untuk menguji API dan mengurai respons ke ruby, ini mungkin cara tercepat tanpa melibatkan permata tambahan:

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

Mudah-mudahan ini tidak perlu dikatakan lagi, tapi jangan gunakan ini dalam produksi.

bbozo.dll
sumber
Anda tidak dapat melakukan ini menggunakan otentikasi NTLM. Jadi Net :: HTTP masih satu-satunya yang memiliki perpustakaan yang mendukungnya.
Rhuan
3
Tidak setuju dengan pernyataan 'tidak ada yang harus menggunakan Net::HTTP'
JellicleCat
1
Tidak disukai karena nobody should be using Net::HTTP any more@bbozo
Patricio Sard
3

Ini berfungsi pada ruby ​​2.4 HTTPS Post dengan objek JSON dan isi respons ditulis.

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
sumber
2

Saya suka klien permintaan http ringan ini yang disebut `unirest '

gem install unirest

pemakaian:

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
sumber
1

Api net / http mungkin sulit digunakan.

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
sumber
Kode ini tidak berfungsi. Anda perlu menginisialisasi Net :: HTTP dengan #mulai seperti ini:Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |client|
Tyler
Bekerja dengan ruby ​​2.3.7p456 (revisi 2018-03-28 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
sumber