Рубі надіслати запит JSON


86

Як надіслати запит JSON в рубіні? У мене є об'єкт JSON, але я не думаю, що можу просто зробити .send. Чи повинен я надіслати форму javascript?

Або я можу використовувати клас net / http у ruby?

З заголовком - тип вмісту = json, а тіло - об'єкт json?

Відповіді:


76
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.
Рамбатіно

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.
Skill M2

17

На мою думку, 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)

Примітки:

у випадку, якщо ви виконуєте автентифікацію за допомогою заголовка набору заголовків авторизації req['Authorization'] = "Token xxxxxxxxxxxx" або http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html


... але якщо чесно це круто і все , але в реальній живій , я б просто використовувати HTTParty stackoverflow.com/a/14491995/473040 :) ... особливо якщо ви маєте справу з HTTPS обробки
equivalent8

вимагати uri марно, оскільки це вже вимагає net / http
noraj

@ еквівалент8: "у реальному житті я б просто використовував HTTParty" - тобто, якщо ви не будуєте худий самоцвіт або іншим чином не хочете іншої залежності. :)
Серхіо Туленцев

@SergioTulentsev погоджується ... якщо ви не створюєте gem / lib (або мікросервіс на основі Ruby), де не хочете вводити непотрібні залежності;)
еквівалент

4

Простий приклад запиту json POST для тих, кому він потрібен, ще простіший, ніж той, до якого посилається Том:

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, я думаю, вам потрібно інше рішення.
Бен Готов,

Це не працює з глибоко вкладеним json. Все, що виходить за межі першого рівня, стає рядком.
неонеое

Не просто виглядає. Це працює. Це просто впевнено. але для таких простих речей, як приклад, який я наводив, це працює чудово
Christoffer

4
Це принципово не запит JSON. Це тіло, закодоване urlen. Немає JSON. Заголовок навіть говорить стільки ж. Це ніколи не працює на жодному прикладі.
raylu

4
Ця відповідь неправильна. Це POST у mime / multipart, до URL-адреси, на якій написано "json".
Джон Хаугленд,

4

Зараз 2020 рік - ніхто Net::HTTPбільше не повинен використовувати, і всі відповіді, здається, говорять так, використовуйте дорогоцінний камінь більш високого рівня, такий як Фарадей - Github


Тим не менш, я люблю робити обгортку навколо виклику HTTP api, щось, що називається як

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

Там , де обманщик виглядає як ця

Я знаю, що існують фреймворки знущань / заглушень HTTP, але принаймні, коли я минулого разу досліджував, вони не дозволяли мені ефективно перевіряти запити, і вони стосувалися лише HTTP, а не, наприклад, для необроблених обмінів TCP, ця система дозволяє мені мати уніфікована структура для всього спілкування API.


Якщо припустити, що ви просто хочете швидко і брудно перетворити хеш у json, надішліть json віддаленому хосту, щоб протестувати API та проаналізувати відповідь на ruby, це, мабуть, найшвидший спосіб без залучення додаткових дорогоцінних каменів:

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

Сподіваємось, це само собою зрозуміло, але не використовуйте це у виробництві.


2
Лол, чому всі ненависники? :) У дописі чітко зазначено, що він не призначений для виробничої або будь-якої іншої серйозної мети, але це найшвидший спосіб встановити JSON-дзвінок API, щоб побачити, як поводиться служба,
bbozo,

Ви не можете зробити це за допомогою автентифікації NTLM. Тож Net :: HTTP все ще є єдиним, хто має бібліотеку, яка його підтримує.
Руан

1
Не погоджуйтесь із Net::HTTPтвердженням "ніхто не повинен використовувати "
JellicleCat

Проголосовано проти nobody should be using Net::HTTP any more@bbozo
Патрісіо Сард

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

API / net / http може бути важким у використанні.

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|
Тайлер

Працює з ruby ​​2.3.7p456 (2018-03-28 редакція 63024) [universal.x86_64-darwin18]
Моріарті,

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'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.