12/08/2018, 13:03

Tìm hiểu về grape API và active model serializers

I. Các khái niệm? 1. Grape API 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 Cài đặt: Thêm dòng này vào ...

I. Các khái niệm?

1. Grape API

  • 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
  • Cài đặt:

Thêm dòng này vào Gemfile:

gem 'grape'

Sau đó chạy:

$ bundle install

2. ActiveModel Serializers

  • ActiveModelSerializers (AMS) là một gem trong rails hỗ trợ người dùng tạo ra JSON dễ dàng và đơn giản hơn. AMS thực hiện thông qua 2 thành phần: Serializers và Adapter. Serializers mô tả những thuôc tính và các mối quan hệ mà cần được chuyển đổi. Adapter mô tả cách các thuộc tính và các mối quan hệ mà cần chuyển đổi.
  • Cài đặt:

Thêm dòng này vào Gemfile

gem 'active_model_serializers'

Sau đó chạy:

$ bundle install

II. Cách sử dụng

1. Grape API

  • Tham khảo ở đây: https://viblo.asia/quynhbv_hp/posts/2p1PvQpBGldr. Bài viết trình bày rất rõ về cách sử dụng Grape API

2. ActiveModel Serializers

  • Ví dụ khi ta gọi 1 API, cụ thể ở đây là gọi api user detail (current_user):
# 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_400)
  end

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

  helpers do
    def authenticate!
      error!({content: "401, Unauthorized"}, 401) unless current_user
    end

    def current_user
      @current_user ||= User.authorize!(env)
    end
  end

  mount UsersAPI
end

#lib/api/v1/users_api.rb
class API::V1::UsersAPI < Grape::API
  resources :users do
    before do
      authenticate!
    end
    namespace :me do
      get do
        render curent_user, meta {message: "current_user's information"}
      end
    end
  end
end
  • Khi client thông qua url: http://localhost:3000/api/v1/users/me, nếu không dùng ActiveModel::Serializer cho model User thì ta sẽ nhận được rất nhiều các attributes từ current_user và tất nhiên nhiều attributes sẽ bị coi là dư thừa nếu phía client không sử dụng đến chúng. VD: user-no-ser.png

    Hình ảnh: kết quả trả về khi dùng postman gọi đến API users thông qua url: http://localhost:3000/api/v1/users/me

Và khi chúng ta dùng đến ActiveModel::Serializer

  • Bật terminal lên và cd đến thư mực chứa project, chạy:
$ rails g serializer user

ta sẽ được 1 file như thế này:

#app/serializers/user_serializer.rb
class UserSerializer < ActiveModel::Serializer
	  attributes :id
end
  • Khi tạo user_serializer.rb thì mặc định attributes trả về dạng JSON của model User chỉ có :id, giờ ta sẽ edit nó thành như thế này:
#app/serializers/user_serializer.rb
class UserSerializer < ActiveModel::Serializer
	  attributes :name, :facebook_id, :birthday, :age, :sex
end
  • Thì khi gọi api user qua url http://localhost:3000/api/v1/users/me, ta sẽ thu được như thế này: user-ser.pngHình ảnh: kết quả trả về khi dùng postman gọi đến API users thông qua url: http://localhost:3000/api/v1/users/me

=> Ta có thể thấy, các attributes không cần dùng đến hoặc bị thừa đã bị loại bỏ khỏi kết quả trả về.

Using a serializer without render

Nhiều thời điểm chúng ta cần sử dụng dữ liệu dạng JSON của 1 resource nào đó thì ta có thể dùng các cách sau:

  • 1 resource:
UserSerializer.new(@user).serializable_hash

=> ta thu được:

 => {:name=>"Phuong", :facebook_id=>"0000000000000", :birthday=>Sun, 30 Nov 1997, :age=>1, :sex=>1}
  • arrays resources:
ActiveModel::ArraySerializer.new(@users).as_json

=> ta thu được:

=> [{:name=>"Phuong", :facebook_id=>"0000000000000", :birthday=>Sun, 30 Nov 1997, :age=>1, :sex=>1}, {:name=>"Maximus Rau DVM", :facebook_id=>"0000000000000", :birthday=>Sun, 30 Nov 1997, :age=>1, :sex=>1}]
Overriding association methods
  • Nếu muốn override quan hệ nào đó, có thể viết như sau:
class UserSerializer < ActiveModel::Serializer
	  attributes :name, :facebook_id, :birthday, :age, :sex

	  has_many :battles

	  def battles
	    object.battles
	  end
end
  • Nếu muốn override 1 thuộc tính nào đó thì ta có thể viết như sau:
class UserSerializer < ActiveModel::Serializer
	    attributes :name, :facebook_id, :birthday, :age, :sex

	    has_many :battles

	    def battles
	      object.battles
	    end

	    def age
	      object.age = 18
	    end
end

III. Lời kết

  • Grape API là 1 công cụ để viết api rất đơn giản nhưng mang lại hiệu quả rất cao.
  • Active Model Serializer khi kết hợp với API thì giúp cho kết quả của trả về API được ngắn gọn dễ hiểu

IV. Tham khảo

  • https://intridea.github.io/grape/docs/
  • https://viblo.asia/quynhbv_hp/posts/2p1PvQpBGldr
  • https://github.com/rails-api/active_model_serializers
0