12/08/2018, 15:27

Tạo Rails API với gem Grape

What is Grape? Grape là một REST-like API micro-framework cho Ruby. Nó được thiết kế để chạy trên Rack hoặc bổ sung cho mô hình ứng dụng web hiện có như Rails và Sinatra bằng việc cung cấp một DSL đơn giản để dễ dàng phát triển các RESTful API. Ưu điểm của Grape: Khả năng phát triển nhanh đơn giản ...

  1. What is Grape? Grape là một REST-like API micro-framework cho Ruby. Nó được thiết kế để chạy trên Rack hoặc bổ sung cho mô hình ứng dụng web hiện có như Rails và Sinatra bằng việc cung cấp một DSL đơn giản để dễ dàng phát triển các RESTful API. Ưu điểm của Grape: Khả năng phát triển nhanh đơn giản có thể dụng cùng ruby on rails hoặc sử dụng độc lập Linh hoạt trong quản lý version(điều quan trọng đối với các api) Có tốc độ xử lý cao hơn so với rails-api Một số kết quả so sánh giữa grape-api và rails-api
  2. Setup Trong bài này, chúng ta sẽ xây dựng 1 hệ thông API đơn giản về thông tin xe hơi. Đàu tiên chạy lệnh rails new car-project để tạo dự án mới. Thêm gem "grape" vào Gemfile. Sau đó tiếp tục chạy lệnh bundle install để cập nhật gem. Tạo thư mục api trong thư mục lib mkdir lib/api Sau đó chúng ta tạo 1 module là ErrorFormatter
module ErrorFormatter
  def self.call message, _backtrace, _options, env
    {
      Settings.meta => {
        Settings.string_error => Settings.error,
        Settings.status_code => message[Settings.status_code.to_sym] || env["api.endpoint"].status,
        Settings.message => message[Settings.content.to_sym]
      }
    }.to_json
  end
end

Trong thư mục lib/api chúng ta tạo thêm thư mục v1 Tạo Controller API đầu tiên cars_api.rb

class API::V1::CarsAPI < Grape::API
  resources :cars do
    get do
      render_success 400, Settings.render_success, data: Car.highlight
    end
  end
end

Tiếp theo chúng ta sẽ tạo file lib/api/v1.rb

class API::V1 < Grape::API
  version "v1", using: :path

  rescue_from Grape::Exceptions::ValidationErrors do
    error!({status_code: Settings.http_code.code_400, content: Settings.validations_error},
      Settings.http_code.code_200)
  end

  desc "Return the current API version - V1."
  get do
    {version: "v1"}
  end

  helpers do
    def render_success status_code, message, data = {}
      {
        Settings.meta => {
          Settings.string_success => Settings.success,
          Settings.status_code => status_code,
          Settings.message => message
          }.merge(data)
      }
    end

    def render_record_not_found!
      error!({status_code: Settings.not_found, content: Settings.not_found},
        Settings.http_code.code_401)
    end

    def authenticate!
      error!({status_code: Settings.status_codes.unauthorized, content: Settings.unauthorized},
        Settings.http_code.code_200) unless current_user
      error!({status_code: Settings.status_codes.blocked_user, content: I18n.t("api.error.authenticate.blocked_user")},
        Settings.http_code.code_200) unless current_user.active?
    end

    def current_user
      @current_user ||= User.current_user headers[Settings.requests.access_token]
    end


    # def claims
    #   auth_header = request.headers['Authorization'] and
    #   token = auth_header.split(' ').last and
    #   JsonWebToken.decode(token)
    # rescue
    #   nil
    # end

    # def invalid_authentication
    #   render json: {error: t('devise.failure.unauthenticated')}, status: :unauthorized
    # end
  end

  mount CarsAPI
end

Thư vào http://localhost:3000/api/v1/cars xem:

Tất nhiên là lỗi rồi, vì chúng ta đã cấu hình quét các API controller trong lib đâu. Để thêm chúng ta sửa lại appication.rb thành:

require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Mitsubishi
  class Application < Rails::Application
    config.serve_static_assets = true
    config.assets.precompile += Ckeditor.assets
    config.assets.precompile += %w( ckeditor/* )
    config.autoload_paths += %W(#{config.root}/app/models/ckeditor)

    config.active_record.raise_in_transactional_callbacks = true

    config.autoload_paths << Rails.root.join("lib")
    config.eager_load_paths << Rails.root.join("lib")

    config.i18n.load_path += Dir["#{Rails.root.to_s}/config/locales/**/*.{rb,yml}"]
    config.autoload_paths += Dir["#{config.root}/app/models/**/"]

    Dir.glob("config/routes/*").each do |route|
      config.paths["config/routes.rb"] << Rails.root.join(route)
    end

    config.middleware.insert_before 0, "Rack::Cors" do
      allow do
        origins '*'
        resource '*', :headers => :any, :methods => [:get, :post, :delete, :put, :patch, :options, :head]
      end
    end
  end
end

Sau khi cấu hình lại, truy cập vào http://localhost:3000/api/v1 ta sẽ có kết quả sau: Như vậy, settup đã thành công. Tiếp tục chúng ta sẽ tạo model Cartegory: rails g model category name:string Sau đó tạo thêm model Car rails g model car name:string cost:integer version:float awidth:integer height:integer length:integer category:references Rồi chạy lệnh rails db:migrate

Thêm seed cho databse:

categories = ["attrage", "migrate", "outlander", "outlander sport", "pajero", "pajero sport", "triton"]
categories.each do |category|
  Category.create! name: category
end

20.times do
  Car.create! name: Faker::Name.name, cost: 1000000000, version: 2.4,
    category_id: rand(1..7)
end

Rồi chạy lệnh rails db:seed Trong car_api.rb Để get Json tất cả Car:

class API::V1::CarsAPI < Grape::API
  resources :cars do
    get do
      render_success 400, Settings.render_success, data: Car.highlight
    end
  end
end

Kết quả:

Chúc các bạn thành công!             </div>
            
            <div class=

0