RemoteResource is a gem to consume resources with REST services.
To replace ActiveResource
by providing a dynamic and customizable API interface for REST services.
Add this line to your application's Gemfile:
# Use this to fetch the gem from RubyGems.org
gem 'ddy_remote_resource', require: 'remote_resource'
Simply include the RemoteResource::Base
module in the class you want to enable for the REST services.
class Post
include RemoteResource::Base
self.site = 'https://www.example.com'
self.collection = true # This option will become default in future versions
attribute :title, String
attribute :featured, Boolean
end
To retrieve resources from the REST service, you can use the .find
, .find_by
, .all
and .where
class methods:
# provide the `id` of the resource as argument
Post.find(12) #=> GET https://www.example.com/posts/12.json
# provide the conditions as argument
Post.find_by(title: 'Our awesome post') #=> GET https://www.example.com/posts.json?title=Our+awesome+post
# no arguments required
Post.all #=> GET https://www.example.com/posts.json
# provide the conditions as argument
Post.where(ids: [10, 11, 12]) #=> GET https://www.example.com/posts.json?ids[]=10&ids[]=11&ids[]=12
To create or alter resources from the REST service, you can use the .create
and .destroy
class methods or the #save
, #update_attributes
and #destroy
instance methods:
# provide the attributes as argument
Post.create(title: 'Our awesome post', featured: true) #=> POST https://www.example.com/posts.json
# provide the attributes on the resource
# new resource
post = Post.new
post.title = 'Our awesome post'
post.featured = true
post.save #=> POST https://www.example.com/posts.json
# existing resource
post = Post.new(id: 12)
post.title = 'Our awesome post'
post.featured = true
post.save #=> PATCH https://www.example.com/posts/12.json
# provide the attributes as argument
post = Post.new(id: 12, title: 'Our post')
post.update_attributes(title: 'Our awesome post', featured: true) #=> PATCH https://www.example.com/posts/12.json
# provide the `id` of the resource as argument
Post.destroy(12) #=> DELETE https://www.example.com/posts/12.json
# provide the `id` on the resource
post = Post.new(id: 12)
post.destroy #=> DELETE https://www.example.com/posts/12.json
You can provide some options to alter the request. The options can be given as the first or second argument when making a request.
connection_options = { root_element: :data, headers: { "X-Locale" => "nl" } }
Post.find(12, connection_options)
Post.all(connection_options)
Post.create({ title:'Our awesome post', featured: true }, connection_options)
post = Post.new(id: 12)
post.title = 'Our awesome post'
post.featured = true
post.save(connection_options)
You can make custom requests by using the REST methods directly. The following REST methods are defined: the .get
, .put
, .patch
and .post
class methods or the #get
, #put
, #patch
and #post
instance methods.
Post.post(title: 'Our awesome post', featured: true) #=> RemoteResource::Response
You can provide some connection options to alter the request. The options can be defined on serveral ways:
- On the
RemoteResource
enabled class - In the
.with_connection_options
block - Directly as the first or second argument when making a request.
There are several connection options that can alter the request URL. Normally the request URL is constructed using the .site
and the relative class name of the RemoteResource
enabled class. You can find this request URL by calling .base_url
on the RemoteResource
enabled class:
Post.base_url #=> https://www.example.com/posts
We will use the Post
class for these examples:
.site
: This sets the host which should be used to construct thebase_url
.- Example:
.site = 'https://api.myapp.com'
Post.base_url #=> https://api.myapp.com/posts
- Example:
.version
: This sets the API version for the path, after the.site
and before the.path_prefix
that is used to construct thebase_url
.- Example:
.version = '/api/v2'
Post.base_url #=> https://www.example.com/api/v2/posts
- Example:
.path_prefix
: This sets the prefix for the path, after the.version
and before the.collection_name
that is used to construct thebase_url
.- Example:
.path_prefix = '/registration'
Post.base_url #=> https://www.example.com/registration/posts
- Example:
.path_postfix
: This sets the postfix for the path, after the.collection_name
that is used to construct thebase_url
.- Example:
.path_postfix = '/new'
Post.base_url #=> https://www.example.com/posts/new
- Example:
.collection
: This toggles the pluralization of thecollection_name
that is used to construct thebase_url
.- Default:
false
, but will betrue
in future versions - Example:
.collection = false
Post.base_url #=> https://www.example.com/post
- Default:
.collection_prefix
: This sets the prefix for the collection, beforecollection_name
that is used to construct thebase_url
. The prefix variable has to be set via connection_options' keycollection_options
.- Example:
.collection_prefix = '/companies/:company_id'
Post.base_url #=> https://www.example.com/companies/:company_id/posts
Post.base_url(collection_options: { company_id: 2 }) #=> https://www.example.com/companies/2/posts
- Example:
.collection_name
: This sets thecollection_name
that is used to construct thebase_url
.- Example:
.collection_name = 'company'
Post.base_url #=> https://www.example.com/company
- Example:
Apart from the options which manipulate the request URL, there are also options to alter the request:
.default_headers
: This sets the default headers.- Default:
{ "Accept" => "application/json", "User-Agent" => "RemoteResource <version>" }
- Example:
.headers = { "User-Agent" => "My App" }
{ "User-Agent" => "My App" }
- Default:
.headers
: This sets the headers which are merged with the default headers.- Default:
{ "Accept" => "application/json", "User-Agent" => "RemoteResource <version>" }
- Example:
.headers = { "X-Locale" => "en" }
{ "Accept" => "application/json", "User-Agent" => "RemoteResource <version>", "X-Locale" => "en" }
- Default:
Some API wrap the resource within a specific element, we call this element the root element. When a root element is given as option the attributes in the request body will be wrapped in the element and the attributes of the response will be unwrapped from the element.
.root_element
: This sets the element in which the body is wrapped.- Example:
.root_element = :data
{"data":{"title":"My awesome post", "featured":true}}
- Example:
You can make your requests in a .with_connection_options
block. All the requests in the block will use the passed in connection options.
Post.with_connection_options(headers: { "X-Locale" => "en" }) do
Post.find(12)
Post.where({ featured: true }, { version: '/api/v2' })
Post.all({ collection_prefix: '/companies/:company_id', collection_options: { company_id: 10 })
end
The last request and response of the resource is set on the resource. You can use this to debug your implementation.
post = Post.find(12)
post.last_request #=> RemoteResource::Request
post.last_response #=> RemoteResource::Response