Rails API with ruby - Grape

GIỚI THIỆU CHUNG

API là viết tắt của Application Programming Interface (giao diện lập trình ứng dụng). Nó là 1 giao tiếp phần mềm được dùng bởi các ứng dụng khác nhau.

Đây là xu hướng phát triển các ứng dụng có thể hoạt động trên các thiết bị khác nhau phù hợp với nhiều nhu cầu người dùng như mobile, website .... Những ứng dụng kiểu này giúp nhà phát triển tiết kiệm tài nguyên cả phần cứng lẫn phần mềm, phát triển ứng dụng linh hoạt hơn và có sự liên kết chặt chẽ giữa các bên.

Ứng với framework Ruby on Rails có rất nhiều cách để xây dựng một API hoàn chỉnh. Tuy vậy trong bài viết này xin được giới thiệu gem ruby-grape vì tính tiện dụng và sự chuyện nghiệp của nó.

CÀI ĐẶT RUBY - GRAPE

Cài đặt ruby-grape tương tự như những gem khác.

  • Thêm gem vào Gemfile:
    gem "grape"
    gem "grape-active_model_serializers"
  • Chạy lệnh bundle install

=> Có thể thấy gem sẽ tự động sinh ra một thư mục app/api tất cả code API sẽ được khai báo trong thư mục này.

VIẾT ĐẶC TẢ API

Đây là một phần rất quan trọng khi xây dựng một API hoàn chỉnh, tuy vậy nhiều lập trình viên thường lao đầu vào code ngay và bỏ qua bước này. Đây là tài liệu đặc tả API sẽ giúp người xem (ngoài lập trình viên) hiểu đc API đó phục vụ mục đích gì và cách nó hoạt động.

Không cần quá đi sâu vào chi tiết từng phần nhỏ nhặt tuy vậy tài liệu cũng nên có những phần cơ bản sau:

  • Đường URL
  • Method
  • Mục đích viết API
  • Input
  • Output (normal)
  • Putput (errors)
  • List errors number

XÂY DỰNG API WITH RUBY - GRAPE

Tiếp theo chúng ta sẽ đi xây dựng một API demo với đặc tả như sau:

  • Đường URL

      http://{servername}access_history/update
    
  • Method

      POST
    
  • Mục đích viết API

      Nhận về lịch sử login lần cuối của user.
    
  • Input

      - user_id
      - access_history
    
  • Output (normal)

      - status: true
      - number_code: 9999
    
  • Otput (errors)

      - number_code + reason
    
  • List errors number

      - 899: Không được phép là ngày trong tương lai
      - 900: Tham số truyền vào không đúng kiểu dữ liệu
      - 901: User truyền vào không tồn tại
      - 902: Access history fail.
    

1. Đường dẫn tới thư mục API

  • app/api/v1

2. Tạo ra file sau: app/api/v1/api.rb với nội dung

class API < Grape::API
  prefix "api"
  version "v1", using: :path
  mount Demo::V1::AccessHistory
end

Đây là file base của toàn bộ API có thể hiểu nó giống như file routes.rb trong Rails.

3. Tạo ra module sau: app/api/v1/validation_rescue.rb với nội dung

module ValidationRescue
  extend ActiveSupport::Concern
  SUCCESS_CODE = "9999"
  included do
    before do
      header[I18n.t("api.number_code")] = SUCCESS_CODE
    end

    rescue_from Grape::Exceptions::ValidationErrors do
      error!(Settings.validate_api_error_not_type.to_h, Settings.http_code,
        I18n.t("api.number_code") => Settings.error_number.not_type.to_s)
    end

    rescue_from APIError::Base do |e|
      case e
      when APIError::User::IdNotFound
        error!(Settings.validate_api_error_not_present.to_h, Settings.http_code,
          I18n.t("api.number_code") => Settings.error_number.not_present.to_s)
      when APIError::User::AccessHistoryFail
        error!(Settings.validate_api_error_not_date.to_h, Settings.http_code,
          I18n.t("api.number_code") => Settings.error_number.not_date.to_s)
      when APIError::User::DateFail
        error!(Settings.validate_api_error_not_tomorrow.to_h, Settings.http_code,
          I18n.t("api.number_code") => Settings.error_number.date_tomorrow.to_s)
      end
    end
  end
end

Về cơ bản module này sẽ sử dụng Grape Exceptions để bắt và định nghĩa trả về mọi lỗi có thể có.

Như trong ví dụ trên có thể thấy:

  • Grape Exceptions: APIError::Base
  • 3 class lỗi là: APIError::User::IdNotFound, APIError::User::AccessHistoryFailAPIError::User::DateFail

Tương ứng với từng lỗi sẽ đẩy ra đầu nhận errors code và reason của nó.

4. Tạo ra module sau: app/api/v1/access_history.rb với nội dung

module Demo::V1::Users
  class AccessHistory < Grape::API
    include ::ValidationRescue
    resource :users_access_history do
      desc "update access history"

      params do
        requires :user_id, type: Integer
        requires :access_history, type: DateTime
      end

      post :update do
        raise APIError::User::AccessHistoryFail unless params[:access_history].is_a?(DateTime)
        date_history = params[:access_history]
        current_date = Time.zone.now
        raise APIError::User::DateFail unless current_date > date_history
        user = Demo::User.find_by_user_id params[:user_id]
        raise APIError::User::IdNotFound unless user.present?
        user.update_attribute :access_history, params[:access_history]
      end
    end
  end
end

Đây là file chứa code xử lý chính của API. Trong đó khai báo rõ ràng:

  • Params nhận vào gồm những gì và có bắt buộc hay không? requires :user_id, type: Integer
  • Method sử dụng là gì? post :update
  • Khi nào bắt ra lỗi và kiểu dữ liệu trả ra khi API chạy tới cùng.

KẾT LUẬN => Về cơ bản Ruby-Grape đã xây dựng một bộ khung chuyên nghiệp và cực kỹ dễ hiểu cho mọi API, việc phải làm bây giờ nếu có thêm một API chỉ cần sửa trên base này là xong.

=> Những thuộc tính khác mà ruby-grape cung cấp các bạn có thể tham khảo trên trang chủ ruby-grape

=> Để test được API có rất nhiều cách và công cụ hỗ trợ, lập trình viên thường sử dụng trực tiếp đường CURL trên console tuy nhiên có một công cụ khá hoàn hảo cho công việc này là POSTMAN các bạn có thể tìm hiểu tại đây