Interact with REST services in an ActiveRecord-like manner
Interact with REST services in an ActiveRecord-like manner
Spyke basically rips off takes inspiration :innocent: from Her, a gem which we sadly had to abandon as it gave us some performance problems and maintenance seemed to have gone stale.
We therefore made Spyke which adds a few fixes/features needed for our projects:
Add this line to your application's Gemfile:
gem 'spyke'
gem 'multi_json' # or whatever is needed to parse responsesSpyke uses Faraday to handle requests and expects it to parse the response body into a hash in the following format:
{ data: { id: 1, name: 'Bob' }, metadata: {}, errors: {} }So, for example for an API that returns JSON like this:
{ "result": { "id": 1, "name": "Bob" }, "extra": {}, "errors": {} }...the simplest possible configuration that could work is something like this:
…You can specify custom URIs on both the class and association level.
Set uri to nil for associations you only want to use data embedded
in the response and never call out to the API.
class User GET http://api.com/people/3
user.image # Will only use embedded data and never call out to api
user.posts # => GET http://api.com/posts/for_user/3
Post.find(4) # => GET http://api.com/posts/4Custom request methods and the with scope methods allow you to
perform requests for non-REST actions:
Post.with('posts/recent') # => GET http://api.com/posts/recent
Post.with(:recent) # => GET http://api.com/posts/recent
Post.with(:recent).where(status: 'draft') # => GET http://api.com/posts/recent?status=draft
Post.with(:recent).post # => POST http://api.com/posts/recentCustom requests from instance:
Post.find(3).put(:publish) # => PUT http://api.com/posts/3/publishArbitrary requests (returns plain Result object):
Post.request(:post, 'posts/3/log', time: '12:00')
# => POST http://api.com/posts/3/log - { time: '12:00' }Custom primary keys can be defined with self.primary_key = :custom_key:
class User Spyke::ConnectionError
Article.with_fallback.all # => []
Article.find(1) # => Spyke::ConnectionError
Article.with_fallback.find(1) # => nil
article = Article.with_fallback(Article.new(title: "Dummy")).find(1)
article.title # => "Dummy"Spyke, like Rails, by default wraps sent attributes in a root element, but this can be disabled or customized:
class Article < Spyke::Base
# Default
include_root_in_json true # { article: { title: ...} }
# Custom
include_root_in_json :post # { post: { title: ...} }
# Disabled
include_root_in_json false # { title: ... }
endIf you need to use different APIs, instead of configuring Spyke::Base
you can configure each class individually:
class Post < Spyke::Base
self.connection = Faraday.new(url: 'http://sashimi.com') do |faraday|
# middleware
end
endWhen used with Rails, Spyke will automatically output helpful ActiveRecord-like messages to the main log:
Started GET "/posts" for 127.0.0.1 at 2014-12-01 14:31:20 +0000
Processing by PostsController#index as HTML
Parameters: {}
Spyke (40.3ms) GET http://api.com/posts [200]
Completed 200 OK in 75ms (Views: 64.6ms | Spyke: 40.3ms | ActiveRecord: 0ms)For more examples of how Spyke can be used, check out fixtures.rb and the test suite.
No open issues yet, or sync has not completed.