Ruby client library for the Garage application API
Ruby Logos
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
gemfiles
lib
spec
.gitignore
.rspec
.travis.yml
CHANGELOG.md
Gemfile
LICENSE.txt
README.md
Rakefile
garage_client.gemspec

README.md

GarageClient Build Status

GarageClient is a simple Ruby library to provide a primitive client interface to the Garage application API.

Install

Install from rake command:

$ bundle install
$ rake install

or modify Gemfile in your application and invoke bundle install.

# Gemfile
gem "garage_client"

Usage

Here are quick examples.

Client initialization

require "garage_client"

# First, you have to create a GarageClient::Client with an access token.
# You can get `YOUR_ACCESS_TOKEN` with OAuth 2.0 flow.
client = GarageClient::Client.new(access_token: YOUR_ACCESS_TOKEN)

Read from Garage application

# GET https://garage.example.com/v1/recipes
client.get("/recipes")

# GET https://garage.example.com/v1/recipes?fields=id,name,ingredients
client.get("/recipes", fields: "id,name,ingredients")

# GET https://garage.example.com/v1/me
user = client.get("/me")

# GET https://garage.example.com/v1/users/:user_id/recipes?fields=__default__,user[id,name]
client.get("/users/#{user.id}/recipes", fields: "__default__,user[id,name]")

Write to Garage application

# POST https://garage.example.com/v1/suggestions
client.post("/suggestions", message: "suggestion message")

# POST https://garage.example.com/v1/users/:user_id/bookmark_tags with JSON {"name":"tag name"}
bookmark_tag = client.post("/users/#{user.id}/bookmark_tags", name: "tag name")

# PUT https://garage.example.com/v1/bookmark_tags/:id with JSON {"name":"new tag name"}
client.put("/bookmark_tags/#{bookmark_tag.id}", name: "new tag name")

# DELETE https://garage.example.com/v1/bookmark_tags/:id
client.delete("/bookmark_tags/#{bookmark_tag.id}")

Response

# `.get` method returns a GarageClient::Response of a resource.
user = client.get("/me")
user.id
user.url
user.name

# `.get` method also returns a GarageClient::Response of an array of resources.
# In this case, the response object can respond to `.total_count` method.
recipes = client.get("/recipes")
recipes.total_count
recipes[0].id
recipes[0].name

# While Garage application API returns all default properties, some additional properties are not included in them.
# You can specify the returned properties by `?fields=...` URI query parameters.
recipes = client.get("/recipes", fields: "__default__,user")
recipes[0].id
recipes[0].name
recipes[0].user.id
recipes[0].user.url
recipes[0].user.name

# `.post` method also returns a GarageClient::Response of the newly created resource.
suggestion = client.post("/suggestions", message: "suggestion message")
suggestion.message

Configuration

There are the following options:

  • adapter - faraday adapter for http client (default: :net_http)
  • cacher - take a cacher class in which caching logic is defined (default: nil)
  • name - Client's application name, which is embedded in User-Agent by default (default: nil. For Rails, Rails.application.class.parent_name.underscore is set by default.)
    • name must be configured globally.
  • headers - default http headers (default: { "Accept" => "application/json", "User-Agent" => "garage_client #{VERSION} #{name}" })
  • endpoint - Garage application API endpoint (default: nil)
  • path_prefix - API path prefix (default: '/v1')
  • verbose - Enable verbose http log (default: false)
  • tracing - (client instance only) Enable distributed tracing and set a logical name of the down stream service. See detail in "Tracing" section below.

You can configure the global settings:

GarageClient.configure do |c|
  c.endpoint = "http://localhost:3000"
  c.name = 'my-awesome-client'
  c.verbose = true
end

or each GarageClient::Client settings:

client = GarageClient::Client.new(
  adapter: :test,
  headers: { "Host" => "garage.example.com" },
  endpoint: "http://localhost:3000",
  path_prefix: "/v2",
  verbose: true,
)

Exceptions

GarageClient raises one of the following exceptions upon an error. Make sure to always look out for these in your code.

GarageClient::BadRequest
GarageClient::Unauthorized
GarageClient::Forbidden
GarageClient::NotFound
GarageClient::NotAcceptable
GarageClient::Conflict
GarageClient::UnsupportedMediaType
GarageClient::UnprocessableEntity
GarageClient::InternalServerError
GarageClient::ServiceUnavailable
GarageClient::GatewayTimeout

Utility

.properties returns a list of properties of the resource.

user = client.get("/me")
user.properties #=> [:id, :url, :name, :_links]

.links returns a list of link names related to the resource.

user = client.get("/me")
user.properties #=> [:self, :bookmarks, :recipes, ...]
user.links.recipes #=> "https://garage.example.com/v1/users/:user_id/recipes"

Caching

Define a cacher class with your custom caching logic to let it cache response, inheriting GarageClient::Cachers::Base. It must override read_from_cache?, written_to_cache?, key, and store to compose your caching logic.

class MyCacher < GarageClient::Cachers::Base
  private

  def read_from_cache?
    has_get_method? && has_cached_path?
  end

  def written_to_cache?
    read_from_cache?
  end

  def key
    @env[:url].to_s
  end

  def store
    Rails.cache
  end

  def options
    { expires_in: 5.minutes }
  end

  def has_get_method?
    @env[:method] == :get
  end

  def has_cached_path?
    case @env[:url].path
    when %r<^/v1/searches>
      true
    when %r<^/v1/recipes/\d+>
      true
    end
  end
end

GarageClient::Client.new(cacher: MyCacher)

Tracing

GarageClient supports distributed tracing. To enable tracing, specify tracing.tracer option for GarageClient::Client instance. Choose one of supported tracers from below. If you want to add new tracer, please give us a PR.

aws-xray

Bundle aws-xray gem in your Gemfile, then configure GarageClient::Client instance with tracing.service option:

require 'aws/xray/faraday'
GarageClient::Client.new(..., tracing: { tracer: 'aws-xray', service: 'user' })

service will be name of the sub segments.