12/08/2018, 14:04

Grape API endpoint

Trong việc làm API, việc dùng gem Grape khá phổ biến (https://github.com/ruby-grape/grape), hiểu rõ hơn về endpoint trong Grape sẽ làm ta chủ động hơn trong việc dùng gem này. Endpoint có thể chia là 2 loại, error endpoint và success endpoint. A. Error endpoint Đơn gỉan là endpoint trả về từ ...

Trong việc làm API, việc dùng gem Grape khá phổ biến (https://github.com/ruby-grape/grape), hiểu rõ hơn về endpoint trong Grape sẽ làm ta chủ động hơn trong việc dùng gem này.

Endpoint có thể chia là 2 loại, error endpoint và success endpoint.

A. Error endpoint

Đơn gỉan là endpoint trả về từ server để báo 1 lỗi nào đó, việc tạo error endpoint trong Grape khá đơn gỉan:

error!({error_code: Settings.http_code.code_400, reason: I18n.t("api_error.common.validation_errors")},
  Settings.http_code.code_200,
  Settings.response_headers.response_id => "TODO",
  Settings.response_headers.result_code => Settings.result_codes.failure)

Header được set ở {error_code: Settings.http_code.code_400, reason: I18n.t("api_error.common.validation_errors")}

Body được set ở Settings.http_code.code_200, Settings.response_headers.response_id => "TODO", Settings.response_headers.result_code => Settings.result_codes.failure)

Ta có thể custom key, value trong header và body dễ dàng bằng cách thay đổi các trường trong method error!.

Method error! của class Grape::Middleware::Error: (https://github.com/ruby-grape/grape/blob/master/lib/grape/middleware/error.rb#L80)

def error!(message, status = options[:default_status], headers = {}, backtrace = [])
  headers = headers.reverse_merge(Grape::Http::Headers::CONTENT_TYPE => content_type)
  rack_response(format_message(message, backtrace), status, headers)
end

Method rack_response: (https://github.com/ruby-grape/grape/blob/master/lib/grape/middleware/error.rb#L99)

def rack_response(message, status = options[:default_status], headers = { Grape::Http::Headers::CONTENT_TYPE => content_type })
  Rack::Response.new([message], status, headers).finish
end

B. Success endpoint

Set header bằng cách sau (trong trường hợp này là set default cho header nên để trong before do end):

before do
  header[Settings.response_headers.response_id] = "TODO"
  header[Settings.response_headers.result_code] = Settings.result_codes.success
end

Method set header của Grape: (https://github.com/ruby-grape/grape/blob/master/lib/grape/dsl/headers.rb)

module Grape
  module DSL
    module Headers
      def header(key = nil, val = nil)
        if key
          val ? header[key.to_s] = val : header.delete(key.to_s)
        else
          @header ||= {}
        end
      end
      alias headers header
    end
  end
end

Body của endpoint được Grape tao trong method get post put head delete options patch, ta thường hay dùng là post hoặc get:

resources :user do
  params do
    ...
  end

  post :evaluation do
    ...
  end
end

Những method này được Grape định nghĩa tại: (https://github.com/ruby-grape/grape/blob/master/lib/grape/dsl/routing.rb#L137):

%w(get post put head delete options patch).each do |meth|
  define_method meth do |*args, &block|
    options = args.extract_options!
    paths = args.first || ['/']
    route(meth.upcase, paths, options, &block)
  end
end

Tại Module Grape::SDL::Routing attr_reader :endpoints giữ values cho việc tạo endpoint, ta thấy có đoạn code route(meth.upcase, paths, options, &block), trong method routes endpoints được gán thêm values với những params được đưa vào tương ứng đoạn code trong vòng post do end mà ta thêm vào. Tại method route của Grape::SDL::Routing: (https://github.com/ruby-grape/grape/blob/master/lib/grape/dsl/routing.rb#L131)

  new_endpoint = Grape::Endpoint.new(inheritable_setting, endpoint_options, &block)
  endpoints << new_endpoint unless endpoints.any? { |e| e.equals?(new_endpoint) }

Class Grape::Endpoint được định nghĩa tại: https://github.com/ruby-grape/grape/blob/master/lib/grape/endpoint.rb.

Trên đây chỉ là sơ lược để hiểu thêm về Grape endpoint, cảm ơn và hi vọng bài viết gíup ích cho công việc của bạn.

0