Xây dựng API với Grape
Bài đăng này đã không được cập nhật trong 7 năm
Hệ thống bạn đang xây dựng cần viết API, bạn đang băn khoăn không biết xây dựng API như thế nào cho dễ quản lí, mang lại hiệu quả cao. Bài viết này mình xin giới thiệu Grape, 1 gem hữu hiệu để quản lí API với nhiều ưu điểm nổi bật
Grape là gì?
Theo Grape thì grape là
Grape is a REST-like API framework for Ruby. It's designed to run on Rack or complement existing web application frameworks such as Rails and Sinatra by providing a simple DSL to easily develop RESTful APIs. It has built-in support for common conventions, including multiple formats, subdomain/prefix restriction, content negotiation, versioning and much more. Grape là 1 REST-like API 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 1 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, có thể sử dụng cùng Ruby on Rails hoặc sử dụng độc lập
- Linh hoạt trong quản lí version
- Có tốc độ sử lý cao hơn so với Rails-api
Cài đặt
Để cài đặt ta thêm cài đặt bằng cách
gem install grape
Hoặc thêm vào Gemfile:
gem 'grape'
Rồi sau đó bundle install
Như vậy là đã cài gem grape thành công. Giờ chúng ta xây dựng cấu trúc file API.
Ở trong controller ta tạo 1 folder api
chuyên quản lí api của hệ thống
app
|––controllers
|––api
Xây dựng API
Grape API là ứng dụng Rack
được tạo bằng các subclass kế thừa từ Grape::API
Ta tạo 1 file base trong api
app
|––controllers
|––api
|––base.rb
Sau đó ta xây dựng base: dùng để khai báo mount
trong đó. Mount có nghĩa các chức năng, code đó đã được tồn tại trong ứng dụng Rails
module API
class Base < Grape::API
mount API::V1::Base
end
end
mount
:
mount
là từ khóa nói vs Rails app có 1 ứng dụng khác (thường là ứng dụng Rack và chính là Grape API) tồn tại.
Versioning
Grape framework cung cấp version. Nghĩa là chúng ta sẽ tổ chức API bên trong 1 phiên bản hoặc module v1. Các phiên bản trong tương lai chúng ta có thể phát triển khi ứng dụng phát triển sẽ được nested bên trong version 2, 3...
Tạo các module
Tao folder con v1
bên trong api
app
|––controllers
|––api
|––base.rb
|––v1
Với mỗi version ta cũng xây dựng 1 base riêng cho nó:
app
|––controllers
|––api
|––base.rb
|––v1
|––base.rb
base này sẽ có trách nhiệm khai báo mount của các class khác
module API
module V1
class Base < Grape::API
mount V1::Users
# mount API::V1::AnotherResource
end
end
end
Chúng ta vừa mount cho class User. Giờ chúng ta hãy xây dựng nó
Tạo users.rb
trong v1
:
app
|––controllers
|––api
|––base.rb
|––v1
|––base.rb
|––users.rb
Định nghĩa Endpoints
Giả sử ta muốn xây dựng 1 api method: GET để lấy toàn bộ danh sách User
Trong app/controllers/api/v1/users.rb
:
module API
module V1
class Users < Grape::API
include API::V1::Defaults
resource :users do
desc "Return all users"
get "", root: :users do
User.all
end
desc "Return a user"
params do
requires :id, type: String, desc: "ID of the user"
end
get ":id", root: "user" do
User.where(id: params[:user_id]).first
end
end
end
end
end
class Users bên trong function API giống như 1 controller
Đầu tiên chúng ta định nghĩa Routes : resource :users
. Sau đó lựa chọn phương thức (GET, POST..) sao cho phù hợp. Ở đây mình lấy danh sách toàn bộ users trong hệ thống và lấy thông tin của 1 user bất kì nên mình dùng method GET
Sau đó ta dùng Postman
theo địa chỉ http://localhost:3000/api/v1/users
sẽ ra danh sách toàn bộ users.
Before và After:
before
và after
callbacks được gọi theo thứ tự sau:
before
before_validation
validations
after_validation
the API call
after
Ví dụ:
module API
module V1
class Users < Grape::API
include API::V1::Defaults
before do
authenticate_user!
end
# .....
end
end
Helper
Có nhiều hàm sẽ dùng chung cho các api nên ta sẽ gom chúng vào 1 file gọi là defaults.rb
trong app/controllers/api/v1/defaults.rb
:
module API
module V1
module Defaults
extend ActiveSupport::Concern
included do
prefix "api"
version "v1", using: :path
default_format :json
format :json
formatter :json,
Grape::Formatter::ActiveModelSerializers
helpers do
def permitted_params
@permitted_params ||= declared(params,
include_missing: false)
end
def logger
Rails.logger
end
end
# check authentice_user
def authenticate_user!
uid = request.headers["Uid"]
token = request.headers["Access-Token"]
@current_user = User.find_by(uid: uid)
unless @current_user && @current_user.valid_token?(token)
api_error!("You need to log in to use the app.", "failure", 401, {})
end
end
# Hàm hiển thị errors message khi lỗi
def api_error!(message, error_code, status, header)
error!({message: message, code: error_code}, status, header)
end
# # Hàm raise errors message khi lỗi
def api_error_log(message)
@logger ||= Logger.new(ProjectLogger.log_path("project_api"))
@logger.info("=============#{Time.zone.now.to_s}==================\n")
@logger.info("#{message}\n")
end
rescue_from ActiveRecord::RecordNotFound do |e|
error_response(message: e.message, status: 404)
end
rescue_from ActiveRecord::RecordInvalid do |e|
error_response(message: e.message, status: 422)
end
rescue_from Grape::Exceptions::ValidationErrors do |e|
error_response(message: e.message, status: 400)
end
end
end
end
end
Routes
Trong config/routes.rb
ta thêm
Rails.application.routes.draw do
mount API::Base, at: "/"
end
Rspec
Để viết rspec cho api ta có thể dùng gem airborne
. Tham khảo tại Airborne
Cài đặt
:
gem install airborne
Ta thêm thư mục giống như sau:
spec
|––api
|––v1
|––users_spec
Ví dụ 1 đoạn rspec cho 1 api cập nhập user
require "rails_helper"
require "airborne"
describe "API::V1::Users" do
after(:all){I18n.locale = :ja}
describe "POST api/v1/users" do
let!(:user) do
FactoryGirl.create :user, id: 1, email: "test@gmail.com", first_name: "James",
last_name: "Bond", provider: "email"
end
context "when user update successfully" do
let(:api_response){FactoryGirl.build(:api_update_user_success_response).deep_symbolize_keys}
before do
post("/api/v1/users", {first_name: "hitorri"},
{"Accept-Language": "en", "App-Version": "knt/1.0", "Uid": user.uid, "Access-Token": user.access_token})
end
it{expect_json(api_response)}
end
end
end
Grape API
là 1 trong số công cụ đơn giản để viết API, nó mang lại hiệu quả cao nhờ cách thức viết đơn giản và hiệu suất cao.
Sự kết hợp hoàn hảo giữa gem Grape
và Airborne
sẽ giúp bạn quản lí api một cách tốt nhất
Hi vọng bài viết có thể giúp ích cho bạn khi xây dựng API!
Tham khảo: https://github.com/ruby-grape/grape https://github.com/ruby-grape/grape http://www.thegreatcodeadventure.com/making-a-rails-api-with-grap/
All rights reserved