Skip to content

SDK Ruby

Exemplos com net/http e faraday.


Cliente com net/http

# fast_deliv_client.rb

require 'net/http'
require 'json'
require 'uri'
require 'bigdecimal'

class FastDelivClient
  BASE_URL        = "https://fast-deliv-backend.vercel.app"
  SUPABASE_URL    = ENV.fetch('SUPABASE_URL')
  SUPABASE_ANON   = ENV.fetch('SUPABASE_ANON_KEY')

  def initialize(email, password)
    @email    = email
    @password = password
    @token    = nil
    @refresh  = nil
    @expires  = Time.now - 1
  end

  # --- Auth ---

  def authenticate
    resp = post_json(
      URI("#{SUPABASE_URL}/auth/v1/token?grant_type=password"),
      { email: @email, password: @password },
      extra_headers: { 'apikey' => SUPABASE_ANON }
    )
    @token   = resp['access_token']
    @refresh = resp['refresh_token']
    @expires = Time.now + resp.fetch('expires_in', 3600).to_i - 60
  end

  def refresh_token
    resp = post_json(
      URI("#{SUPABASE_URL}/auth/v1/token?grant_type=refresh_token"),
      { refresh_token: @refresh },
      extra_headers: { 'apikey' => SUPABASE_ANON }
    )
    @token   = resp['access_token']
    @expires = Time.now + resp.fetch('expires_in', 3600).to_i - 60
  end

  def auth_headers
    authenticate if @token.nil?
    refresh_token if Time.now >= @expires
    { 'Authorization' => "Bearer #{@token}" }
  end

  # --- HTTP helpers ---

  def http_for(uri)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = uri.scheme == 'https'
    http
  end

  def post_json(uri, body, extra_headers: {})
    req = Net::HTTP::Post.new(uri)
    req['Content-Type'] = 'application/json'
    extra_headers.each { |k, v| req[k] = v }
    req.body = JSON.dump(body)
    resp = http_for(uri).request(req)
    raise "HTTP #{resp.code}: #{resp.body}" unless resp.is_a?(Net::HTTPSuccess)
    JSON.parse(resp.body)
  end

  def get(path, params: {})
    uri = URI("#{BASE_URL}#{path}")
    uri.query = URI.encode_www_form(params) unless params.empty?
    req = Net::HTTP::Get.new(uri)
    auth_headers.each { |k, v| req[k] = v }
    resp = http_for(uri).request(req)
    raise "HTTP #{resp.code}: #{resp.body}" unless resp.is_a?(Net::HTTPSuccess)
    JSON.parse(resp.body)
  end

  def post(path, body)
    uri = URI("#{BASE_URL}#{path}")
    post_json(uri, body, extra_headers: auth_headers)
  end

  def patch(path)
    uri = URI("#{BASE_URL}#{path}")
    req = Net::HTTP::Patch.new(uri)
    auth_headers.each { |k, v| req[k] = v }
    resp = http_for(uri).request(req)
    raise "HTTP #{resp.code}: #{resp.body}" unless resp.is_a?(Net::HTTPSuccess)
    JSON.parse(resp.body)
  end

  def put(path, body)
    uri = URI("#{BASE_URL}#{path}")
    req = Net::HTTP::Put.new(uri)
    req['Content-Type'] = 'application/json'
    auth_headers.each { |k, v| req[k] = v }
    req.body = JSON.dump(body)
    resp = http_for(uri).request(req)
    raise "HTTP #{resp.code}: #{resp.body}" unless resp.is_a?(Net::HTTPSuccess)
    JSON.parse(resp.body)
  end

  # --- Entregas ---

  def list_deliveries(status: nil)
    params = status ? { status: status } : {}
    get('/api/v1/deliveries', params: params)
  end

  def create_delivery(title:, origin_address:, origin_lat:, origin_lng:,
                      destination_address:, destination_lat:, destination_lng:)
    post('/api/v1/deliveries', {
      title: title,
      origin_address: origin_address,
      origin_lat: origin_lat,
      origin_lng: origin_lng,
      destination_address: destination_address,
      destination_lat: destination_lat,
      destination_lng: destination_lng
    })
  end

  def assign_delivery(id)   = patch("/api/v1/deliveries/#{id}/assign")
  def start_delivery(id)    = patch("/api/v1/deliveries/#{id}/start")
  def complete_delivery(id) = patch("/api/v1/deliveries/#{id}/complete")
  def cancel_delivery(id)   = patch("/api/v1/deliveries/#{id}/cancel")

  # --- Motoristas ---

  def list_drivers = get('/api/v1/drivers')

  # --- Carteira ---

  def get_wallet          = get('/api/v1/wallets/me')
  def get_transactions    = get('/api/v1/wallets/me/transactions')

  def withdraw(amount:, pix_key:, pix_key_type:)
    post('/api/v1/wallets/withdraw', {
      amount: amount,
      pix_key: pix_key,
      pix_key_type: pix_key_type
    })
  end

  # --- Localizacao ---

  def update_location(lat:, lng:, heading: nil)
    body = { lat: lat, lng: lng }
    body[:heading] = heading if heading
    put('/api/v1/locations/me', body)
  end

  def list_locations = get('/api/v1/locations')

  # --- Precos ---

  def get_pricing = get('/api/v1/pricing')

  def update_pricing(**attrs)
    put('/api/v1/pricing', attrs)
  end
end

Uso basico

require_relative 'fast_deliv_client'

client = FastDelivClient.new('admin@empresa.com', 'senha123')

# Listar entregas pendentes
pending = client.list_deliveries(status: 'pending')
puts "#{pending.length} entregas pendentes"

# Criar entrega
delivery = client.create_delivery(
  title: 'Entrega Setor Sul',
  origin_address: 'Rua das Flores, 100, Goiania',
  origin_lat: -16.6869,
  origin_lng: -49.2648,
  destination_address: 'Av. T-63, 800, Goiania',
  destination_lat: -16.7012,
  destination_lng: -49.2789
)
puts "Criada: #{delivery['id']}"

Versao com Faraday

# Gemfile: gem 'faraday', '~> 2.0'

require 'faraday'
require 'faraday/net_http'
require 'json'

class FastDelivFaradayClient
  BASE_URL = "https://fast-deliv-backend.vercel.app"

  def initialize(token)
    @conn = Faraday.new(url: BASE_URL) do |f|
      f.request :json
      f.response :json
      f.headers['Authorization'] = "Bearer #{token}"
      f.adapter :net_http
    end
  end

  def list_deliveries(status: nil)
    params = status ? { status: status } : {}
    @conn.get('/api/v1/deliveries', params).body
  end

  def create_delivery(payload)
    resp = @conn.post('/api/v1/deliveries', payload)
    raise "#{resp.status}: #{resp.body}" unless resp.success?
    resp.body
  end

  def cancel_delivery(id)
    resp = @conn.patch("/api/v1/deliveries/#{id}/cancel")
    resp.body
  end

  def list_drivers
    @conn.get('/api/v1/drivers').body
  end

  def get_wallet
    @conn.get('/api/v1/wallets/me').body
  end

  def get_transactions
    @conn.get('/api/v1/wallets/me/transactions').body
  end

  def get_pricing
    @conn.get('/api/v1/pricing').body
  end
end

# Uso
client = FastDelivFaradayClient.new(ENV['FAST_DELIV_TOKEN'])
puts client.list_deliveries(status: 'completed').length

Calculo de ganho do motorista

require 'bigdecimal'
require 'bigdecimal/util'

def calc_driver_earnings(distance_km, pricing)
  base     = BigDecimal(pricing['base_fare'])
  min_km   = pricing['min_km'].to_f
  per_km   = BigDecimal(pricing['price_per_km'])

  return base if distance_km <= min_km

  base + (BigDecimal(distance_km.to_s) - BigDecimal(min_km.to_s)) * per_km
end

pricing = client.get_pricing
puts "Rota 12km: R$ #{calc_driver_earnings(12, pricing)}"   # R$ 29.00
puts "Rota 3km:  R$ #{calc_driver_earnings(3,  pricing)}"   # R$ 15.00

Polling de status

def wait_for_completion(client, delivery_id, timeout: 3600)
  deadline = Time.now + timeout
  terminal = %w[completed cancelled]

  loop do
    raise "Timeout aguardando entrega #{delivery_id}" if Time.now > deadline

    deliveries = client.list_deliveries
    delivery = deliveries.find { |d| d['id'] == delivery_id }
    raise "Entrega #{delivery_id} nao encontrada" unless delivery

    status = delivery['status']
    puts "Status: #{status}"
    return delivery if terminal.include?(status)

    sleep 30
  end
end