All Projects → balvig → Spyke

balvig / Spyke

Licence: mit
Interact with REST services in an ActiveRecord-like manner

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Spyke

Networking
⚡️ Elegantly connect to a REST JSON Api. URLSession + Combine + Decodable + Generics = <3
Stars: ✭ 499 (-15.57%)
Mutual labels:  api, rest-api, rest, json
Httpie
As easy as /aitch-tee-tee-pie/ 🥧 Modern, user-friendly command-line HTTP client for the API era. JSON support, colors, sessions, downloads, plugins & more. https://twitter.com/httpie
Stars: ✭ 53,052 (+8876.65%)
Mutual labels:  api, rest-api, rest, json
Http Fake Backend
Build a fake backend by providing the content of JSON files or JavaScript objects through configurable routes.
Stars: ✭ 253 (-57.19%)
Mutual labels:  api, rest-api, rest, json
Generator Http Fake Backend
Yeoman generator for building a fake backend by providing the content of JSON files or JavaScript objects through configurable routes.
Stars: ✭ 49 (-91.71%)
Mutual labels:  api, rest-api, rest, json
Json Api Dart
JSON:API client for Dart/Flutter
Stars: ✭ 53 (-91.03%)
Mutual labels:  api, rest-api, rest, json
Grafanajsondatasource
Grafana datasource to load JSON data over your arbitrary HTTP backend
Stars: ✭ 146 (-75.3%)
Mutual labels:  api, rest-api, rest, json
Json Serverless
Transform a JSON file into a serverless REST API in AWS cloud
Stars: ✭ 108 (-81.73%)
Mutual labels:  api, rest-api, rest, json
Jsonapi Utils
Build JSON API-compliant APIs on Rails with no (or less) learning curve.
Stars: ✭ 191 (-67.68%)
Mutual labels:  api, rest, json, activerecord
Mockoon
Mockoon is the easiest and quickest way to run mock APIs locally. No remote deployment, no account required, open source.
Stars: ✭ 3,448 (+483.42%)
Mutual labels:  api, rest-api, rest
Datoji
A tiny JSON storage service. Create, Read, Update, Delete and Search JSON data.
Stars: ✭ 222 (-62.44%)
Mutual labels:  api, rest-api, json
Wp Rest Api Cache
Enable caching for WordPress REST API and increase speed of your application
Stars: ✭ 239 (-59.56%)
Mutual labels:  api, rest-api, rest
Horaires Ratp Api
Webservice pour les horaires et trafic RATP en temps réel
Stars: ✭ 232 (-60.74%)
Mutual labels:  api, rest, json
Flask Restplus
Fully featured framework for fast, easy and documented API development with Flask
Stars: ✭ 2,585 (+337.39%)
Mutual labels:  api, rest, json
Vulcain
Fast and idiomatic client-driven REST APIs.
Stars: ✭ 3,190 (+439.76%)
Mutual labels:  api, rest-api, rest
Imbo
Imbo is an image "server" that can be used to add/get/delete images using a RESTful interface.
Stars: ✭ 312 (-47.21%)
Mutual labels:  rest-api, rest, json
Kanary
A minimalist web framework for building REST APIs in Kotlin/Java.
Stars: ✭ 319 (-46.02%)
Mutual labels:  api, rest-api, rest
Bookmarks.dev
Bookmarks and Code Snippets Manager for Developers & Co
Stars: ✭ 218 (-63.11%)
Mutual labels:  api, rest-api, rest
Node Rest Client
REST API client from node.js
Stars: ✭ 365 (-38.24%)
Mutual labels:  rest-api, rest, json
Ws
⚠️ Deprecated - (in favour of Networking) ☁️ Elegantly connect to a JSON api. (Alamofire + Promises + JSON Parsing)
Stars: ✭ 352 (-40.44%)
Mutual labels:  rest-api, rest, json
Javacord
An easy to use multithreaded library for creating Discord bots in Java.
Stars: ✭ 368 (-37.73%)
Mutual labels:  api, rest-api, rest

Spyke


Interact with remote REST services in an ActiveRecord-like manner.

Gem Version


Spyke basically rips off takes inspiration 😇 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:

  • Fast handling of even large amounts of JSON
  • Proper support for scopes
  • Ability to define custom URIs for associations
  • ActiveRecord-like log output
  • Handling of API-side validations
  • Googlable name! :)

Configuration

Add this line to your application's Gemfile:

gem 'spyke'
gem 'multi_json' # or whatever is needed to parse responses

Spyke 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:

# config/initializers/spyke.rb

class JSONParser < Faraday::Response::Middleware
  def parse(body)
    json = MultiJson.load(body, symbolize_keys: true)
    {
      data: json[:result],
      metadata: json[:extra],
      errors: json[:errors]
    }
  end
end

Spyke::Base.connection = Faraday.new(url: 'http://api.com') do |c|
  c.request   :json
  c.use       JSONParser
  c.adapter   Faraday.default_adapter
end

Usage

Adding a class and inheriting from Spyke::Base will allow you to interact with the remote service:

class User < Spyke::Base
  has_many :posts
  scope :active, -> { where(active: true) }
end

User.all
# => GET http://api.com/users

User.active
# => GET http://api.com/users?active=true

User.where(age: 3).active
# => GET http://api.com/users?active=true&age=3

user = User.find(3)
# => GET http://api.com/users/3

user.posts
# => find embedded in returned data or GET http://api.com/users/3/posts

user.update(name: 'Alice')
# => PUT http://api.com/users/3 - { user: { name: 'Alice' } }

user.destroy
# => DELETE http://api.com/users/3

User.create(name: 'Bob')
# => POST http://api.com/users - { user: { name: 'Bob' } }

Custom URIs

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 < Spyke::Base
  uri 'people(/:id)' # id optional, both /people and /people/4 are valid

  has_many :posts, uri: 'posts/for_user/:user_id' # user_id is required
  has_one :image, uri: nil # only use embedded data
end

class Post < Spyke::Base
end

user = User.find(3) # => 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/4

Custom requests

Custom request methods and the with scope methods allow you to perform requests for non-REST actions:

The .with scope:

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/recent

Custom requests from instance:

Post.find(3).put(:publish) # => PUT http://api.com/posts/3/publish

Arbitrary 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

Custom primary keys can be defined with self.primary_key = :custom_key:

class User < Spyke::Base
  self.primary_key = :user_id

  # When using custom URIs the :id parameter also has to be adjusted
  uri 'people(/:user_id)'
end

API-side validations

Spyke expects errors to be formatted in the same way as the ActiveModel::Errors details hash, ie:

{ title: [{ error: 'blank'}, { error: 'too_short', count: 10 }]}

If the API you're using returns errors in a different format you can remap it in Faraday to match the above. Doing this will allow you to show errors returned from the server in forms and f.ex using @post.errors.full_messages just like ActiveRecord.

Error handling and fallbacks

Should the API fail to connect or time out, a Spyke::ConnectionError will be raised. If you need to recover gracefully from connection problems, you can either rescue that exception or use the with_fallback feature:

# API is down
Article.all # => 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"

Attributes-wrapping

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: ... }
end

Using multiple APIs

If 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
end

Log output

When 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)

Other examples

For more examples of how Spyke can be used, check out fixtures.rb and the test suite.

Contributing

If possible please take a look at the tests marked "wishlisted"! These are features/fixes I'd like to implement but haven't gotten around to doing yet :)

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].