GithubHelp home page GithubHelp logo

cookpad / garage Goto Github PK

View Code? Open in Web Editor NEW
512.0 21.0 45.0 655 KB

Rails extension for RESTful Hypermedia API

License: MIT License

Ruby 78.23% JavaScript 16.82% CSS 1.51% HTML 1.38% Haml 1.86% Shell 0.11% Dockerfile 0.09%

garage's Introduction

Garage

Ruby Gem Version

Rails framework to add RESTful hypermedia API to your application.

Gem name has been changed!

We renamed gem name the_garage from version 2.0.0. Please update your Gemfile.

What Is It?

Garage provides a simple, Hypermedia friendly RESTful API to your Rails application using its native RESTful routes. Garage provides a descriptive way to serve your ActiveRecord models, as well as plain old Ruby objects as JSON-based resources.

Garage supports OAuth 2 authorizations via Doorkeeper (more extensions to come), and provides resource-based access controls.

Quickstart

In Gemfile:

# Notice this gem has "the_" prefix for gem name.
gem 'the_garage'

In your Rails model class:

class Employee < ActiveRecord::Base
  include Garage::Representer
  include Garage::Authorizable

  belongs_to :division
  has_many :projects
  property :id
  property :title
  property :first_name
  property :last_name

  property :division, selectable: true
  collection :projects, selectable: true

  link(:division) { division_path(division) }
  link(:projects) { employee_projects_path(self) }

  def self.build_permissions(perms, other, target)
    perms.permits! :read
  end
end

In your controller classes:

class ApplicationController < ActionController::Base
  include Garage::ControllerHelper

  # ...
end

class EmployeesController < ApplicationController
  include Garage::RestfulActions

  def require_resources
    @resources = Employee.all
  end
end

Resources are rendered with respond_with (responders gem). Additional options can be passed to respond_with by implementing respond_with_resources_options (index action) and respond_with_resource_options (show, update destroy actions).

Available options

  • :paginate - (Boolean) Enable pagination when true. Paginates with the per_page and page params
  • :per_page - (Integer) value for default number of resources per page when paginating
  • :max_per_page - (Integer) Maximum resources per page, irrespective of requested per_page
  • :hard_limit - (Integer) Limit of retrievable records when paginating. Also hides total records.
  • :distinct_by - (Symbol) Specify a property to count by for total page count
  • :to_resource_options - (Hash) Options to pass as argument to to_resource(options)

Create decorator for your AR models

With not small application, you may add a presentation layer to build API responses. Define a decorator class with Resource suffix and define #to_resource in your AR model.

class User < ActiveRecord::Base
  def to_resource
    UserResource.new(self)
  end
end

class UserResource
  include Garage::Representer
  include Garage::Authorizable

  property :id
  property :name
  property :email

  delegate :id, :name, :email, to: :@model

  def initialize(model)
    @model = model
  end
end

Advanced Configurations

In config/initializers/garage.rb:

Garage.configure {}

# Optional
Rails.application.config.to_prepare do
  Garage::TokenScope.configure do
    register :public, desc: "accessing publicly available data" do
      access :read, Recipe
    end

    register :read_post, desc: "reading blog post" do
      access :read, Post
    end
  end
end

# If you want to use different authentication/authorization logic.
Garage.configuration.strategy = Garage::Strategy::AuthServer

The following authentication strategies are available.

  • Garage::Strategy::NoAuthentication - Does not authenticate request and does not verify permission and access on resource operation. For non-public, internal-use Garage application.
  • Garage::Strategy::Test - Trust request thoroughly, and build access token from request headers. For testing or prototyping.
  • Garage::Strategy::Doorkeeper - Authenticate request with doorkeeper gem. To use this strategy, bundle garage-doorkeeper gem.
  • Garage::Strategy::AuthServer - Delegate authentication to OAuth server. This auth strategy has configurations.

Delegate Authentication/Authorization to your OAuth server

To delegate auth to your OAuth server, use Garage::Strategy::AuthServer strategy. Then configure auth server strategy:

  • Garage.configuration.auth_server_url - A full url of your OAuth server's access token validation endpoint. i.e. https://example.com/token.
  • Garage.configuration.auth_server_host - A host header value to request to your OAuth server. Can be empty.
  • Garage.configuration.auth_server_timeout - A read timeout second. Default is 1 second.

The OAuth server must response a json with following structure.

  • token (string, null) - OAuth access token value.
  • token_type (string) - OAuth access token value. i.e. bearer type.
  • scope (string) - OAuth scopes separated by spaces. i.e. public read_user.
  • application_id (integer) - OAuth application id of the access token.
  • resource_owner_id (integer, null) - Resource owner id of the access token.
  • expired_at (string, null) - Expire datetime with string representation.
  • revoked_at (string, null) - Revoked datetime with string representation.

When requested access token is invalid, OAuth server must response 401.

Customize Authentication/Authorization

Garage supports customizable Authentication/Authorization strategy. The Strategy has some conventions to follow.

  • Offer OAuth access token via access_token method. With no access token case (does not authenticate request) access_token should return nil.
  • Register verify_auth hook as before filter in included block if authenticate request. Or register custom authentication hook. The custom authentication hook should response unauthorized using unauthorized_render_options when fails to authenticate a request.
  • Offer whether verify permission and access in RestfulActions via verify_permission method. Return true to verify them.
module MyStrategy
  extend ActiveSupport::Concern

  included do
    # Register verify_auth hook if you want to authenticate request.
    before_action :verify_auth
  end

  def access_token
    # Fetch some `attributes` from DB or auth server API using request.
    # Then returns an AccessToken with caching.
    @access_token ||= Garage::Strategy::AccessToken.new(attributes)
  end

  # Whether verify permission and access in `RestfulActions`.
  def verify_permission?
    true
  end
end

Distributed tracing

In case you use auth-server strategy, you can setup distributed tracing for the service communication between garage application and auth server. Currently, we support following tracers:

  • aws-xray using aws-xray gem.
    • Bundle aws-xray gem in your application.
    • Configure service option for a logical service name of the auth server.
# e.g. aws-xray tracer
require 'aws/xray/hooks/net_http'
Garage::Tracer::AwsXrayTracer.service = 'your-auth-server-name'
Garage.configuration.tracer = Garage::Tracer::AwsXrayTracer

Development

See DEVELOPMENT.md.

Authors

  • Tatsuhiko Miyagawa
  • Taiki Ono
  • Yusuke Mito
  • Ryo Nakamura

Inspired By

garage's People

Contributors

adorechic avatar amatsuda avatar blueplanet avatar creasty avatar eagletmt avatar eisuke avatar fortissimo1997 avatar hokaccha avatar hotchpotch avatar iguchi1124 avatar k0kubun avatar kaorimatz avatar kenchan0130 avatar luvtechno avatar makimoto avatar miyagawa avatar mtgto avatar osyoyu avatar pocke avatar r7kamura avatar taiki45 avatar takashi avatar uasi avatar y-yagi avatar yasaichi avatar ykzts avatar yoshiori avatar yui-knk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

garage's Issues

How to add extra actions?

I want to add extra actions(except :index, :create, :show, :update, :destroy), when used garage in my project, something like "/v1/users/get_names".

How to do that?

Broken with Hashie >= 3.0.0

Hashie >= 3.0.0 Mash::respond_to? always returns true when given method name ending with "!", "?", "_", "=".
Ref: hashie/hashie@5ac8516#diff-167a475bc5a73269819928a9da362073R190

It breaks this garage's code:
https://github.com/cookpad/garage/blob/master/lib/garage/representer.rb#L159

Garage assumes instance of Hashie::Mash to be a instance including Garage::Representer.
As a result of it, it fails at here with a message "NoMethodError: undefined method `params' for Hashie::Mash:Class ".

I suggest specifying Hashie < 3.0.0 in gemspec.

doorkeeper dependency

I read @taiki45's this post and the post describes about doorkeeper dependency as following.

Doorkeeper は Rails アプリケーションに OAuth 2 provider の機能を持たせるための gem です。Garage は Doorkeeper を用いて認可機能を提供します。

クックパッドでは複数の Garage アプリケーションが存在しているので、>Doorkeeper を使用せずに、認証認可サーバーへ認証認可を委譲するモジュールを >Garage に追加しています。このような Doorkeeper 以外の認可実装や認可を行わない実装への対応は Garage 本体へ追加予定です。

Is there any roadmap or schedules about this?

[Question] Any way to avoid to create show action for create action?

I created this controller

class UsersController < ApplicationController
  include Garage::RestfulActions

  def require_resources
    @resources = User.all
  end

  def require_resource
    @resource = User.find(params[:id])
  end

  def create_resource
    @resources.create(user_params)
  end

  private

  def user_params
    params
      .require(:user)
      .permit(:first_name, :last_name, :first_name_kana, :last_name_kana,
              :email, :password, :password_confirmation, :birthday, :sex)
  end
end

and routing

resources :users, only: [:index, :show, :create]

it works well, but if I don't want to provide and remove show action from routing, error occured like No route matches {:action=>"show", :controller=>"users", :id=>4} when i call create action. because of this line

There is any way to remove show action but using create action?

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.