Ruby ส่งคำขอ JSON


86

ฉันจะส่งคำขอ JSON ใน Ruby ได้อย่างไร ฉันมีวัตถุ JSON .sendแต่ฉันไม่คิดว่าฉันจะทำ จาวาสคริปต์ต้องส่งแบบฟอร์มหรือไม่

หรือใช้คลาส net / http ใน Ruby ได้หรือไม่?

ด้วย header - content type = json และ body วัตถุ json?

คำตอบ:


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
ฉันชอบคำแนะนำของคุณในการใช้ URI เพื่อจัดการชื่อโฮสต์และพอร์ตซึ่งเป็นเรื่องที่ค่อนข้างน่าเบื่อ แต่คุณลืมตั้งค่า uri.path ใน Post.new (... ):req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
ArnauOrriols

1
การตอบสนองที่เรียบง่ายและสะอาดที่สุด นี่มันเยี่ยมมาก
joelc

http.request(req).read_bodyเพื่ออ่านเนื้อหาตอบสนอง เยี่ยมมาก!
iGian

1
ฉันค่อนข้างมั่นใจว่ามันเปลี่ยนไปใน 2.4.1 แต่พระเจ้าของฉัน ไวยากรณ์นั้นเป็นขั้นต้น รู้ว่ามันมี URI จาก Post.new () ดังนั้นทำไมคุณต้องส่งค่าซ้ำแยกใน start () ขั้นต้น ไม่น่าแปลกใจที่มีแพ็คเกจอื่น ๆ อีกมากมายในทับทิมที่จัดการกับ 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

ข้อยกเว้นใดที่ควรระบุ
Mio

7
สำหรับคำขอ https ให้เพิ่ม: http.use_ssl = true
ทักษะ M2

16

HTTPartyทำให้สิ่งนี้ง่ายขึ้นเล็กน้อยที่ฉันคิด (และทำงานร่วมกับ json ที่ซ้อนกัน ฯลฯ ซึ่งดูเหมือนจะไม่ทำงานในตัวอย่างอื่น ๆ ที่ฉันเคยเห็น

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

6

ตัวอย่างชีวิตจริงแจ้งAirbrake API เกี่ยวกับการปรับใช้ใหม่ผ่าน 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)

หมายเหตุ:

ในกรณีที่คุณทำการพิสูจน์ตัวตนผ่าน Authorization header set header req['Authorization'] = "Token xxxxxxxxxxxx" หรือhttp://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html


... แต่จริงๆแล้วมันเจ๋งและทั้งหมดนี้ แต่ในชีวิตจริงฉันจะใช้ HTTParty stackoverflow.com/a/14491995/473040 :) ... โดยเฉพาะอย่างยิ่งถ้าคุณกำลังจัดการกับ https
เทียบเท่า 8

การกำหนดให้ uri ไม่มีประโยชน์เนื่องจาก net / http
noraj

@ equivalent8: "ในชีวิตจริงฉันแค่ใช้ HTTParty" นั่นคือเว้นแต่คุณจะสร้างอัญมณีที่ไม่ติดมันหรือไม่ต้องการการพึ่งพาอื่น :)
Sergio Tulentsev

@SergioTulentsev เห็นด้วย ... เว้นแต่คุณจะสร้าง gem / lib (หรือ microservice ที่ใช้ Ruby) ซึ่งคุณไม่ต้องการแนะนำการอ้างอิงที่ไม่จำเป็น;)
เทียบเท่า

5

ตัวอย่างคำขอ json POST ง่ายๆสำหรับผู้ที่ต้องการมันง่ายกว่าที่ Tom เชื่อมโยงไป

require 'net/http'

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

19
ดูเหมือนว่าจะใช้งานได้ แต่ post_form แปลพารามิเตอร์เป็นไวยากรณ์? key = value & key = value หากคุณต้องการทำ POST โดยตั้งค่าเนื้อหาคำขอเป็นสตริง JSON ฉันคิดว่าคุณต้องการวิธีแก้ไขปัญหาอื่น
Ben Gotow

สิ่งนี้ใช้ไม่ได้กับ json ที่ซ้อนกันอย่างลึกซึ้ง สิ่งที่เกินระดับแรกจะกลายเป็นสตริง
neoneye

Doens ไม่เพียง แต่ดูเหมือน มันได้ผล. มันง่ายแน่นอน แต่สำหรับสิ่งง่ายๆเช่นตัวอย่างที่ฉันให้มามันก็ใช้ได้ดี
Christoffer

4
โดยพื้นฐานแล้วนี่ไม่ใช่คำขอ JSON นี่คือร่างกายที่เข้ารหัส ไม่มี JSON ส่วนหัวยังบอกได้มาก สิ่งนี้ใช้ไม่ได้กับตัวอย่างใด ๆ เลยทีเดียว
raylu

4
คำตอบนี้ไม่ถูกต้อง มันเป็น POST ในละครใบ้ / หลายส่วนไปยัง url ที่มีข้อความ "json" อยู่ในนั้น
John Haugeland

4

มันเป็นปี 2020 - ไม่มีใครควรใช้Net::HTTPอีกต่อไปและคำตอบทั้งหมดดูเหมือนจะพูดอย่างนั้นให้ใช้อัญมณีระดับสูงเช่น Faraday - Github


ที่กล่าวว่าสิ่งที่ฉันชอบทำคือ wrapper รอบ ๆ การเรียก HTTP api สิ่งที่เรียกว่า like

rv = Transporter::FaradayHttp[url, options]

เนื่องจากสิ่งนี้ทำให้ฉันสามารถโทร HTTP ปลอมโดยไม่มีการอ้างอิงเพิ่มเติมเช่น:

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

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

ที่ faker มีลักษณะเช่นนี้

ฉันรู้ว่ามีเฟรมเวิร์กการเยาะเย้ย / การตัด HTTP แต่อย่างน้อยเมื่อฉันค้นคว้าครั้งสุดท้ายพวกเขาไม่อนุญาตให้ฉันตรวจสอบคำขออย่างมีประสิทธิภาพและเป็นเพียง HTTP เท่านั้นไม่ใช่ตัวอย่างสำหรับการแลกเปลี่ยน TCP ดิบระบบนี้ช่วยให้ฉันมี กรอบงานที่เป็นหนึ่งเดียวสำหรับการสื่อสาร API ทั้งหมด


สมมติว่าคุณต้องการแปลงแฮชเป็น json อย่างรวดเร็วและสกปรกส่ง json ไปยังโฮสต์ระยะไกลเพื่อทดสอบ API และแยกวิเคราะห์การตอบสนองต่อทับทิมนี่อาจเป็นวิธีที่เร็วที่สุดโดยไม่ต้องเกี่ยวข้องกับอัญมณีเพิ่มเติม:

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

หวังว่าสิ่งนี้จะเป็นไปโดยไม่พูด แต่อย่าใช้สิ่งนี้ในการผลิต


คุณไม่สามารถทำได้โดยใช้การรับรองความถูกต้อง NTLM ดังนั้น Net :: HTTP จึงยังคงเป็นเพียงไลบรารีที่รองรับ
Rhuan

3
ไม่เห็นด้วยกับNet::HTTPคำยืนยันว่า 'ไม่มีใครควรใช้'
JellicleCat

1
โหวตลงเพราะnobody should be using Net::HTTP any more@bbozo
Patricio Sard

3

สิ่งนี้ใช้ได้กับ Ruby 2.4 HTTPS Post พร้อมออบเจ็กต์ JSON และเนื้อหาการตอบสนองที่เขียนออกมา

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

ฉันชอบไคลเอนต์คำขอ http น้ำหนักเบาที่เรียกว่า `` unirest ''

gem install unirest

การใช้งาน:

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

net / http api สามารถใช้งานได้ยาก

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

รหัสนี้ใช้ไม่ได้ คุณต้องเริ่มต้น Net :: HTTP ด้วย #start ดังนี้:Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |client|
Tyler

ทำงานร่วมกับทับทิม 2.3.7p456 (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'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.