class Apipie::Application

Attributes

resource_descriptions[R]

Public Class Methods

new() click to toggle source
Calls superclass method
# File lib/apipie/application.rb, line 19
def initialize
  super
  init_env
end

Public Instance Methods

[](resource_id, method_name = nil)
active_dsl?() click to toggle source

Is there a reason to interpret the DSL for this run? with specific setting for some environment there is no reason the dsl should be interpreted (e.g. no validations and doc from cache)

# File lib/apipie/application.rb, line 377
def active_dsl?
  Apipie.configuration.validate? || ! Apipie.configuration.use_cache? || Apipie.configuration.force_dsl?
end
add_param_group(controller, name, &block) click to toggle source
# File lib/apipie/application.rb, line 149
def add_param_group(controller, name, &block)
  key = "#{controller.name}##{name}"
  @param_groups[key] = block
end
api_controllers_paths() click to toggle source
# File lib/apipie/application.rb, line 328
def api_controllers_paths
  Dir.glob(Apipie.configuration.api_controllers_matcher)
end
available_versions() click to toggle source
# File lib/apipie/application.rb, line 24
def available_versions
  @resource_descriptions.keys.sort
end
checksum() click to toggle source
# File lib/apipie/application.rb, line 370
def checksum
  @checksum ||= compute_checksum
end
clear_cached_routes!() click to toggle source
# File lib/apipie/application.rb, line 61
def clear_cached_routes!
  @_rails_routes = nil
  @_rails_routes_by_controller_and_action = nil
end
compute_checksum() click to toggle source
# File lib/apipie/application.rb, line 354
def compute_checksum
  if Apipie.configuration.use_cache?
    file_base = File.join(Apipie.configuration.cache_dir, Apipie.configuration.doc_base_url)
    all_docs = {}
    Dir.glob(file_base + '/*.json').sort.each do |f|
      all_docs[File.basename(f, '.json')] = JSON.parse(File.read(f))
    end
  else
    load_documentation if available_versions == []
    all_docs = Apipie.available_versions.inject({}) do |all, version|
      all.update(version => Apipie.to_json(version))
    end
  end
  Digest::SHA1.hexdigest(JSON.dump(all_docs))
end
controller_versions(controller) click to toggle source

recursively searches what versions has the controller specified in resource_description? It's used to derivate the default value of versions for methods.

# File lib/apipie/application.rb, line 124
def controller_versions(controller)
  value_from_parents(controller, default: [Apipie.configuration.default_version]) do |c|
    ret = @controller_versions[c.to_s]
    ret unless ret.empty?
  end
end
define_method_description(controller, method_name, dsl_data) click to toggle source

create new method api description

# File lib/apipie/application.rb, line 73
def define_method_description(controller, method_name, dsl_data)
  return if ignored?(controller, method_name)
  ret_method_description = nil

  versions = dsl_data[:api_versions] || []
  versions = controller_versions(controller) if versions.empty?

  versions.each do |version|
    resource_id_with_version = "#{version}##{get_resource_id(controller)}"
    resource_description = get_resource_description(resource_id_with_version)

    if resource_description.nil?
      resource_description = define_resource_description(controller, version)
    end

    method_description = Apipie::MethodDescription.new(method_name, resource_description, dsl_data)

    # we create separate method description for each version in
    # case the method belongs to more versions. We return just one
    # because the version doesn't matter for the purpose it's used
    # (to wrap the original version with validators)
    ret_method_description ||= method_description
    resource_description.add_method_description(method_description)
  end

  ret_method_description
end
define_resource_description(controller, version, dsl_data = nil) click to toggle source

create new resource api description

# File lib/apipie/application.rb, line 102
def define_resource_description(controller, version, dsl_data = nil)
  return if ignored?(controller)

  resource_id = get_resource_id(controller)
  resource_description = @resource_descriptions[version][resource_id]
  if resource_description
    # we already defined the description somewhere (probably in
    # some method. Updating just meta data from dsl
    resource_description.update_from_dsl_data(dsl_data) if dsl_data
  else
    resource_description = Apipie::ResourceDescription.new(controller, resource_id, dsl_data, version)

    Apipie.debug("@resource_descriptions[#{version}][#{resource_id}] = #{resource_description}")
    @resource_descriptions[version][resource_id] ||= resource_description
  end

  return resource_description
end
get_method_description(resource_id, method_name = nil) click to toggle source

get api for given method

There are two ways how this method can be used: 1) Specify both parameters

resource_id:
    controller class - UsersController
    string with resource name (plural) and version - "v1#users"
method_name: name of the method (string or symbol)

2) Specify only first parameter:

resource_id: string containing both resource and method name joined
with '#' symbol.
- "users#create" get default version
- "v2#users#create" get specific version
# File lib/apipie/application.rb, line 177
def get_method_description(resource_id, method_name = nil)
  if resource_id.is_a?(String)
    crumbs = resource_id.split('#')
    if method_name.nil?
      method_name = crumbs.pop
    end
    resource_id = crumbs.join("#")
    resource_description = get_resource_description(resource_id)
  elsif resource_id.respond_to? :apipie_resource_descriptions
    resource_description = get_resource_description(resource_id)
  else
    raise ArgumentError.new("Resource #{resource_id} does not exists.")
  end
  resource_description&.method_description(method_name.to_sym)
end
Also aliased as: []
get_method_descriptions(resource, method) click to toggle source

get all versions of method description

# File lib/apipie/application.rb, line 232
def get_method_descriptions(resource, method)
  get_resource_descriptions(resource).map do |resource_description|
    resource_description.method_description(method.to_sym)
  end.compact
end
get_param_group(controller, name) click to toggle source
# File lib/apipie/application.rb, line 154
def get_param_group(controller, name)
  key = "#{controller.name}##{name}"
  if @param_groups.key?(key)
    return @param_groups[key]
  else
    raise "param group #{key} not defined"
  end
end
get_resource_description(resource, version = nil) click to toggle source

options:

> “users”

> “v2#users”

> V2::UsersController

# File lib/apipie/application.rb, line 198
def get_resource_description(resource, version = nil)
  if resource.is_a?(String)
    crumbs = resource.split('#')
    if crumbs.size == 2
      version = crumbs.first
    end
    version ||= Apipie.configuration.default_version
    if @resource_descriptions.key?(version)
      return @resource_descriptions[version][crumbs.last]
    end
  else
    resource_id = get_resource_id(resource)
    if version
      resource_id = "#{version}##{resource_id}"
    end

    if resource_id.nil?
      return nil
    end
    resource_description = get_resource_description(resource_id)
    if resource_description && resource_description.controller.to_s == resource.to_s
      return resource_description
    end
  end
end
get_resource_descriptions(resource) click to toggle source

get all versions of resource description

# File lib/apipie/application.rb, line 225
def get_resource_descriptions(resource)
  available_versions.map do |version|
    get_resource_description(resource, version)
  end.compact
end
get_resource_id(klass) click to toggle source
# File lib/apipie/application.rb, line 397
def get_resource_id(klass)
  if klass.class == String
    klass
  elsif @controller_to_resource_id.key?(klass)
    @controller_to_resource_id[klass]
  elsif Apipie.configuration.namespaced_resources? && klass.respond_to?(:controller_path)
    return nil if klass == ActionController::Base

    version_prefix = version_prefix(klass)
    path = klass.controller_path

    unless version_prefix == '/'
      path =
        path.gsub(version_prefix, '')
    end

    path.gsub('/', '-')
  elsif klass.respond_to?(:controller_name)
    return nil if klass == ActionController::Base
    klass.controller_name
  else
    raise "Apipie: Can not resolve resource #{klass} name."
  end
end
get_resource_name(klass) click to toggle source

@deprecated Use {#get_resource_id} instead

# File lib/apipie/application.rb, line 382
    def get_resource_name(klass)
      ActiveSupport::Deprecation.warn(
        <<~HEREDOC
          Apipie::Application.get_resource_name is deprecated.
          Use `Apipie::Application.get_resource_id instead.
        HEREDOC
      )

      get_resource_id(klass)
    end
init_env() click to toggle source

initialize variables for gathering dsl data

# File lib/apipie/application.rb, line 248
def init_env
  @resource_descriptions = ActiveSupport::HashWithIndifferentAccess.new { |h, version| h[version] = {} }
  @controller_to_resource_id = {}
  @param_groups = {}

  # what versions does the controller belong in (specified by resource_description)?
  @controller_versions = Hash.new { |h, controller| h[controller.to_s] = [] }
end
json_schema_for_method_response(version, controller_name, method_name, return_code, allow_nulls) click to toggle source
# File lib/apipie/application.rb, line 266
def json_schema_for_method_response(version, controller_name, method_name, return_code, allow_nulls)
  method = @resource_descriptions[version][controller_name].method_description(method_name)
  raise NoDocumentedMethod.new(controller_name, method_name) if method.nil?

  Apipie::SwaggerGenerator
    .json_schema_for_method_response(method, return_code, allow_nulls)
end
json_schema_for_self_describing_class(cls, allow_nulls) click to toggle source
# File lib/apipie/application.rb, line 274
def json_schema_for_self_describing_class(cls, allow_nulls)
  Apipie::SwaggerGenerator
    .json_schema_for_self_describing_class(cls, allow_nulls)
end
load_documentation() click to toggle source
# File lib/apipie/application.rb, line 347
def load_documentation
  if !@documentation_loaded || Apipie.configuration.reload_controllers?
    Apipie.reload_documentation
    @documentation_loaded = true
  end
end
locale() click to toggle source
# File lib/apipie/application.rb, line 422
def locale
  Apipie.configuration.locale&.call(nil)
end
locale=(locale) click to toggle source
# File lib/apipie/application.rb, line 426
def locale=(locale)
  Apipie.configuration.locale&.call(locale)
end
rails_routes(route_set = nil, base_url = "") click to toggle source
# File lib/apipie/application.rb, line 28
def rails_routes(route_set = nil, base_url = "")
  return @_rails_routes if route_set.nil? && @_rails_routes

  route_set ||= Rails.application.routes
  # ensure routes are loaded
  Rails.application.reload_routes! unless Rails.application.routes.routes.any?

  flattened_routes = []

  route_set.routes.each do |route|
    # route is_a ActionDispatch::Journey::Route
    # route.app is_a ActionDispatch::Routing::Mapper::Constraints
    # route.app.app is_a TestEngine::Engine
    route_app = route.app.app
    if route_app.respond_to?(:routes) && route_app.routes.is_a?(ActionDispatch::Routing::RouteSet)
      # recursively go though the mounted engines
      flattened_routes.concat(rails_routes(route_app.routes, File.join(base_url, route.path.spec.to_s)))
    else
      route.base_url = base_url
      flattened_routes << route
    end
  end

  @_rails_routes = flattened_routes
end
rails_routes_by_controller_and_action() click to toggle source
# File lib/apipie/application.rb, line 54
def rails_routes_by_controller_and_action
  @_rails_routes_by_controller_and_action = rails_routes.group_by do |route|
    requirements = route.requirements
    [requirements[:controller], requirements[:action]]
  end
end
recorded_examples() click to toggle source
# File lib/apipie/application.rb, line 257
def recorded_examples
  return @recorded_examples if @recorded_examples
  @recorded_examples = Apipie::Extractor::Writer.load_recorded_examples
end
reload_documentation() click to toggle source
# File lib/apipie/application.rb, line 332
def reload_documentation
  # don't load translated strings, we'll translate them later
  old_locale = locale
  locale = Apipie.configuration.default_locale

  rails_mark_classes_for_reload

  api_controllers_paths.each do |f|
    load_controller_from_file f
  end
  @checksum = nil if Apipie.configuration.update_checksum

  locale = old_locale
end
reload_examples() click to toggle source
# File lib/apipie/application.rb, line 262
def reload_examples
  @recorded_examples = nil
end
remove_method_description(resource, versions, method_name) click to toggle source
# File lib/apipie/application.rb, line 238
def remove_method_description(resource, versions, method_name)
  versions.each do |version|
    resource = get_resource_id(resource)
    if resource_description = get_resource_description("#{version}##{resource}")
      resource_description.remove_method_description(method_name)
    end
  end
end
routes_for_action(controller, method, args) click to toggle source
# File lib/apipie/application.rb, line 66
def routes_for_action(controller, method, args)
  routes = rails_routes_by_controller_and_action[[controller.name.underscore.chomp('_controller'), method.to_s]] || []

  Apipie.configuration.routes_formatter.format_routes(routes, args)
end
set_controller_versions(controller, versions) click to toggle source
# File lib/apipie/application.rb, line 145
def set_controller_versions(controller, versions)
  @controller_versions[controller.to_s] = versions
end
set_resource_id(controller, resource_id) click to toggle source
# File lib/apipie/application.rb, line 393
def set_resource_id(controller, resource_id)
  @controller_to_resource_id[controller] = resource_id
end
to_json(version, resource_id, method_name, lang) click to toggle source
# File lib/apipie/application.rb, line 299
def to_json(version, resource_id, method_name, lang)

  return unless valid_search_args?(version, resource_id, method_name)

  _resources = if resource_id.blank?
    # take just resources which have some methods because
    # we dont want to show eg ApplicationController as resource
    resource_descriptions[version].inject({}) do |result, (k,v)|
      result[k] = v.to_json(nil, lang) unless v._methods.blank?
      result
    end
  else
    [@resource_descriptions[version][resource_id].to_json(method_name, lang)]
  end

  url_args = Apipie.configuration.version_in_url ? version : ''

  {
    :docs => {
      :name => Apipie.configuration.app_name,
      :info => Apipie.app_info(version, lang),
      :copyright => Apipie.configuration.copyright,
      :doc_url => Apipie.full_url(url_args),
      :api_url => Apipie.api_base_url(version),
      :resources => _resources
    }
  }
end
to_swagger_json(version, resource_id, method_name, language, clear_warnings = false) click to toggle source
# File lib/apipie/application.rb, line 279
def to_swagger_json(version, resource_id, method_name, language, clear_warnings = false)
  return unless valid_search_args?(version, resource_id, method_name)

  resources =
    Apipie::Generator::Swagger::ResourceDescriptionsCollection
      .new(resource_descriptions)
      .filter(
        resource_id: resource_id,
        method_name: method_name,
        version: version
      )

  Apipie::SwaggerGenerator.generate_from_resources(
    resources,
    version: version,
    language: language,
    clear_warnings: clear_warnings
  )
end
translate(str, locale) click to toggle source
# File lib/apipie/application.rb, line 430
def translate(str, locale)
  if Apipie.configuration.translate
    Apipie.configuration.translate.call(str, locale)
  else
    str
  end
end
value_from_parents(controller, *args, default: nil) { |controller, *args| ... } click to toggle source

Recursively walks up the controller hierarchy looking for a value from the block. Stops at ActionController::Base. @param [Class] controller controller to start from @param [Array] args arguments passed to the block @param [Object] default default value to return if no value is found @param [Proc] block block to call with controller and args

# File lib/apipie/application.rb, line 138
def value_from_parents(controller, *args, default: nil, &block)
  return default if controller == ActionController::Base || controller == AbstractController::Base || controller.nil?

  thing = yield(controller, *args)
  thing || value_from_parents(controller.superclass, *args, default: default, &block)
end

Private Instance Methods

get_base_url(version) click to toggle source
# File lib/apipie/application.rb, line 461
def get_base_url(version)
  Apipie.configuration.api_base_url[version]
end
get_resource_version(resource_description) click to toggle source
# File lib/apipie/application.rb, line 465
def get_resource_version(resource_description)
  if resource_description.respond_to? :_version
    resource_description._version
  else
    Apipie.configuration.default_version
  end
end
ignored?(controller, method = nil) click to toggle source
# File lib/apipie/application.rb, line 477
def ignored?(controller, method = nil)
  ignored = Apipie.configuration.ignored
  return true if ignored.include?(controller.name)
  return true if ignored.include?("#{controller.name}##{method}")
end
load_controller_from_file(controller_file) click to toggle source
# File lib/apipie/application.rb, line 473
def load_controller_from_file(controller_file)
  require_dependency controller_file
end
rails_mark_classes_for_reload() click to toggle source

Since Rails 3.2, the classes are reloaded only on file change. We need to reload all the controller classes to rebuild the docs, therefore we just force to reload all the code. This happens only when reload_controllers is set to true and only when showing the documentation.

If cache_classes is set to false, it does nothing, as this would break loading of the controllers.

# File lib/apipie/application.rb, line 491
def rails_mark_classes_for_reload
  unless Rails.application.config.cache_classes
    clear_cached_routes!
    Rails.application.reloader.reload!
    init_env
    reload_examples
    Rails.application.reloader.prepare!
  end
end
valid_search_args?(version, resource_id, method_name) click to toggle source

Make sure that the version/resource_id/method_name are valid combination resource_id and method_name can be nil

# File lib/apipie/application.rb, line 442
def valid_search_args?(version, resource_id, method_name)
  return false unless self.resource_descriptions.key?(version)
  if resource_id
    return false unless self.resource_descriptions[version].key?(resource_id)
    if method_name
      resource_description = self.resource_descriptions[version][resource_id]
      return false unless resource_description.valid_method_name?(method_name)
    end
  end
  return true
end
version_prefix(klass) click to toggle source
# File lib/apipie/application.rb, line 454
def version_prefix(klass)
  version = controller_versions(klass).first
  base_url = get_base_url(version)
  return "/" if base_url.blank?
  base_url[1..-1] + "/"
end