/rom-http

Abstract HTTP adapter for ROM

Primary LanguageRubyMIT LicenseMIT

rom-http Join the chat at https://gitter.im/rom-rb/chat

Gem Version Build Status Dependency Status Code Climate Documentation Status

HTTP adapter for ROM

Synopsis

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

class RequestHandler
  def call(dataset)
    uri = URI(dataset.uri)
    uri.path = "/#{dataset.name}/#{dataset.path}"
    uri.query = URI.encode_www_form(dataset.params)

    http = Net::HTTP.new(uri.host, uri.port)
    request_klass = Net::HTTP.const_get(ROM::Inflector.classify(dataset.request_method))

    request = request_klass.new(uri.request_uri)
    dataset.headers.each_with_object(request) do |(header, value), request|
      request[header.to_s] = value
    end

    response = http.request(request)
  end
end

class ResponseHandler
  def call(response, dataset)
    Array([JSON.parse(response.body)]).flatten
  end
end

class Users < ROM::Relation[:http]
  dataset :users

  # You can also define a schema block
  # which will use dry-data's Dry::Data['hash']
  # coercion to pre-process your data
  schema do
    attribute 'id', 'strict.int'
    attribute 'name', 'strict.string'
    attribute 'username', 'strict.string'
    attribute 'email', 'strict.string'
    attribute 'phone', 'strict.string'
    attribute 'website', 'strict.string'
  end

  def by_id(id)
    with_path(id.to_s)
  end
end

configuration = ROM::Configuration.new(:http, {
  uri: 'http://jsonplaceholder.typicode.com',
  headers: {
    Accept: 'application/json'
  },
  request_handler: RequestHandler.new,
  response_handler: ResponseHandler.new
})
configuration.register_relation(Users)
container = ROM.container(configuration)

container.relation(:users).by_id(1).to_a
# => GET http://jsonplaceholder.typicode.com/users/1 [ Accept: application/json ]

Extending

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

module ROM
  module MyAdapter
    class Dataset < ROM::HTTP::Dataset
      default_request_handler ->(dataset) do
        uri = URI(dataset.uri)
        uri.path = "/#{dataset.name}/#{dataset.path}"
        uri.query = URI.encode_www_form(dataset.params)

        http = Net::HTTP.new(uri.host, uri.port)
        request_klass = Net::HTTP.const_get(ROM::Inflector.classify(dataset.request_method))

        request = request_klass.new(uri.request_uri)
        dataset.headers.each_with_object(request) do |(header, value), request|
          request[header.to_s] = value
        end

        response = http.request(request)
      end

      default_response_handler ->(response, dataset) do
        Array([JSON.parse(response.body)]).flatten
      end
    end

    class Gateway < ROM::HTTP::Gateway; end

    class Relation < ROM::HTTP::Relation
      adapter :my_adapter
    end

    module Commands
      class Create < ROM::HTTP::Commands::Create
        adapter :my_adapter
      end

      class Update < ROM::HTTP::Commands::Create
        adapter :my_adapter
      end

      class Delete < ROM::HTTP::Commands::Create
        adapter :my_adapter
      end
    end
  end
end

ROM.register_adapter(:my_adapter, ROM::MyAdapter)

configuration = ROM::Configuration.new(:my_adapter, {
  uri: 'http://jsonplaceholder.typicode.com',
  headers: {
    Accept: 'application/json'
  }
})

class Users < ROM::Relation[:my_adapter]
  dataset :users

  def by_id(id)
    with_path(id.to_s)
  end
end

configuration.register_relation(Users)
container = ROM.container(configuration)

container.relation(:users).by_id(1).to_a
# => GET http://jsonplaceholder.typicode.com/users/1 [ Accept: application/json ]