Ruby (Net::HTTP)
Net::HTTP idioms, persistent connections, and consuming the JSON response.
Ruby shipsNet::HTTP in the standard library, which is enough to call any JSON API without adding a gem. For larger apps,HTTParty orFaraday can clean up the boilerplate. This guide focuses onNet::HTTP because it is always available, then shows the same calls inHTTParty for contrast.
Setup
Open one persistent connection if you are calling the API repeatedly. TheNet::HTTP.start block keeps the TCP+TLS connection open for every call inside it, so a loop of 100 fetches becomes 100x cheaper.
require "net/http"
require "json"
require "uri"
API = "https://gorest.co.in/public/v2"
TOKEN = ENV.fetch("GOREST_TOKEN")
BASE = URI(API)
HTTP = Net::HTTP.new(BASE.host, BASE.port)
HTTP.use_ssl = true
HTTP.start # open the TCP+TLS connection once and reuse it
Send the bearer token
Add the token to every request via a small helper. Nothing magical; it just stamps the same headers each time and parses the JSON response.
HEADERS = {
"Authorization" => "Bearer #{TOKEN}",
"Accept" => "application/json",
"Content-Type" => "application/json"
}.freeze
def call(req)
HEADERS.each { |k, v| req[k] = v }
res = HTTP.request(req)
[res.code.to_i, res.body && !res.body.empty? ? JSON.parse(res.body) : nil, res]
end
List users
def list_users(status: "active", page: 1)
uri = URI("#{API}/users")
uri.query = URI.encode_www_form(status: status, page: page)
code, body, _ = call(Net::HTTP::Get.new(uri))
raise "GET /users -> #{code}" unless code == 200
body
end
list_users(status: "active").first(3)
Fetch a single user
def get_user(id)
code, body, _ = call(Net::HTTP::Get.new(URI("#{API}/users/#{id}")))
return nil if code == 404
raise "GET /users/#{id} -> #{code}" unless code == 200
body
end
Create, update, delete
Build the request, setbody to the JSON payload, and letcall handle the rest. The fields the API accepts on a user arename,email,gender, andstatus.
# Create
req = Net::HTTP::Post.new(URI("#{API}/users"))
req.body = JSON.dump(name: "Tenali Ramakrishna",
email: "tenali-#{Time.now.to_i}@example.com",
gender: "male",
status: "active")
code, created, _ = call(req)
raise "Create failed: #{code}" unless code == 201
# Partial update
req = Net::HTTP::Patch.new(URI("#{API}/users/#{created['id']}"))
req.body = JSON.dump(status: "inactive")
call(req)
# Delete
call(Net::HTTP::Delete.new(URI("#{API}/users/#{created['id']}")))
A 422 means validation failed. The body is an array of{ "field" => "...", "message" => "..." } hashes; surface them to your form layer:
req = Net::HTTP::Post.new(URI("#{API}/users"))
req.body = JSON.dump(name: "x")
code, errors, _ = call(req)
if code == 422
errors.each { |e| puts "#{e['field']}: #{e['message']}" }
end
Pagination
The API puts pagination metadata in response headers (X-Pagination-Total,X-Pagination-Pages,X-Pagination-Page andX-Pagination-Limit). Loop on the page count rather than guessing when to stop:
def each_user(filters = {})
return enum_for(:each_user, filters) unless block_given?
page = 1
loop do
uri = URI("#{API}/users")
uri.query = URI.encode_www_form(filters.merge(page: page))
code, batch, res = call(Net::HTTP::Get.new(uri))
raise "GET /users -> #{code}" unless code == 200
batch.each { |u| yield u }
break if page >= res["X-Pagination-Pages"].to_i
page += 1
end
end
each_user(status: "active").first(50).map { |u| u["email"] }
Retry on 429
The API rate-limits per access token. When you hit the ceiling, you get a 429 with anX-RateLimit-Reset header in seconds. Wrap requests in a small back-off helper:
def call_with_retry(req, attempts: 3)
attempts.times do
code, body, res = call(req)
return [code, body, res] unless code == 429
sleep [res["X-RateLimit-Reset"].to_i, 1].max
end
raise "Rate limited; gave up"
end
Same calls in HTTParty
If you prefer a higher-level client,HTTParty collapses every snippet above into one or two lines. It does the JSON parse and bearer header for you when you set the defaults on a class:
require "httparty"
class GoRest
include HTTParty
base_uri "https://gorest.co.in/public/v2"
headers "Authorization" => "Bearer #{ENV.fetch('GOREST_TOKEN')}",
"Content-Type" => "application/json",
"Accept" => "application/json"
def self.list_users(**query)
get("/users", query: query).parsed_response
end
def self.create_user(payload)
post("/users", body: payload.to_json).parsed_response
end
end
Tips
- Reuse one code Net::HTTP | object across calls in the same process. Re-creating it per call doubles your latency on every request.
- Pass the token via env ( code GOREST_TOKEN | ). In Rails apps, expose it through the credentials file or code Rails.application.config_for | .
Time.now.to_iis a quick way to make test emails unique without a UUID dependency.- Tests for code that calls this API: stub with WebMock or VCR rather than hitting the network. Cassettes are tiny because v2 responses do not wrap the data.
Keep going
JavaScript (Fetch API)
Browser-native fetch with async/await, bearer-token auth, error handling, and pagination.
Node.js
Server-side requests with global fetch and axios: retries, env-loaded tokens, streaming JSON.
Python (requests)
Calls with the requests library, JSON bodies, query filtering, and dataclass parsing.