RemoteResource

RemoteResource is a gem to use resources with REST services.

Goal of RemoteResource

To replace ActiveResource by providing a dynamic and customizable API interface for REST services.

Installation

Add this line to your application's Gemfile:

# Use this to fetch the gem from Gitlab
gem 'remote_resource', git: '[email protected]:jvanderpas/remote_resource.git'

# Use this to fetch the gem from RubyGems.org
gem 'ddy_remote_resource', require: 'remote_resource'

Usage

Simply include the RemoteResource::Base module in the class you want to enable for the REST services.

class ContactPerson
  include RemoteResource::Base

  self.site    = "https://www.myapp.com"
  self.version = '/v2'
end

Options

You can set a few options for the RemoteResource enabled class.

Base URL options (base_url)

The base_url is constructed from the .site, .version, .path_prefix, .path_postfix, .collection, .collection_prefix, and .collection_name options. The .collection_name is automatically constructed from the relative class name.

We will use the ContactPerson class for these examples, with the .collection_name of 'contact_person':

  • .site: This sets the URL which should be used to construct the base_url.
    • Example: .site = "https://www.myapp.com"
    • base_url: https://www.myapp.com/contact_person
  • .version: This sets the API version for the path, after the .site and before the .path_prefix that is used to construct the base_url.
    • Example: .version = "/api/v2"
    • base_url: https://www.myapp.com/api/v2/contact_person
  • .path_prefix: This sets the prefix for the path, after the .version and before the .collection_name that is used to construct the base_url.
    • Example: .path_prefix = "/registration"
    • base_url: https://www.myapp.com/registration/contact_person
  • .path_postfix: This sets the postfix for the path, after the .collection_name that is used to construct the base_url.
    • Example: .path_postfix = "/new"
    • base_url: https://www.myapp.com/contact_person/new
  • .collection: This toggles the pluralization of the collection_name that is used to construct the base_url.
    • Default: false
    • Example: .collection = true
    • base_url: https://www.myapp.com/contact_persons
  • .collection_prefix: This sets the prefix for the collection, before collection_name that is used to construct the base_url. The prefix variable has to be set via connection_options' key collection_options.
    • Default: ``
    • Example: .collection_prefix = "/companies/:company_id" and connection_options collection_options: { company_id: 2 }
    • base_url: https://www.myapp.com/companies/2/contact_persons
  • .collection_name: This sets the collection_name that is used to construct the base_url.
    • Example: .collection_name = "company"
    • base_url: https://www.myapp.com/company

override

To override the base_url completely, you can use the base_url option. This option should be passed into the connection_options hash when making a request:

  • base_url: This sets the base_url. note: this does not override the .content_type option
    • Example: { base_url: "https://api.foo.com/v1" }
    • base_url: https://api.foo.com/v1

Request options

Apart from the options which manipulate the base_url, there are some more:

  • .extra_headers: This sets the extra headers which are merged with the .default_headers and should be used for the request. note: you can't set the .default_headers
    • Default: .default_headers: { "Content-Type" => "application/json" }
    • Example: .extra_headers = { "X-Locale" => "en" }
    • .headers: { "Content-Type" => "application/json", "X-Locale" => "en" }
  • .content_type: This sets the content-type which should be used for the request URL. note: this is appended to the base_url
    • Default: ".json"
    • base_url: https://www.myapp.com/contact_person
    • Example: .content-type = ".json"
    • Request URL: https://www.myapp.com/contact_person.json

Body and params options

Last but not least, you can pack the request body or params in a root_element:

  • .root_element: This sets the root_element in which the request body or params should be 'packed' for the request.
    • Params: { email_address: "[email protected]", phone_number: "0031701234567" }
    • Example: .root_element = :contact_person
    • Packed params: { "contact_person" => { email_address: "[email protected]", phone_number: "0031701234567" } }

Querying

Finder methods

You can use the .find, .find_by and .all class methods:

# use the `id` as argument
ContactPerson.find(12)

# use a conditions `Hash` as argument
ContactPerson.find_by(username: 'foobar')

# just the whole collection
ContactPerson.all

To override the given options, you can pass in a connection_options hash:

connection_options: { root_element: :contact_person, headers: { "X-Locale" => "nl" } }

# use the `id` as argument
ContactPerson.find(12, connection_options)

# use a conditions `Hash` as argument
ContactPerson.find_by((username: 'foobar'), connection_options)

Persistence methods

You can use the .create class method and the #save instance method:

# .create
ContactPerson.create(username: 'aapmies', first_name: 'Mies')

# #save
contact_person = ContactPerson.new(id: 12)
contact_person.username = 'aapmies'
contact_person.save

To override the given options, you can pass in a connection_options hash:

connection_options: { root_element: :contact_person, headers: { "X-Locale" => "nl" } }

contact_person = ContactPerson.new(id: 12)
contact_person.username = 'aapmies'
contact_person.save(connection_options)

REST methods

You can use the .get, .put, .patch and .post class methods and the `

get,#put,#patchand#post` instance methods.

With a connection_options block

You can make your requests in a connection_options block. All the requests in the block will use the passed in connection_options.

ContactPerson.with_connection_options(headers: { "X-Locale" => "en" }) do
  ContactPerson.find_by(username: 'foobar')
  ContactPerson.find_by(username: 'aapmies', (content-type: '.xml'))
  ContactPerson.find_by((username: 'viking'), (headers: { "X-Locale" => "nl" }))
end

This will result in two request which use the { headers: { "X-Locale" => "en" } } as connection_options, one which will use the { headers: { "X-Locale" => "nl" } } as connection_options. And one that will append .xml to the request URL.

Responses

The response body of the request will be 'unpacked' from the root_element if necessary and parsed. The resulting Hash will be used to assign the attributes of the resource.

However if you want to access the response of the request, you can use the #_response method. This returns a RemoteResource::Response object with the #response_body and #response_code methods.

contact_person = ContactPerson.find_by((username: 'foobar'), connection_options)
contact_person._response                 #=> RemoteResource::Response
contact_person._response.response_code   #=> 200
contact_person._response.response_body   #=> '{"username":"foobar", "name":"Foo", "surname":"Bar"}'