Skip to content

Latest commit

 

History

History
143 lines (106 loc) · 4.63 KB

using-callbacks.md

File metadata and controls

143 lines (106 loc) · 4.63 KB

Flexirest: Using callbacks

You can use callbacks to alter get/post parameters, the URL or set the post body (doing so overrides normal parameter insertion in to the body) before a request or to adjust the response after a request. This can either be a block or a named method (like ActionController's before_callback/before_action methods).

The callback is passed the name of the method (e.g. :save) and an object (a request object for before_request and a response object for after_request). The request object has four public attributes post_params (a Hash of the POST parameters), get_params (a Hash of the GET parameters), headers and url (a String containing the full URL without GET parameters appended).

require 'secure_random'

class Person < Flexirest::Base
  before_request do |name, request|
    if request.post? || name == :save
      id = request.post_params.delete(:id)
      request.get_params[:id] = id
    end
  end

  before_request :replace_token_in_url

  before_request :add_authentication_details

  before_request :replace_body

  before_request :override_default_content_type

  private

  def replace_token_in_url(name, request)
    request.url.gsub!("#token", SecureRandom.hex)
  end

  def add_authentication_details(name, request)
    request.headers["X-Custom-Authentication-Token"] = ENV["AUTH_TOKEN"]
  end

  def replace_body(name, request)
    if name == :create
      request.body = request.post_params.to_json
    end
  end

  def override_default_content_type(name, request)
    if name == :save
      request.headers["Content-Type"] = "application/json"
    end
  end
end

If you need to, you can create a custom parent class with a before_request callback and all children will inherit this callback.

class MyProject::Base < Flexirest::Base
  before_request do |name, request|
    request.get_params[:api_key] = "1234567890-1234567890"
  end
end

class Person < MyProject::Base
  # No need to declare a before_request for :api_key, already defined by the parent
end

After callbacks work in exactly the same way:

class Person < Flexirest::Base
  get :all, "/people"
  get :all, "/people"

  after_request :fix_empty_content
  after_request :cache_all_people

  private

  def fix_empty_content(name, response)
    if response.status == 204 && response.body.blank?
      response.body = '{"empty": true}'
    end
  end

  def cache_all_people(name, response)
    if name == :all
      response.response_headers["Expires"] = 1.hour.from_now.iso8601
    end
  end
end

Note: since v1.3.21 the empty response trick above isn't necessary, empty responses for 204 are accepted normally (the method returns true), but this is here to show an example of an after_request callback adjusting the body. The cache_all_people example shows how to cache a response even if the server doesn't send the correct headers.

If you manually set caching responses like the above, you may want to invalidate that cache when you make a create, update, delete etc request for the resource, for example:

class Animal < Flexirest::Base
  after_request :cache
  before_request :cache_cleanup

  get :get, '/animals/:id'
  post :update, '/animals/:id'
  delete :delete, '/animals/:id'

  def cache_cleanup(name, request)
    if name == :update || name == :delete
      Flexirest::Logger.info("  \033[1;4;32m#{Flexirest.name}\033[0m Invalidating cache for #{self.class.name} #{request.url}")
      Rails.cache.delete("#{self.class.name}:#{request.url}")
    end
  end

  def cache(name, response)
    if name == :get
      response.response_headers["Expires"] = 1.hour.from_now.iso8601
    end
  end
end

If you want to trap an error in an after_request callback and retry the request, this can be done - but retries will only happen once for each request (so we'd recommend checking all conditions in a single after_request and then retrying after fixing them all). You achieve this by raising a Flexirest::CallbackRetryRequestException from the callback.

class Person < Flexirest::Base
  get :all, "/people"

  after_request :fix_invalid_request

  private

  def fix_invalid_request(name, response)
    if response.status == 401
      # Do something to fix the state of caches/variables used in the
      # before_request, etc
      raise Flexirest::CallbackRetryRequestException.new
    end
  end
end

If you want to cancel the request from within a callback, you can simply return false and the mapped method result will also be false, however, we would normally advocate raising an exception so the reason for the callback failure is more explicit.


< Caching | Lazy loading >