class Rester::Service

Constants

BASE_MIDDLEWARE

The base set of middleware to use for every service. Middleware will be executed in the order specified.

Attributes

logger[R]

Public Class Methods

_load_resources(version_module) click to toggle source
# File lib/rester/service.rb, line 84
def _load_resources(version_module)
  version_module.constants.map { |c|
    version_module.const_get(c)
  }.select { |c|
    c.is_a?(Class) && c < Service::Resource
  }
end
_load_version_module(version) click to toggle source
# File lib/rester/service.rb, line 73
def _load_version_module(version)
  versions.include?(version.to_sym) or
    raise ArgumentError, "invalid version #{version.inspect}"

  const_get(version.to_s.upcase)
end
_middleware() click to toggle source
# File lib/rester/service.rb, line 36
def _middleware
  @__middleware ||= BASE_MIDDLEWARE.dup
end
call(env) click to toggle source

The call method needs to call the rack_call method, which adds additional rack middleware.

# File lib/rester/service.rb, line 51
def call(env)
  instance.rack_call(env)
end
instance() click to toggle source
# File lib/rester/service.rb, line 45
def instance
  @instance ||= new
end
method_missing(meth, *args, &block) click to toggle source
# File lib/rester/service.rb, line 55
def method_missing(meth, *args, &block)
  instance.public_send(meth, *args, &block)
end
resources(version_module) click to toggle source
# File lib/rester/service.rb, line 80
def resources(version_module)
  (@__resources ||= {})[version_module] ||= _load_resources(version_module)
end
service_name() click to toggle source
# File lib/rester/service.rb, line 65
def service_name
  @__name ||= (name && name.split('::').last) || 'Anonymous'
end
use(klass, *args) click to toggle source

Middleware DSL

# File lib/rester/service.rb, line 32
def use(klass, *args)
  _middleware << [klass, *args]
end
version_module(version) click to toggle source
# File lib/rester/service.rb, line 69
def version_module(version)
  (@__version_modules ||= {})[version.to_sym] ||= _load_version_module(version)
end
versions() click to toggle source
# File lib/rester/service.rb, line 59
def versions
  @__versions ||= constants.map(&:to_s).select { |c|
    c.match(/^V\d{1,3}$/)
  }.map(&:downcase).map(&:to_sym)
end

Public Instance Methods

call(env) click to toggle source

Call the service app directly.

Duplicates the instance before processing the request so individual requests can't impact each other.

# File lib/rester/service.rb, line 117
def call(env)
  dup.call!(env)
end
call!(env) click to toggle source

Process the request.

Calls methods that may modify instance variables, so the instance should be dup'd beforehand.

# File lib/rester/service.rb, line 126
def call!(env)
  _process_request(Rester.request)
end
logger=(new_logger) click to toggle source
# File lib/rester/service.rb, line 97
def logger=(new_logger)
  new_logger = Utils::LoggerWrapper.new(new_logger) if new_logger
  @_logger = new_logger
end
name() click to toggle source
# File lib/rester/service.rb, line 102
def name
  self.class.service_name
end
rack_call(env) click to toggle source

To be called by Rack. Wraps the app in middleware.

# File lib/rester/service.rb, line 108
def rack_call(env)
  _rack_app.call(env)
end

Private Instance Methods

_build_rack_app() click to toggle source
# File lib/rester/service.rb, line 136
def _build_rack_app
  Rack::Builder.new.tap { |app|
    self.class._middleware.each { |m| app.use(*m) }
    app.run self
  }.to_app
end
_call_method(request) click to toggle source

Calls the appropriate method on the appropriate Service::Resource for the request.

# File lib/rester/service.rb, line 165
def _call_method(request)
  params = request.params
  resource_obj = nil
  resource_id = nil

  request.each_resource do |name, id|
    unless resource_obj
      (resource_obj = _load_resource(request.version, name)) or
        _error!(Errors::NotFoundError)
    else
      mounted_resource = resource_obj.mounts[name] or
        _error!(Errors::NotFoundError)
      resource_obj = mounted_resource.new
    end

    params.merge!(resource_obj.id_param => id) if id
    resource_id = id
  end

  resource_obj.process(request.request_method, !!resource_id, params)
end
_error!(klass, message=nil) click to toggle source

Throws an exception (instead of raising it). This is done for performance reasons. The exception will be caught in the ErrorHandling middleware.

# File lib/rester/service.rb, line 224
def _error!(klass, message=nil)
  Errors.throw_error!(klass, message)
end
_load_resource(version, name) click to toggle source

Loads the appropriate Service::Resource for the request. This will return the class, not an instance.

# File lib/rester/service.rb, line 190
def _load_resource(version, name)
  _version_module(version).const_get(name.camelcase.singularize).new
rescue NameError
  nil
end
_prepare_response(retval) click to toggle source

Prepares the retval from a Service::Resource method to be returned to the client (i.e., validates it and dumps it as JSON).

# File lib/rester/service.rb, line 205
def _prepare_response(retval)
  unless retval.is_a?(Hash)
    _error!(Errors::ServerError, "Invalid response: #{retval.inspect}")
  end

  JSON.dump(retval)
end
_process_request(request) click to toggle source

Validates the request, calls the appropriate Service::Resource method and returns a valid Rack response.

# File lib/rester/service.rb, line 146
def _process_request(request)
  _error!(Errors::NotFoundError) unless request.valid?
  _validate_version(request)
  retval = _call_method(request)
  _response(request.post? ? 201 : 200, _prepare_response(retval))
end
_rack_app() click to toggle source
# File lib/rester/service.rb, line 132
def _rack_app
  @__rack_app ||= _build_rack_app
end
_response(status, body=nil, headers={}) click to toggle source

Returns a valid rack response.

# File lib/rester/service.rb, line 215
def _response(status, body=nil, headers={})
  body = [body].compact
  headers = headers.merge("Content-Type" => "application/json")
  Rack::Response.new(body, status, headers).finish
end
_validate_version(request) click to toggle source

Validates that the version of the request matches a defined version module. If the version is not found, it throws a NotFoundError (HTTP 404).

# File lib/rester/service.rb, line 156
def _validate_version(request)
  unless self.class.versions.include?(request.version)
    _error!(Errors::NotFoundError, request.version)
  end
end
_version_module(version) click to toggle source

Returns the module specified by the version in the request.

# File lib/rester/service.rb, line 198
def _version_module(version)
  self.class.version_module(version)
end