Skip to content
18 changes: 18 additions & 0 deletions app/views/apipie/apipies/_action.md.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<%-
first_api = action[:apis].try(:first) || {}
-%>
## <%= action[:name] == "index" ? "List" : action[:name].capitalize %> [<%= [first_api[:http_method], first_api[:api_url]].join(' ') %>]
<%= first_api[:short_description] %>

+ Request (application/json)
+ Attributes
<%-
action[:params].each do |p| -%>
<%= render(:partial => "param", :locals => {:param => p, :action => action}) %>
<%-
end
-%>

<%- action[:responses].each do |r| -%>
<%= render(:partial => 'response', :locals => {:response => r, :action => action}) %>
<%- end -%>
Empty file.
5 changes: 5 additions & 0 deletions app/views/apipie/apipies/_param.md.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%-
meta = [param[:expected_type], param[:required] ? 'required' : 'optional'].compact.join(', ')
allowed_params = param[:allowed] ? ':' + param[:allowed].join(', ') : nil
-%>
- <%= ["`#{param[:full_name]}`", allowed_params, "(#{meta})", param[:description]].compact.join(' ') %>
8 changes: 8 additions & 0 deletions app/views/apipie/apipies/_resource.md.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Group <%= resource[:name].titlecase %>
<%= raw resource[:short_description] %>
<%= raw resource[:full_description] unless resource[:full_description].blank? %>
<%= render(:partial => 'headers', :locals => { headers: resource[:headers], h_level: 2 }) %>
<%- resource[:methods].each do |a| -%>
<% next if !a[:show] %>
<%= render(:partial => "action", :locals => {:action => a, :resource => resource.except(:methods)}) -%>
<%- end -%>
11 changes: 11 additions & 0 deletions app/views/apipie/apipies/_response.md.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
+ Response <%= response[:code] %> (application/vnd.api+json)

<%=
if response[:body]
begin
JSON.pretty_generate(response[:body]).gsub(/^/, ' ')
rescue JSON::GeneratorError => e
response[:body].html_safe
end
end
-%>
11 changes: 11 additions & 0 deletions app/views/apipie/apipies/static.md.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FORMAT: 1A
DOC_HOST: <%= @doc[:doc_url].html_safe %>
API_HOST: <%= @doc[:api_url].html_safe %>

# <%= @doc[:name].html_safe %>
<%= @doc[:info].html_safe %>
<%= @doc[:copyright].html_safe %>

<%- @doc[:resources].sort_by(&:first).each do |key, resource| -%>
<%= render(partial: "resource", locals: {resource: resource}) -%>
<%- end -%>
1 change: 1 addition & 0 deletions app/views/layouts/apipie/apipie.md.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= yield %>
12 changes: 10 additions & 2 deletions lib/apipie-rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
require "apipie/routing"
require "apipie/markup"
require "apipie/apipie_module"
require "apipie/dsl_definition"
require "apipie/dsl/definition"
require "apipie/configuration"
require "apipie/method_description"
require "apipie/resource_description"
require "apipie/param_description"
require "apipie/errors"
require "apipie/error_description"
require "apipie/response_description"
require "apipie/see_description"
require "apipie/validator"
require "apipie/railtie"
Expand All @@ -21,3 +21,11 @@
if Rails.version.start_with?("3.0")
warn 'Warning: apipie-rails is not going to support Rails 3.0 anymore in future versions'
end

module Apipie

def self.root
@root ||= Pathname.new(File.dirname(File.expand_path(File.dirname(__FILE__), '/../')))
end

end
2 changes: 1 addition & 1 deletion lib/apipie/client/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def substituted_url(method)
end

def transformation_hash(method)
method[:params].find_all { |p| p[:expected_type] == "hash" && !p[:params].nil? }.reduce({ }) do |h, p|
method[:params].find_all { |p| p[:expected_type] == "object" && !p[:params].nil? }.reduce({ }) do |h, p|
h.update(p[:name] => p[:params].map { |pp| pp[:name] })
end
end
Expand Down
77 changes: 77 additions & 0 deletions lib/apipie/dsl/action.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
module Apipie

# DSL is a module that provides #api, #error, #param, #error.
module DSL

module Action

def def_param_group(name, &block)
Apipie.add_param_group(self, name, &block)
end

#
# # load paths from routes and don't provide description
# api
#
def api(method, path, desc = nil, options={}) #:doc:
return unless Apipie.active_dsl?
_apipie_dsl_data[:api] = true
_apipie_dsl_data[:api_args] << [method, path, desc, options]
end

# # load paths from routes
# api! "short description",
#
def api!(desc = nil, options={}) #:doc:
return unless Apipie.active_dsl?
_apipie_dsl_data[:api] = true
_apipie_dsl_data[:api_from_routes] = { :desc => desc, :options =>options }
end

# Reference other similar method
#
# api :PUT, '/articles/:id'
# see "articles#create"
# def update; end
def see(*args)
return unless Apipie.active_dsl?
_apipie_dsl_data[:see] << args
end

# Show some example of what does the described
# method return.
def example(example) #:doc:
return unless Apipie.active_dsl?
_apipie_dsl_data[:examples] << example.strip_heredoc
end

# Determine if the method should be included
# in the documentation
def show(show)
return unless Apipie.active_dsl?
_apipie_dsl_data[:show] = show
end

# Describe whole resource
#
# Example:
# api :desc => "Show user profile", :path => "/users/", :version => '1.0 - 3.4.2012'
# param :id, Fixnum, :desc => "User ID", :required => true
# desc <<-EOS
# Long description...
# EOS
def resource_description(options = {}, &block) #:doc:
return unless Apipie.active_dsl?
raise ArgumentError, "Block expected" unless block_given?

dsl_data = Resource::Description.eval_dsl(self, &block)
versions = dsl_data[:api_versions]
@apipie_resource_descriptions = versions.map do |version|
Apipie.define_resource_description(self, version, dsl_data)
end
Apipie.set_controller_versions(self, versions)
end
end

end # module DSL
end # module Apipie
42 changes: 42 additions & 0 deletions lib/apipie/dsl/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Apipie DSL functions.
module Apipie

# DSL is a module that provides #api, #error, #param, #error.
module DSL

module Base
attr_reader :apipie_resource_descriptions, :api_params

private

def _apipie_dsl_data
@_apipie_dsl_data ||= _apipie_dsl_data_init
end

def _apipie_dsl_data_clear
@_apipie_dsl_data = nil
end

def _apipie_dsl_data_init
@_apipie_dsl_data = {
:api => false,
:api_args => [],
:api_from_routes => nil,
:responses => [],
:params => [],
:headers => [],
:resource_id => nil,
:short_description => nil,
:description => nil,
:examples => [],
:see => [],
:formats => nil,
:api_versions => [],
:meta => nil,
:show => true
}
end
end

end # module DSL
end # module Apipie
170 changes: 170 additions & 0 deletions lib/apipie/dsl/common.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
module Apipie

# DSL is a module that provides #api, #error, #param, #error.
module DSL

module Common
def api_versions(*versions)
_apipie_dsl_data[:api_versions].concat(versions)
end
alias :api_version :api_versions

# Describe the next method.
#
# Example:
# desc "print hello world"
# def hello_world
# puts "hello world"
# end
#
def desc(description) #:doc:
return unless Apipie.active_dsl?
if _apipie_dsl_data[:description]
raise "Double method description."
end
_apipie_dsl_data[:description] = description
end
alias :description :desc
alias :full_description :desc

# describe next method with document in given path
# in convension, these doc located under "#{Rails.root}/doc"
# Example:
# document "hello_world.md"
# def hello_world
# puts "hello world"
# end
def document path
content = File.open(File.join(Rails.root, Apipie.configuration.doc_path, path)).read
desc content
end

# Describe available request/response formats
#
# formats ['json', 'jsonp', 'xml']
def formats(formats) #:doc:
return unless Apipie.active_dsl?
_apipie_dsl_data[:formats] = formats
end

# Describe additional metadata
#
# meta :author => { :name => 'John', :surname => 'Doe' }
def meta(meta) #:doc:
_apipie_dsl_data[:meta] = meta
end


# Describe possible responses
#
# Example:
# response :desc => "speaker is sleeping", :code => 500, :meta => [:some, :more, :data]
# response 500, "speaker is sleeping"
# def hello_world
# return 500 if self.speaker.sleeping?
# puts "hello world"
# end
#
def response(code, example=nil, options={}) #:doc:
return unless Apipie.active_dsl?
_apipie_dsl_data[:responses] << [code, example, options]
end

def error(code, example=nil, options={})
response(code, example, options)
end

def success(code, example=nil, options={})
response(code, example, options)
end

def _apipie_define_validators(description)

# [re]define method only if validation is turned on
if description && (Apipie.configuration.validate == true ||
Apipie.configuration.validate == :implicitly ||
Apipie.configuration.validate == :explicitly)

_apipie_save_method_params(description.method, description.params)

unless instance_methods.include?(:apipie_validations)
define_method(:apipie_validations) do
method_params = self.class._apipie_get_method_params(action_name)

if Apipie.configuration.validate_presence?
method_params.each do |_, param|
# check if required parameters are present
raise ParamMissing.new(param) if param.required && !params.has_key?(param.name)
end
end

if Apipie.configuration.validate_value?
method_params.each do |_, param|
# params validations
param.validate(params[:"#{param.name}"]) if params.has_key?(param.name)
end
end

# Only allow params passed in that are defined keys in the api
# Auto skip the default params (format, controller, action)
if Apipie.configuration.validate_key?
params.reject{|k,_| %w[format controller action].include?(k.to_s) }.each_key do |param|
# params allowed
raise UnknownParam.new(param) if method_params.select {|_,p| p.name.to_s == param.to_s}.empty?
end
end

if Apipie.configuration.process_value?
@api_params ||= {}
method_params.each do |_, param|
# params processing
@api_params[param.as] = param.process_value(params[:"#{param.name}"]) if params.has_key?(param.name)
end
end
end
end

if (Apipie.configuration.validate == :implicitly || Apipie.configuration.validate == true)
old_method = instance_method(description.method)

define_method(description.method) do |*args|
apipie_validations

# run the original method code
old_method.bind(self).call(*args)
end
end

end
end

def _apipie_save_method_params(method, params)
@method_params ||= {}
@method_params[method] = params
end

def _apipie_get_method_params(method)
@method_params[method]
end

# Describe request header.
# Headers can't be validated with config.validate_presence = true
#
# Example:
# header 'ClientId', "client-id"
# def show
# render :text => headers['HTTP_CLIENT_ID']
# end
#
def header(header_name, description, options = {}) #:doc
return unless Apipie.active_dsl?
_apipie_dsl_data[:headers] << {
name: header_name,
description: description,
options: options
}
end
end

end # module DSL
end # module Apipie
Loading