Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
apipie with doc extracted to separate classes
# app/concerns/controllers/api_doc.rb
#
# Controller extension with common API documentation shortcuts
#
module Controllers::ApiDoc
# Apipie doesn't allow to append anything to esisting
# description. It raises an error on double definition.
#
def append_desc(desc = "")
_apipie_dsl_data[:description] << desc << "\n"
end
# Converts passed +code+ to the markdown
# by prepending 4 spaces to each line
#
# @param code [String]
# @return [String]
#
def to_markdown_code(code)
code.split("\n").map do |line|
(" " * 4) + line
end.join("\n")
end
# Includes passed list of json schemas
# to method description
#
# @example
# include_response_schema 'users.json', '_user.json'
#
# @param schemas [Array<String>]
#
def include_response_schema(*schemas)
root = Rails.root.join('spec/support/api/schemas')
_apipie_dsl_data[:description] = _apipie_dsl_data[:description].strip_heredoc
append_desc("## Response schema")
schemas.each do |relative_path|
append_desc MarkdownJsonSchema.read(relative_path)
end
end
# Exports all documentation from provided class
#
# @example
# class ProfilesController < ApplicationController
# extend Controllers::ApiDoc
# expose_doc
# # exports all docs from ProfilesDoc class
# # that must be inherired from ApplicationDoc
# end
#
# @see ApplicationDoc
#
def expose_doc(doc_name = "#{controller_path}_doc")
begin
doc_klass = doc_name.classify.constantize
doc_klass.apply(self)
rescue NameError
end
end
end
# app/docs/application_doc.rb
#
# A common class for defining API docs
#
# This class is abstract, to define your own doc
# for controller Api::ResourcesController, create a class
#
# class Api::ResourcesDoc < ApplicationDoc
# resource_description do
# # any method from Apipie
# end
#
# doc_for :action_name do
# # documentation for Api::ResourcesController#action_name
# # using Apipie methods
# end
# end
#
class ApplicationDoc
extend Controllers::ApiDoc
class << self
# Stores provided resource description
# to include it later to the controller class
#
# @param block [Proc]
#
def resource_description(&block)
@_resource_description_block = block
end
# Returns stored resource description (or empty proc)
#
# @return [Proc]
#
def resource_description_block
@_resource_description_block || proc {}
end
# Defines documentation for provided +action_name+
#
# @param action_name [#to_s] should match controller action name
# @param block [Proc] documentation for +action_name+ action
#
def doc_for(action_name, &block)
docs[action_name] = block
end
# Returns mappign action_name => documentation
#
# @return [Hash]
#
def docs
@_docs ||= {}
end
# Applies all defined DSL to provided controller class
#
# @param controller [ActionController::Base]
#
def apply(controller)
resource_description_block = self.resource_description_block
docs = self.docs
controller.class_eval do
resource_description(&resource_description_block)
docs.each do |action_name, block|
instance_eval(&block)
define_method(action_name) {}
end
end
end
end
end
# app/controllers/api/users_controller.rb
# (a simple example)
#
class Api::UsersController < Api::BaseController
extend Controllers::ApiDoc
expose_doc
end
@marlosirapuan

This comment has been minimized.

Copy link

@marlosirapuan marlosirapuan commented Feb 22, 2016

@iliabylich, thank you.. works 99%, except def_param_group. Look:

class TasksDoc < ApplicationDoc
  resource_description do
    description 'bla bla'
  end

  def_param_group :tasks do
    param :text, String, required: true
    param :duration, Integer
  end

  doc_for :show do
    api :GET, "/tasks/:id", "View task"
    param :id, Integer, required: true
  end

  doc_for :create do
    api :POST, "/tasks", "Create new task"
    # not work here
    param_group :tasks
  end
end
@barancw

This comment has been minimized.

Copy link

@barancw barancw commented Oct 28, 2016

I found a quick workaround. The def_param_group must be run inside of a doc_for block.

This will work:

class TasksDoc < ApplicationDoc
  resource_description do
    description 'bla bla'
  end

  doc_for :nothing do
    def_param_group :tasks do
      param :text, String, required: true
      param :duration, Integer
    end
  end

  doc_for :show do
    api :GET, "/tasks/:id", "View task"
    param :id, Integer, required: true
  end

  doc_for :create do
    api :POST, "/tasks", "Create new task"
    # works now
    param_group :tasks
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment