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 ...
- 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
- 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!