diff --git a/app/views/apipie/apipies/_action.md.erb b/app/views/apipie/apipies/_action.md.erb
new file mode 100644
index 00000000..e324da48
--- /dev/null
+++ b/app/views/apipie/apipies/_action.md.erb
@@ -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 -%>
diff --git a/app/views/apipie/apipies/_headers.md.erb b/app/views/apipie/apipies/_headers.md.erb
new file mode 100644
index 00000000..e69de29b
diff --git a/app/views/apipie/apipies/_param.md.erb b/app/views/apipie/apipies/_param.md.erb
new file mode 100644
index 00000000..4dce7383
--- /dev/null
+++ b/app/views/apipie/apipies/_param.md.erb
@@ -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(' ') %>
diff --git a/app/views/apipie/apipies/_resource.md.erb b/app/views/apipie/apipies/_resource.md.erb
new file mode 100644
index 00000000..ff49609b
--- /dev/null
+++ b/app/views/apipie/apipies/_resource.md.erb
@@ -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 -%>
diff --git a/app/views/apipie/apipies/_response.md.erb b/app/views/apipie/apipies/_response.md.erb
new file mode 100644
index 00000000..df83d616
--- /dev/null
+++ b/app/views/apipie/apipies/_response.md.erb
@@ -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
+-%>
diff --git a/app/views/apipie/apipies/static.md.erb b/app/views/apipie/apipies/static.md.erb
new file mode 100644
index 00000000..04b969d0
--- /dev/null
+++ b/app/views/apipie/apipies/static.md.erb
@@ -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 -%>
diff --git a/app/views/layouts/apipie/apipie.md.erb b/app/views/layouts/apipie/apipie.md.erb
new file mode 100644
index 00000000..37f0bddb
--- /dev/null
+++ b/app/views/layouts/apipie/apipie.md.erb
@@ -0,0 +1 @@
+<%= yield %>
diff --git a/lib/apipie-rails.rb b/lib/apipie-rails.rb
index a4b7fe97..f7ef7821 100644
--- a/lib/apipie-rails.rb
+++ b/lib/apipie-rails.rb
@@ -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"
@@ -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
diff --git a/lib/apipie/client/generator.rb b/lib/apipie/client/generator.rb
index ede403a8..e429f440 100755
--- a/lib/apipie/client/generator.rb
+++ b/lib/apipie/client/generator.rb
@@ -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
diff --git a/lib/apipie/dsl/action.rb b/lib/apipie/dsl/action.rb
new file mode 100644
index 00000000..d32eed98
--- /dev/null
+++ b/lib/apipie/dsl/action.rb
@@ -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
diff --git a/lib/apipie/dsl/base.rb b/lib/apipie/dsl/base.rb
new file mode 100644
index 00000000..b6043e6e
--- /dev/null
+++ b/lib/apipie/dsl/base.rb
@@ -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
diff --git a/lib/apipie/dsl/common.rb b/lib/apipie/dsl/common.rb
new file mode 100644
index 00000000..445012d3
--- /dev/null
+++ b/lib/apipie/dsl/common.rb
@@ -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
diff --git a/lib/apipie/dsl/concern.rb b/lib/apipie/dsl/concern.rb
new file mode 100644
index 00000000..7d9ccdc8
--- /dev/null
+++ b/lib/apipie/dsl/concern.rb
@@ -0,0 +1,44 @@
+module Apipie
+
+  # DSL is a module that provides #api, #error, #param, #error.
+  module DSL
+
+    module Concern
+      include Apipie::DSL::Base
+      include Apipie::DSL::Common
+      include Apipie::DSL::Action
+      include Apipie::DSL::Param
+
+      # the concern was included into a controller
+      def included(controller)
+        super
+        _apipie_concern_data.each do |method_name, _apipie_dsl_data|
+          # remove method description if exists and create new one
+          description = Apipie.define_method_description(controller, method_name, _apipie_dsl_data)
+          controller._apipie_define_validators(description)
+        end
+      end
+
+      def _apipie_concern_data
+        @_apipie_concern_data ||= []
+      end
+
+      def apipie_concern?
+        true
+      end
+
+      # create method api and redefine newly added method
+      def method_added(method_name) #:doc:
+        super
+
+        return if ! Apipie.active_dsl? || !_apipie_dsl_data[:api]
+
+        _apipie_concern_data << [method_name, _apipie_dsl_data.merge(:from_concern => true)]
+      ensure
+        _apipie_dsl_data_clear
+      end
+
+    end
+
+  end # module DSL
+end # module Apipie
diff --git a/lib/apipie/dsl/controller.rb b/lib/apipie/dsl/controller.rb
new file mode 100644
index 00000000..a52384c5
--- /dev/null
+++ b/lib/apipie/dsl/controller.rb
@@ -0,0 +1,74 @@
+module Apipie
+
+  # DSL is a module that provides #api, #error, #param, #error.
+  module DSL
+
+    module Controller
+      include Apipie::DSL::Base
+      include Apipie::DSL::Common
+      include Apipie::DSL::Action
+      include Apipie::DSL::Param
+
+      # defines the substitutions to be made in the API paths deifned
+      # in concerns included. For example:
+      #
+      # There is this method defined in concern:
+      #
+      #    api GET ':controller_path/:id'
+      #    def show
+      #      # ...
+      #    end
+      #
+      # If you include the concern into some controller, you can
+      # specify the value for :controller_path like this:
+      #
+      #      apipie_concern_subst(:controller_path => '/users')
+      #      include ::Concerns::SampleController
+      #
+      # The resulting path will be '/users/:id'.
+      #
+      # It has to be specified before the concern is included.
+      #
+      # If not specified, the default predefined substitions are
+      #
+      #    {:conroller_path => controller.controller_path,
+      #     :resource_id  => `resource_id_from_apipie` }
+      def apipie_concern_subst(subst_hash)
+        _apipie_concern_subst.merge!(subst_hash)
+      end
+
+      def _apipie_concern_subst
+        @_apipie_concern_subst ||= {:controller_path => self.controller_path,
+                                    :resource_id => Apipie.get_resource_name(self)}
+      end
+
+      def _apipie_perform_concern_subst(string)
+        return _apipie_concern_subst.reduce(string) do |ret, (key, val)|
+          ret.gsub(":#{key}", val)
+        end
+      end
+
+      def apipie_concern?
+        false
+      end
+
+      # create method api and redefine newly added method
+      def method_added(method_name) #:doc:
+        super
+        return if !Apipie.active_dsl? || !_apipie_dsl_data[:api]
+
+        return if _apipie_dsl_data[:api_args].blank? && _apipie_dsl_data[:api_from_routes].blank?
+
+        # remove method description if exists and create new one
+        Apipie.remove_method_description(self, _apipie_dsl_data[:api_versions], method_name)
+        description = Apipie.define_method_description(self, method_name, _apipie_dsl_data)
+
+        _apipie_dsl_data_clear
+        _apipie_define_validators(description)
+      ensure
+        _apipie_dsl_data_clear
+      end
+    end
+
+  end # module DSL
+end # module Apipie
diff --git a/lib/apipie/dsl/definition.rb b/lib/apipie/dsl/definition.rb
new file mode 100644
index 00000000..484495ab
--- /dev/null
+++ b/lib/apipie/dsl/definition.rb
@@ -0,0 +1,8 @@
+require "apipie/dsl/base"
+require "apipie/dsl/action"
+require "apipie/dsl/common"
+require "apipie/dsl/param"
+require "apipie/dsl/concern"
+
+require "apipie/dsl/resource"
+require "apipie/dsl/controller"
diff --git a/lib/apipie/dsl/param.rb b/lib/apipie/dsl/param.rb
new file mode 100644
index 00000000..2bbcc64e
--- /dev/null
+++ b/lib/apipie/dsl/param.rb
@@ -0,0 +1,59 @@
+module Apipie
+
+  # DSL is a module that provides #api, #error, #param, #error.
+  module DSL
+
+    # this describes the params, it's in separate module because it's
+    # used in Validators as well
+    module Param
+      # Describe method's parameter
+      #
+      # Example:
+      #   param :greeting, String, :desc => "arbitrary text", :required => true
+      #   def hello_world(greeting)
+      #     puts greeting
+      #   end
+      #
+      def param(param_name, validator, desc_or_options = nil, options = {}, &block) #:doc:
+        return unless Apipie.active_dsl?
+        _apipie_dsl_data[:params] << [param_name,
+                                      validator,
+                                      desc_or_options,
+                                      options.merge(:param_group => @_current_param_group),
+                                      block]
+      end
+
+      # Reuses param group for this method. The definition is looked up
+      # in scope of this controller. If the group was defined in
+      # different controller, the second param can be used to specify it.
+      # when using action_aware parmas, you can specify :as =>
+      # :create or :update to explicitly say how it should behave
+      def param_group(name, scope_or_options = nil, options = {})
+        if scope_or_options.is_a? Hash
+          options.merge!(scope_or_options)
+          scope = options[:scope]
+        else
+          scope = scope_or_options
+        end
+        scope ||= _default_param_group_scope
+
+        @_current_param_group = {
+          :scope => scope,
+          :name => name,
+          :options => options,
+          :from_concern => scope.apipie_concern?
+        }
+        self.instance_exec(&Apipie.get_param_group(scope, name))
+      ensure
+        @_current_param_group = nil
+      end
+
+      # where the group definition should be looked up when no scope
+      # given. This is expected to return a controller.
+      def _default_param_group_scope
+        self
+      end
+    end
+
+  end # module DSL
+end # module Apipie
diff --git a/lib/apipie/dsl/resource.rb b/lib/apipie/dsl/resource.rb
new file mode 100644
index 00000000..714e1b54
--- /dev/null
+++ b/lib/apipie/dsl/resource.rb
@@ -0,0 +1,65 @@
+# Apipie DSL functions.
+module Apipie
+
+  # DSL is a module that provides #api, #error, #param, #error.
+  module DSL
+
+    module Resource
+
+      class Description
+        include Apipie::DSL::Base
+        include Apipie::DSL::Common
+        include Apipie::DSL::Resource
+        include Apipie::DSL::Param
+
+        def initialize(controller)
+          @controller = controller
+        end
+
+        def _eval_dsl(&block)
+          instance_eval(&block)
+          return _apipie_dsl_data
+        end
+
+        # evaluates resource description DSL and returns results
+        def self.eval_dsl(controller, &block)
+          dsl_data  = self.new(controller)._eval_dsl(&block)
+          if dsl_data[:api_versions].empty?
+            dsl_data[:api_versions] = Apipie.controller_versions(controller)
+          end
+          dsl_data
+        end
+      end
+
+      # by default, the resource id is derived from controller_name
+      # it can be overwritten with.
+      #
+      #    resource_id "my_own_resource_id"
+      def resource_id(resource_id)
+        Apipie.set_resource_id(@controller, resource_id)
+      end
+
+      def name(name)
+        _apipie_dsl_data[:resource_name] = name
+      end
+
+      def api_base_url(url)
+        _apipie_dsl_data[:api_base_url] = url
+      end
+
+      def short(short)
+        _apipie_dsl_data[:short_description] = short
+      end
+      alias :short_description :short
+
+      def path(path)
+        _apipie_dsl_data[:path] = path
+      end
+
+      def app_info(app_info)
+        _apipie_dsl_data[:app_info] = app_info
+      end
+    end
+
+  end # module DSL
+end # module Apipie
diff --git a/lib/apipie/dsl_definition.rb b/lib/apipie/dsl_definition.rb
deleted file mode 100644
index 88a78c95..00000000
--- a/lib/apipie/dsl_definition.rb
+++ /dev/null
@@ -1,480 +0,0 @@
-# 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,
-         :errors            => [],
-         :params            => [],
-         :headers           => [],
-         :resource_id        => nil,
-         :short_description => nil,
-         :description       => nil,
-         :examples          => [],
-         :see               => [],
-         :formats           => nil,
-         :api_versions      => [],
-         :meta              => nil,
-         :show              => true
-       }
-      end
-    end
-
-    module Resource
-      # by default, the resource id is derived from controller_name
-      # it can be overwritten with.
-      #
-      #    resource_id "my_own_resource_id"
-      def resource_id(resource_id)
-        Apipie.set_resource_id(@controller, resource_id)
-      end
-
-      def name(name)
-        _apipie_dsl_data[:resource_name] = name
-      end
-
-      def api_base_url(url)
-        _apipie_dsl_data[:api_base_url] = url
-      end
-
-      def short(short)
-        _apipie_dsl_data[:short_description] = short
-      end
-      alias :short_description :short
-
-      def path(path)
-        _apipie_dsl_data[:path] = path
-      end
-
-      def app_info(app_info)
-        _apipie_dsl_data[:app_info] = app_info
-      end
-    end
-
-    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 = ResourceDescriptionDsl.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
-
-    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 errors
-      #
-      # Example:
-      #   error :desc => "speaker is sleeping", :code => 500, :meta => [:some, :more, :data]
-      #   error 500, "speaker is sleeping"
-      #   def hello_world
-      #     return 500 if self.speaker.sleeping?
-      #     puts "hello world"
-      #   end
-      #
-      def error(code_or_options, desc=nil, options={}) #:doc:
-        return unless Apipie.active_dsl?
-        _apipie_dsl_data[:errors] << [code_or_options, desc, 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
-
-    # this describes the params, it's in separate module because it's
-    # used in Validators as well
-    module Param
-      # Describe method's parameter
-      #
-      # Example:
-      #   param :greeting, String, :desc => "arbitrary text", :required => true
-      #   def hello_world(greeting)
-      #     puts greeting
-      #   end
-      #
-      def param(param_name, validator, desc_or_options = nil, options = {}, &block) #:doc:
-        return unless Apipie.active_dsl?
-        _apipie_dsl_data[:params] << [param_name,
-                                      validator,
-                                      desc_or_options,
-                                      options.merge(:param_group => @_current_param_group),
-                                      block]
-      end
-
-      # Reuses param group for this method. The definition is looked up
-      # in scope of this controller. If the group was defined in
-      # different controller, the second param can be used to specify it.
-      # when using action_aware parmas, you can specify :as =>
-      # :create or :update to explicitly say how it should behave
-      def param_group(name, scope_or_options = nil, options = {})
-        if scope_or_options.is_a? Hash
-          options.merge!(scope_or_options)
-          scope = options[:scope]
-        else
-          scope = scope_or_options
-        end
-        scope ||= _default_param_group_scope
-
-        @_current_param_group = {
-          :scope => scope,
-          :name => name,
-          :options => options,
-          :from_concern => scope.apipie_concern?
-        }
-        self.instance_exec(&Apipie.get_param_group(scope, name))
-      ensure
-        @_current_param_group = nil
-      end
-
-      # where the group definition should be looked up when no scope
-      # given. This is expected to return a controller.
-      def _default_param_group_scope
-        self
-      end
-    end
-
-    module Controller
-      include Apipie::DSL::Base
-      include Apipie::DSL::Common
-      include Apipie::DSL::Action
-      include Apipie::DSL::Param
-
-      # defines the substitutions to be made in the API paths deifned
-      # in concerns included. For example:
-      #
-      # There is this method defined in concern:
-      #
-      #    api GET ':controller_path/:id'
-      #    def show
-      #      # ...
-      #    end
-      #
-      # If you include the concern into some controller, you can
-      # specify the value for :controller_path like this:
-      #
-      #      apipie_concern_subst(:controller_path => '/users')
-      #      include ::Concerns::SampleController
-      #
-      # The resulting path will be '/users/:id'.
-      #
-      # It has to be specified before the concern is included.
-      #
-      # If not specified, the default predefined substitions are
-      #
-      #    {:conroller_path => controller.controller_path,
-      #     :resource_id  => `resource_id_from_apipie` }
-      def apipie_concern_subst(subst_hash)
-        _apipie_concern_subst.merge!(subst_hash)
-      end
-
-      def _apipie_concern_subst
-        @_apipie_concern_subst ||= {:controller_path => self.controller_path,
-                                    :resource_id => Apipie.get_resource_name(self)}
-      end
-
-      def _apipie_perform_concern_subst(string)
-        return _apipie_concern_subst.reduce(string) do |ret, (key, val)|
-          ret.gsub(":#{key}", val)
-        end
-      end
-
-      def apipie_concern?
-        false
-      end
-
-      # create method api and redefine newly added method
-      def method_added(method_name) #:doc:
-        super
-        return if !Apipie.active_dsl? || !_apipie_dsl_data[:api]
-
-        return if _apipie_dsl_data[:api_args].blank? && _apipie_dsl_data[:api_from_routes].blank?
-
-        # remove method description if exists and create new one
-        Apipie.remove_method_description(self, _apipie_dsl_data[:api_versions], method_name)
-        description = Apipie.define_method_description(self, method_name, _apipie_dsl_data)
-
-        _apipie_dsl_data_clear
-        _apipie_define_validators(description)
-      ensure
-        _apipie_dsl_data_clear
-      end
-    end
-
-    module Concern
-      include Apipie::DSL::Base
-      include Apipie::DSL::Common
-      include Apipie::DSL::Action
-      include Apipie::DSL::Param
-
-      # the concern was included into a controller
-      def included(controller)
-        super
-        _apipie_concern_data.each do |method_name, _apipie_dsl_data|
-          # remove method description if exists and create new one
-          description = Apipie.define_method_description(controller, method_name, _apipie_dsl_data)
-          controller._apipie_define_validators(description)
-        end
-      end
-
-      def _apipie_concern_data
-        @_apipie_concern_data ||= []
-      end
-
-      def apipie_concern?
-        true
-      end
-
-      # create method api and redefine newly added method
-      def method_added(method_name) #:doc:
-        super
-
-        return if ! Apipie.active_dsl? || !_apipie_dsl_data[:api]
-
-        _apipie_concern_data << [method_name, _apipie_dsl_data.merge(:from_concern => true)]
-      ensure
-        _apipie_dsl_data_clear
-      end
-
-    end
-
-    class ResourceDescriptionDsl
-      include Apipie::DSL::Base
-      include Apipie::DSL::Common
-      include Apipie::DSL::Resource
-      include Apipie::DSL::Param
-
-      def initialize(controller)
-        @controller = controller
-      end
-
-      def _eval_dsl(&block)
-        instance_eval(&block)
-        return _apipie_dsl_data
-      end
-
-      # evaluates resource description DSL and returns results
-      def self.eval_dsl(controller, &block)
-        dsl_data  = self.new(controller)._eval_dsl(&block)
-        if dsl_data[:api_versions].empty?
-          dsl_data[:api_versions] = Apipie.controller_versions(controller)
-        end
-        dsl_data
-      end
-    end
-
-  end # module DSL
-end # module Apipie
diff --git a/lib/apipie/error_description.rb b/lib/apipie/error_description.rb
deleted file mode 100644
index 518d2d32..00000000
--- a/lib/apipie/error_description.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-module Apipie
-
-  class ErrorDescription
-
-    attr_reader :code, :description, :metadata
-
-    def self.from_dsl_data(args)
-      code_or_options, desc, options = args
-      Apipie::ErrorDescription.new(code_or_options,
-                                   desc,
-                                   options)
-    end
-
-    def initialize(code_or_options, desc=nil, options={})
-      if code_or_options.is_a? Hash
-        code_or_options.symbolize_keys!
-        @code = code_or_options[:code]
-        @metadata = code_or_options[:meta]
-        @description = code_or_options[:desc] || code_or_options[:description]
-      else
-        @code = code_or_options
-        @metadata = options[:meta]
-        @description = desc
-      end
-    end
-
-    def to_json
-      {
-        :code => code,
-        :description => description,
-        :metadata => metadata
-      }
-    end
-
-  end
-
-end
diff --git a/lib/apipie/markup.rb b/lib/apipie/markup.rb
index aa32b543..c239a1a0 100644
--- a/lib/apipie/markup.rb
+++ b/lib/apipie/markup.rb
@@ -27,7 +27,8 @@ def initialize
       end
 
       def to_html(text)
-        Maruku.new(text).to_html
+        # Maruku.new(text).to_html
+        text
       end
 
     end
diff --git a/lib/apipie/method_description.rb b/lib/apipie/method_description.rb
index 43946045..83298691 100644
--- a/lib/apipie/method_description.rb
+++ b/lib/apipie/method_description.rb
@@ -30,8 +30,8 @@ def initialize(method, resource, dsl_data)
       desc = dsl_data[:description] || ''
       @full_description = Apipie.markup_to_html(desc)
 
-      @errors = dsl_data[:errors].map do |args|
-        Apipie::ErrorDescription.from_dsl_data(args)
+      @responses = dsl_data[:responses].map do |args|
+        Apipie::ResponseDescription.from_dsl_data(args)
       end
 
       @see = dsl_data[:see].map do |args|
@@ -81,21 +81,21 @@ def params_ordered
       all_params.find_all(&:validator)
     end
 
-    def errors
-      return @merged_errors if @merged_errors
-      @merged_errors = []
+    def responses
+      return @merged_responses if @merged_responses
+      @merged_responses = []
       if @resource
-        resource_errors = @resource._errors_args.map do |args|
-          Apipie::ErrorDescription.from_dsl_data(args)
+        resource_responses = @resource._responses_args.map do |args|
+          Apipie::ResponseDescription.from_dsl_data(args)
         end
 
-        # exclude overwritten parent errors
-        @merged_errors = resource_errors.find_all do |err|
-          !@errors.any? { |e| e.code == err.code }
+        # exclude overwritten parent responses
+        @merged_responses = resource_responses.find_all do |response|
+          !@responses.any? { |r| r.code == response.code }
         end
       end
-      @merged_errors.concat(@errors)
-      return @merged_errors
+      @merged_responses.concat(@responses)
+      return @merged_responses
     end
 
     def version
@@ -145,7 +145,7 @@ def to_json(lang=nil)
         :apis => method_apis_to_json(lang),
         :formats => formats,
         :full_description => Apipie.app.translate(@full_description, lang),
-        :errors => errors.map(&:to_json),
+        :responses => responses.map(&:to_json),
         :params => params_ordered.map{ |param| param.to_json(lang) }.flatten,
         :examples => @examples,
         :metadata => @metadata,
diff --git a/lib/apipie/param_description.rb b/lib/apipie/param_description.rb
index 6c3780ed..72c5f8a7 100644
--- a/lib/apipie/param_description.rb
+++ b/lib/apipie/param_description.rb
@@ -8,7 +8,7 @@ module Apipie
   # validator - Validator::BaseValidator subclass
   class ParamDescription
 
-    attr_reader :method_description, :name, :desc, :allow_nil, :allow_blank, :validator, :options, :metadata, :show, :as, :validations
+    attr_reader :method_description, :name, :desc, :allowed, :allow_nil, :allow_blank, :validator, :options, :metadata, :show, :as, :validations
     attr_accessor :parent, :required
 
     def self.from_dsl_data(method_description, args)
@@ -44,6 +44,8 @@ def initialize(method_description, name, validator, desc_or_options = nil, optio
       @as = options[:as] || @name
       @desc = preformat_text(@options[:desc])
 
+      @allowed = Array === validator ? @options[:allowed] : []
+
       @parent = @options[:parent]
       @metadata = @options[:meta]
 
@@ -126,6 +128,7 @@ def to_json(lang = nil)
                :required => required,
                :allow_nil => allow_nil,
                :allow_blank => allow_blank,
+               :allowed => allowed,
                :validator => validator.to_s,
                :expected_type => validator.expected_type,
                :metadata => metadata,
diff --git a/lib/apipie/render.rb b/lib/apipie/render.rb
new file mode 100644
index 00000000..1a72e18b
--- /dev/null
+++ b/lib/apipie/render.rb
@@ -0,0 +1,59 @@
+module Apipie
+  module Render
+    # Attempt to use the Rails application views, otherwise default to built in views
+    def self.renderer(formats = nil)
+      return @apipie_renderer if @apipie_renderer
+
+      @apipie_renderer = ActionView::Base.new([base_path, layouts_path], {}, nil, formats)
+      @apipie_renderer.singleton_class.send(:include, ApipieHelper)
+      return @apipie_renderer
+    end
+
+    def self.page(file_name, template, variables, layout = 'apipie', formats = nil)
+      av = renderer(formats)
+      File.open(file_name, "w") do |f|
+        variables.each do |var, val|
+          av.instance_variable_set("@#{var}", val)
+        end
+        f.write av.render(
+          :template => "#{template}",
+          :layout => (layout && "apipie/#{layout}"),
+          :formats => formats)
+      end
+    end
+
+    def self.with_loaded_documentation
+      Apipie.configuration.use_cache = false # we don't want to skip DSL evaluation
+      Apipie.reload_documentation
+      yield
+    end
+
+    def self.copy_jscss(dest)
+      src = File.expand_path(Apipie.root.join('app', 'public', 'apipie'))
+      FileUtils.mkdir_p dest
+      FileUtils.cp_r "#{src}/.", dest
+    end
+
+    def self.lang_ext(lang = nil)
+      lang ? ".#{lang}" : ""
+    end
+
+    private
+
+    def self.base_path
+      if File.directory?("#{Rails.root}/app/views/apipie/apipies")
+        "#{Rails.root}/app/views/apipie/apipies"
+      else
+        File.expand_path(Apipie.root.join('app', 'views', 'apipie', 'apipies'))
+      end
+    end
+
+    def self.layouts_path
+      if File.directory?("#{Rails.root}/app/views/layouts/apipie")
+        "#{Rails.root}/app/views/layouts"
+      else
+        File.expand_path(Apipie.root.join('app', 'views', 'layouts'))
+      end
+    end
+  end
+end
diff --git a/lib/apipie/render/html.rb b/lib/apipie/render/html.rb
new file mode 100644
index 00000000..75e50aee
--- /dev/null
+++ b/lib/apipie/render/html.rb
@@ -0,0 +1,72 @@
+require 'apipie/render'
+
+module Apipie
+  module Render
+    module HTML
+
+      def self.one_page(file_base, doc, lang = nil)
+        FileUtils.mkdir_p(File.dirname(file_base)) unless File.exists?(File.dirname(file_base))
+
+        Render.page("#{file_base}-onepage#{Render.lang_ext(lang)}.html", "static", {:doc => doc[:docs],
+          :language => lang, :languages => Apipie.configuration.languages})
+      end
+
+      def self.plain_page(file_base, doc, lang = nil)
+        FileUtils.mkdir_p(File.dirname(file_base)) unless File.exists?(File.dirname(file_base))
+
+        Render.page("#{file_base}-plain#{Render.lang_ext(lang)}.html", "plain", {:doc => doc[:docs],
+          :language => lang, :languages => Apipie.configuration.languages}, nil)
+      end
+
+      def self.index_page(file_base, doc, include_json = false, show_versions = false, lang = nil)
+        FileUtils.mkdir_p(File.dirname(file_base)) unless File.exists?(File.dirname(file_base))
+        versions = show_versions && Apipie.available_versions
+        Render.page("#{file_base}#{Render.lang_ext(lang)}.html", "index", {:doc => doc[:docs],
+          :versions => versions, :language => lang, :languages => Apipie.configuration.languages})
+
+        File.open("#{file_base}#{Render.lang_ext(lang)}.json", "w") { |f| f << doc.to_json } if include_json
+      end
+
+      def self.resource_pages(version, file_base, doc, include_json = false, lang = nil)
+        doc[:docs][:resources].each do |resource_name, _|
+          resource_file_base = File.join(file_base, resource_name.to_s)
+          FileUtils.mkdir_p(File.dirname(resource_file_base)) unless File.exists?(File.dirname(resource_file_base))
+
+          doc = Apipie.to_json(version, resource_name, nil, lang)
+          doc[:docs][:link_extension] = (lang ? ".#{lang}.html" : ".html")
+          Render.page("#{resource_file_base}#{Render.lang_ext(lang)}.html", "resource", {:doc => doc[:docs],
+            :resource => doc[:docs][:resources].first, :language => lang, :languages => Apipie.configuration.languages})
+          File.open("#{resource_file_base}#{Render.lang_ext(lang)}.json", "w") { |f| f << doc.to_json } if include_json
+        end
+      end
+
+      def self.method_pages(version, file_base, doc, include_json = false, lang = nil)
+        doc[:docs][:resources].each do |resource_name, resource_params|
+          resource_params[:methods].each do |method|
+            method_file_base = File.join(file_base, resource_name.to_s, method[:name].to_s)
+            FileUtils.mkdir_p(File.dirname(method_file_base)) unless File.exists?(File.dirname(method_file_base))
+
+            doc = Apipie.to_json(version, resource_name, method[:name], lang)
+            doc[:docs][:link_extension] = (lang ? ".#{lang}.html" : ".html")
+            Render.page("#{method_file_base}#{Render.lang_ext(lang)}.html", "method", {
+              :doc => doc[:docs],
+              :resource => doc[:docs][:resources].first,
+              :method => doc[:docs][:resources].first[:methods].first,
+              :language => lang,
+              :languages => Apipie.configuration.languages
+            })
+
+            File.open("#{method_file_base}#{Render.lang_ext(lang)}.json", "w") { |f| f << doc.to_json } if include_json
+          end
+        end
+      end
+
+      def self.copy_jscss(dest)
+        src = File.expand_path(Apipie.root.join('app', 'public', 'apipie'))
+        FileUtils.mkdir_p dest
+        FileUtils.cp_r "#{src}/.", dest
+      end
+
+    end
+  end
+end
diff --git a/lib/apipie/render/json.rb b/lib/apipie/render/json.rb
new file mode 100644
index 00000000..9f1b0477
--- /dev/null
+++ b/lib/apipie/render/json.rb
@@ -0,0 +1,16 @@
+require 'apipie/render'
+
+module Apipie
+  module Render
+    module JSON
+
+      def self.one_page(file_base, doc, lang = nil)
+        FileUtils.mkdir_p(file_base) unless File.exists?(file_base)
+
+        filename = "schema_apipie#{Render.lang_ext(lang)}.json"
+        File.open("#{file_base}/#{filename}", 'w') { |file| file.write(::JSON.pretty_generate(doc)) }
+      end
+
+    end
+  end
+end
diff --git a/lib/apipie/render/markdown.rb b/lib/apipie/render/markdown.rb
new file mode 100644
index 00000000..e75ef27f
--- /dev/null
+++ b/lib/apipie/render/markdown.rb
@@ -0,0 +1,55 @@
+require 'apipie/render'
+
+module Apipie
+  module Render
+    module Markdown
+
+      def self.one_page(file_base, doc, lang = nil)
+        FileUtils.mkdir_p(File.dirname(file_base)) unless File.exists?(File.dirname(file_base))
+
+        Render.page("#{file_base}-onepage#{Render.lang_ext(lang)}.md", "static", {
+          :doc => doc[:docs],
+          :language => lang,
+          :languages => Apipie.configuration.languages
+        }, 'apipie', [:md])
+      end
+
+      def self.resource_pages(version, file_base, doc, include_json = false, lang = nil)
+        doc[:docs][:resources].each do |resource_name, _|
+          resource_file_base = File.join(file_base, resource_name.to_s)
+          FileUtils.mkdir_p(File.dirname(resource_file_base)) unless File.exists?(File.dirname(resource_file_base))
+
+          doc = Apipie.to_json(version, resource_name, nil, lang)
+          doc[:docs][:link_extension] = (lang ? ".#{lang}.md" : ".md")
+
+          Render.page("#{resource_file_base}#{Render.lang_ext(lang)}.md", "resource", {
+            :doc => doc[:docs],
+            :resource => doc[:docs][:resources].first,
+            :language => lang,
+            :languages => Apipie.configuration.languages
+          }, 'apipie', [:md])
+        end
+      end
+
+      def self.method_pages(version, file_base, doc, include_json = false, lang = nil)
+        doc[:docs][:resources].each do |resource_name, resource_params|
+          resource_params[:methods].each do |method|
+            method_file_base = File.join(file_base, resource_name.to_s, method[:name].to_s)
+            FileUtils.mkdir_p(File.dirname(method_file_base)) unless File.exists?(File.dirname(method_file_base))
+
+            doc = Apipie.to_json(version, resource_name, method[:name], lang)
+            doc[:docs][:link_extension] = (lang ? ".#{lang}.md" : ".md")
+            Render.page("#{method_file_base}#{Render.lang_ext(lang)}.md", "method", {
+              :doc => doc[:docs],
+              :resource => doc[:docs][:resources].first,
+              :method => doc[:docs][:resources].first[:methods].first,
+              :language => lang,
+              :languages => Apipie.configuration.languages
+            }, 'apipie')
+          end
+        end
+      end
+
+    end
+  end
+end
diff --git a/lib/apipie/resource_description.rb b/lib/apipie/resource_description.rb
index 083d6c25..3b28d8c0 100644
--- a/lib/apipie/resource_description.rb
+++ b/lib/apipie/resource_description.rb
@@ -13,14 +13,14 @@ module Apipie
   class ResourceDescription
 
     attr_reader :controller, :_short_description, :_full_description, :_methods, :_id,
-      :_path, :_name, :_params_args, :_errors_args, :_formats, :_parent, :_metadata,
+      :_path, :_name, :_params_args, :_responses_args, :_formats, :_parent, :_metadata,
       :_headers
 
     def initialize(controller, resource_name, dsl_data = nil, version = nil, &block)
 
       @_methods = ActiveSupport::OrderedHash.new
       @_params_args = []
-      @_errors_args = []
+      @_responses_args = []
 
       @controller = controller
       @_id = resource_name
@@ -37,7 +37,7 @@ def update_from_dsl_data(dsl_data)
       @_short_description = dsl_data[:short_description]
       @_path = dsl_data[:path] || ""
       @_formats = dsl_data[:formats]
-      @_errors_args = dsl_data[:errors]
+      @_responses_args = dsl_data[:responses]
       @_params_args = dsl_data[:params]
       @_metadata = dsl_data[:meta]
       @_api_base_url = dsl_data[:api_base_url]
@@ -82,7 +82,12 @@ def doc_url
       Apipie.full_url crumbs.join('/')
     end
 
-    def api_url; "#{Apipie.api_base_url(_version)}#{@_path}"; end
+    def api_url
+      crumbs = []
+      crumbs << @_api_base_url
+      crumbs << @_id
+      crumbs.join('/')
+    end
 
     def valid_method_name?(method_name)
       @_methods.keys.map(&:to_s).include?(method_name.to_s)
diff --git a/lib/apipie/response_description.rb b/lib/apipie/response_description.rb
new file mode 100644
index 00000000..5e36e13b
--- /dev/null
+++ b/lib/apipie/response_description.rb
@@ -0,0 +1,37 @@
+module Apipie
+
+  class ResponseDescription
+
+    attr_reader :code, :body, :metadata, :headers
+
+    def self.from_dsl_data(args)
+      code_or_options, desc, options = args
+      Apipie::ResponseDescription.new(code_or_options,
+                                   desc,
+                                   options)
+    end
+
+    def initialize(code, body=nil, options={})
+      if !code.is_a? Numeric
+        warn "First argument must be a response code (Integer)"
+      else
+        options.symbolize_keys!
+        @headers = options[:headers]
+        @body = body
+        @code = code
+        @metadata = options[:meta]
+      end
+    end
+
+    def to_json
+      {
+        :code => code,
+        :headers => headers,
+        :body => body,
+        :metadata => metadata
+      }
+    end
+
+  end
+
+end
diff --git a/lib/apipie/validator.rb b/lib/apipie/validator.rb
index b4973a60..85df859e 100644
--- a/lib/apipie/validator.rb
+++ b/lib/apipie/validator.rb
@@ -101,11 +101,11 @@ def description
 
       def expected_type
         if @type.ancestors.include? Hash
-          'hash'
+          'object'
         elsif @type.ancestors.include? Array
           'array'
         elsif @type.ancestors.include? Numeric
-          'numeric'
+          'number'
         else
           'string'
         end
@@ -331,7 +331,7 @@ def description
       end
 
       def expected_type
-        'hash'
+        'object'
       end
 
       # where the group definition should be looked up when no scope
diff --git a/lib/boolean.rb b/lib/boolean.rb
new file mode 100644
index 00000000..ea9b4523
--- /dev/null
+++ b/lib/boolean.rb
@@ -0,0 +1,39 @@
+class Boolean
+
+  def self.new(bool)
+    bool
+  end
+
+  def self.true
+    true
+  end
+
+  def self.false
+    false
+  end
+
+end
+
+class FalseClass
+
+  def is_a?(other)
+    other == Boolean || super
+  end
+
+  def self.===(other)
+    other == Boolean || super
+  end
+
+end
+
+class TrueClass
+
+  def is_a?(other)
+    other == Boolean || super
+  end
+
+  def self.===(other)
+    other == Boolean || super
+  end
+
+end
diff --git a/lib/tasks/apipie.rake b/lib/tasks/apipie.rake
index 71ffe8bb..41929490 100644
--- a/lib/tasks/apipie.rake
+++ b/lib/tasks/apipie.rake
@@ -1,56 +1,9 @@
 # -*- coding: utf-8 -*-
 require 'fileutils'
+require 'apipie/render/html'
 
 namespace :apipie do
 
-  desc "Generate static documentation"
-  # You can specify OUT=output_base_file to have the following structure:
-  #
-  #    output_base_file.html
-  #    output_base_file-onepage.html
-  #    output_base_file
-  #    | - resource1.html
-  #    | - resource1
-  #    | - | - method1.html
-  #    | - | - method2.html
-  #    | - resource2.html
-  #
-  # By default OUT="#{Rails.root}/doc/apidoc"
-  task :static, [:version] => :environment do |t, args|
-    with_loaded_documentation do
-      args.with_defaults(:version => Apipie.configuration.default_version)
-      out = ENV["OUT"] || File.join(::Rails.root, Apipie.configuration.doc_path, 'apidoc')
-      subdir = File.basename(out)
-      copy_jscss(out)
-      Apipie.configuration.version_in_url = false
-      ([nil] + Apipie.configuration.languages).each do |lang|
-        I18n.locale = lang || Apipie.configuration.default_locale
-        Apipie.url_prefix = "./#{subdir}"
-        doc = Apipie.to_json(args[:version], nil, nil, lang)
-        doc[:docs][:link_extension] = "#{lang_ext(lang)}.html"
-        generate_one_page(out, doc, lang)
-        generate_plain_page(out, doc, lang)
-        generate_index_page(out, doc, false, false, lang)
-        Apipie.url_prefix = "../#{subdir}"
-        generate_resource_pages(args[:version], out, doc, false, lang)
-        Apipie.url_prefix = "../../#{subdir}"
-        generate_method_pages(args[:version], out, doc, false, lang)
-      end
-    end
-  end
-
-  desc "Generate static documentation json"
-  task :static_json, [:version] => :environment do |t, args|
-    with_loaded_documentation do
-      args.with_defaults(:version => Apipie.configuration.default_version)
-      out = ENV["OUT"] || File.join(::Rails.root, Apipie.configuration.doc_path, 'apidoc')
-      ([nil] + Apipie.configuration.languages).each do |lang|
-        doc = Apipie.to_json(args[:version], nil, nil, lang)
-        generate_json_page(out, doc, lang)
-      end
-    end
-  end
-
   # By default the full cache is built.
   # It is possible to generate index resp. resources only with
   # rake apipie:cache cache_part=index (resources resp.)
@@ -61,7 +14,7 @@ namespace :apipie do
     cache_part = ENV['cache_part']
     generate_index = (cache_part == 'resources' ? false : true)
     generate_resources = (cache_part == 'index' ? false : true)
-    with_loaded_documentation do
+    Apipie::Render.with_loaded_documentation do
       puts "#{Time.now} | Documents loaded..."
       ([nil] + Apipie.configuration.languages).each do |lang|
         I18n.locale = lang || Apipie.configuration.default_locale
@@ -76,7 +29,7 @@ namespace :apipie do
           Apipie.url_prefix = "./#{subdir}"
           doc = Apipie.to_json(Apipie.configuration.default_version, nil, nil, lang)
           doc[:docs][:link_extension] = (lang ? ".#{lang}.html" : ".html")
-          generate_index_page(file_base, doc, true, false, lang)
+          Apipie::Render::HTML.index_page(file_base, doc, true, false, lang)
         end
         Apipie.available_versions.each do |version|
           file_base_version = File.join(file_base, version)
@@ -84,12 +37,12 @@ namespace :apipie do
           doc = Apipie.to_json(version, nil, nil, lang)
           doc[:docs][:link_extension] = (lang ? ".#{lang}.html" : ".html")
 
-          generate_index_page(file_base_version, doc, true, true, lang) if generate_index
+          Apipie::Render::HTML.index_page(file_base_version, doc, true, true, lang) if generate_index
           if generate_resources
             Apipie.url_prefix = "../#{subdir_traversal_prefix}#{subdir}"
-            generate_resource_pages(version, file_base_version, doc, true, lang)
+            Apipie::Render::HTML.resource_pages(version, file_base_version, doc, true, lang)
             Apipie.url_prefix = "../../#{subdir_traversal_prefix}#{subdir}"
-            generate_method_pages(version, file_base_version, doc, true, lang)
+            Apipie::Render::HTML.method_pages(version, file_base_version, doc, true, lang)
           end
         end
       end
@@ -97,158 +50,4 @@ namespace :apipie do
     puts "#{Time.now} | Finished"
   end
 
-  # Attempt to use the Rails application views, otherwise default to built in views
-  def renderer
-    return @apipie_renderer if @apipie_renderer
-    base_path = if File.directory?("#{Rails.root}/app/views/apipie/apipies")
-                  "#{Rails.root}/app/views/apipie/apipies"
-                else
-                  File.expand_path("../../../app/views/apipie/apipies", __FILE__)
-                end
-    layouts_path = if File.directory?("#{Rails.root}/app/views/layouts/apipie")
-                     "#{Rails.root}/app/views/layouts"
-                   else
-                     File.expand_path("../../../app/views/layouts", __FILE__)
-                   end
-    @apipie_renderer = ActionView::Base.new([base_path, layouts_path])
-    @apipie_renderer.singleton_class.send(:include, ApipieHelper)
-    return @apipie_renderer
-  end
-
-  def render_page(file_name, template, variables, layout = 'apipie')
-    av = renderer
-    File.open(file_name, "w") do |f|
-      variables.each do |var, val|
-        av.instance_variable_set("@#{var}", val)
-      end
-      f.write av.render(
-        :template => "#{template}",
-        :layout => (layout && "apipie/#{layout}"))
-    end
-  end
-
-  def generate_json_page(file_base, doc, lang = nil)
-    FileUtils.mkdir_p(file_base) unless File.exists?(file_base)
-
-    filename = "schema_apipie#{lang_ext(lang)}.json"
-    File.open("#{file_base}/#{filename}", 'w') { |file| file.write(JSON.pretty_generate(doc)) }
-  end
-
-  def generate_one_page(file_base, doc, lang = nil)
-    FileUtils.mkdir_p(File.dirname(file_base)) unless File.exists?(File.dirname(file_base))
-
-    render_page("#{file_base}-onepage#{lang_ext(lang)}.html", "static", {:doc => doc[:docs],
-      :language => lang, :languages => Apipie.configuration.languages})
-  end
-
-  def generate_plain_page(file_base, doc, lang = nil)
-    FileUtils.mkdir_p(File.dirname(file_base)) unless File.exists?(File.dirname(file_base))
-
-    render_page("#{file_base}-plain#{lang_ext(lang)}.html", "plain", {:doc => doc[:docs],
-      :language => lang, :languages => Apipie.configuration.languages}, nil)
-  end
-
-  def generate_index_page(file_base, doc, include_json = false, show_versions = false, lang = nil)
-    FileUtils.mkdir_p(File.dirname(file_base)) unless File.exists?(File.dirname(file_base))
-    versions = show_versions && Apipie.available_versions
-    render_page("#{file_base}#{lang_ext(lang)}.html", "index", {:doc => doc[:docs],
-      :versions => versions, :language => lang, :languages => Apipie.configuration.languages})
-
-    File.open("#{file_base}#{lang_ext(lang)}.json", "w") { |f| f << doc.to_json } if include_json
-  end
-
-  def generate_resource_pages(version, file_base, doc, include_json = false, lang = nil)
-    doc[:docs][:resources].each do |resource_name, _|
-      resource_file_base = File.join(file_base, resource_name.to_s)
-      FileUtils.mkdir_p(File.dirname(resource_file_base)) unless File.exists?(File.dirname(resource_file_base))
-
-      doc = Apipie.to_json(version, resource_name, nil, lang)
-      doc[:docs][:link_extension] = (lang ? ".#{lang}.html" : ".html")
-      render_page("#{resource_file_base}#{lang_ext(lang)}.html", "resource", {:doc => doc[:docs],
-        :resource => doc[:docs][:resources].first, :language => lang, :languages => Apipie.configuration.languages})
-      File.open("#{resource_file_base}#{lang_ext(lang)}.json", "w") { |f| f << doc.to_json } if include_json
-    end
-  end
-
-  def generate_method_pages(version, file_base, doc, include_json = false, lang = nil)
-    doc[:docs][:resources].each do |resource_name, resource_params|
-      resource_params[:methods].each do |method|
-        method_file_base = File.join(file_base, resource_name.to_s, method[:name].to_s)
-        FileUtils.mkdir_p(File.dirname(method_file_base)) unless File.exists?(File.dirname(method_file_base))
-
-        doc = Apipie.to_json(version, resource_name, method[:name], lang)
-        doc[:docs][:link_extension] = (lang ? ".#{lang}.html" : ".html")
-        render_page("#{method_file_base}#{lang_ext(lang)}.html", "method", {:doc => doc[:docs],
-                                                           :resource => doc[:docs][:resources].first,
-                                                           :method => doc[:docs][:resources].first[:methods].first,
-                                                           :language => lang,
-                                                           :languages => Apipie.configuration.languages})
-
-        File.open("#{method_file_base}#{lang_ext(lang)}.json", "w") { |f| f << doc.to_json } if include_json
-      end
-    end
-  end
-
-  def with_loaded_documentation
-    Apipie.configuration.use_cache = false # we don't want to skip DSL evaluation
-    Apipie.reload_documentation
-    yield
-  end
-
-
-  def copy_jscss(dest)
-    src = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'app', 'public', 'apipie'))
-    FileUtils.mkdir_p dest
-    FileUtils.cp_r "#{src}/.", dest
-  end
-
-  def lang_ext(lang = nil)
-    lang ? ".#{lang}" : ""
-  end
-
-  desc "Generate CLI client for API documented with apipie gem. (deprecated)"
-  task :client do
-    puts <<MESSAGE
-The apipie gem itself doesn't provide client code generator. See
-https://github.com/Pajk/apipie-rails/wiki/CLI-client for more information on
-how to write your own generator.
-MESSAGE
-  end
-
-  def plaintext(text)
-    text.gsub(/<.*?>/, '').gsub("\n",' ').strip
-  end
-
-  desc "Update api description in controllers base on routes"
-  task :update_from_routes => [:environment] do
-    Apipie.configuration.force_dsl = true
-    ignored = Apipie.configuration.ignored_by_recorder
-    with_loaded_documentation do
-      apis_from_routes = Apipie::Extractor.apis_from_routes
-      apis_from_routes.each do |(controller, action), apis|
-        next if ignored.include?(controller)
-        next if ignored.include?("#{controller}##{action}")
-        Apipie::Extractor::Writer.update_action_description(controller.constantize, action) do |u|
-          u.update_apis(apis)
-        end
-      end
-    end
-  end
-
-  desc "Convert your examples from the old yaml into the new json format"
-  task :convert_examples => :environment do
-    yaml_examples_file = File.join(Rails.root, Apipie.configuration.doc_path, "apipie_examples.yml")
-    if File.exists?(yaml_examples_file)
-      #if SafeYAML gem is enabled, it will load examples as an array of Hash, instead of hash
-      if defined? SafeYAML
-        examples = YAML.load_file(yaml_examples_file, :safe=>false)
-      else
-        examples = YAML.load_file(yaml_examples_file)
-      end
-    else
-      examples = {}
-    end
-    Apipie::Extractor::Writer.write_recorded_examples(examples)
-  end
-
 end
diff --git a/lib/tasks/renderers/html.rake b/lib/tasks/renderers/html.rake
new file mode 100644
index 00000000..781c1549
--- /dev/null
+++ b/lib/tasks/renderers/html.rake
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+require 'fileutils'
+require 'apipie/render/html'
+
+namespace :apipie do
+  namespace :render do
+
+    desc "Generate static documentation"
+    # You can specify OUT=output_base_file to have the following structure:
+    #
+    #    output_base_file.html
+    #    output_base_file-onepage.html
+    #    output_base_file
+    #    | - resource1.html
+    #    | - resource1
+    #    | - | - method1.html
+    #    | - | - method2.html
+    #    | - resource2.html
+    #
+    # By default OUT="#{Rails.root}/doc/apidoc"
+    task :html, [:version] => :environment do |t, args|
+      Apipie::Render.with_loaded_documentation do
+        args.with_defaults(:version => Apipie.configuration.default_version)
+        out = ENV["OUT"] || File.join(::Rails.root, Apipie.configuration.doc_path, 'apidoc')
+        subdir = File.basename(out)
+        Apipie::Render::HTML.copy_jscss(out)
+        Apipie.configuration.version_in_url = false
+        ([nil] + Apipie.configuration.languages).each do |lang|
+          I18n.locale = lang || Apipie.configuration.default_locale
+          Apipie.url_prefix = "./#{subdir}"
+          doc = Apipie.to_json(args[:version], nil, nil, lang)
+          doc[:docs][:link_extension] = "#{Apipie::Render.lang_ext(lang)}.html"
+          Apipie::Render::HTML.one_page(out, doc, lang)
+          Apipie::Render::HTML.plain_page(out, doc, lang)
+          Apipie::Render::HTML.index_page(out, doc, false, false, lang)
+          Apipie.url_prefix = "../#{subdir}"
+          Apipie::Render::HTML.resource_pages(args[:version], out, doc, false, lang)
+          Apipie.url_prefix = "../../#{subdir}"
+          Apipie::Render::HTML.method_pages(args[:version], out, doc, false, lang)
+        end
+      end
+    end
+
+  end
+
+end
diff --git a/lib/tasks/renderers/json.rake b/lib/tasks/renderers/json.rake
new file mode 100644
index 00000000..8b156dcf
--- /dev/null
+++ b/lib/tasks/renderers/json.rake
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+require 'fileutils'
+require 'apipie/render/json'
+
+namespace :apipie do
+
+  namespace :render do
+
+    desc "Generate static documentation json"
+    task :json, [:version] => :environment do |t, args|
+      Apipie::Render.with_loaded_documentation do
+        args.with_defaults(:version => Apipie.configuration.default_version)
+        out = ENV["OUT"] || File.join(::Rails.root, Apipie.configuration.doc_path, 'apidoc')
+        ([nil] + Apipie.configuration.languages).each do |lang|
+          doc = Apipie.to_json(args[:version], nil, nil, lang)
+          Apipie::Render::JSON.one_page(out, doc, lang)
+        end
+      end
+    end
+
+  end
+
+end
diff --git a/lib/tasks/renderers/markdown.rake b/lib/tasks/renderers/markdown.rake
new file mode 100644
index 00000000..244b42f4
--- /dev/null
+++ b/lib/tasks/renderers/markdown.rake
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+require 'fileutils'
+require 'apipie/render/markdown'
+
+namespace :apipie do
+
+  namespace :render do
+    desc "Generate static markdown documentation"
+    task :markdown, [:version] => :environment do |t, args|
+      Apipie::Render.with_loaded_documentation do
+        args.with_defaults(:version => Apipie.configuration.default_version)
+        out = ENV["OUT"] || File.join(::Rails.root, Apipie.configuration.doc_path, 'apidoc')
+        subdir = File.basename(out)
+        Apipie.configuration.version_in_url = false
+        ([nil] + Apipie.configuration.languages).each do |lang|
+          I18n.locale = lang || Apipie.configuration.default_locale
+          Apipie.url_prefix = "./#{subdir}"
+          doc = Apipie.to_json(args[:version], nil, nil, lang)
+          doc[:docs][:link_extension] = "#{Apipie::Render.lang_ext(lang)}.md"
+          Apipie::Render::Markdown.one_page(out, doc, lang)
+        end
+      end
+    end
+
+  end
+
+end
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 239a278d..8d83bb48 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -243,9 +243,10 @@ def reload_controllers
                                   :required => false,
                                   :allow_nil => true,
                                   :allow_blank => false,
+                                  :allowed => [],
                                   :metadata => nil,
                                   :show => true,
-                                  :expected_type => "hash",
+                                  :expected_type => 'object',
                                   :validations => [])
           end
 
@@ -439,12 +440,12 @@ def reload_controllers
     it "should contain possible errors description" do
       a = Apipie.get_method_description(UsersController, :show)
 
-      expect(a.errors[0].code).to eq(500)
-      expect(a.errors[0].description).to include("crashed")
-      expect(a.errors[1].code).to eq(401)
-      expect(a.errors[1].description).to eq("Unauthorized")
-      expect(a.errors[2].code).to eq(404)
-      expect(a.errors[2].description).to eq("Not Found")
+      expect(a.responses[0].code).to eq(500)
+      expect(a.responses[0].body).to include("crashed")
+      expect(a.responses[1].code).to eq(401)
+      expect(a.responses[1].body).to eq("Unauthorized")
+      expect(a.responses[2].code).to eq(404)
+      expect(a.responses[2].body).to eq("Not Found")
     end
 
     it "should contain all params description" do
@@ -521,80 +522,109 @@ def reload_controllers
 
     it "should be described by valid json" do
       json = Apipie[UsersController, :two_urls].to_json
-      expected_hash = {
-        :errors => [{:code=>404, :description=>"Missing", :metadata => {:some => "metadata"}},
-                    {:code=>500, :description=>"Server crashed for some <%= reason %>"}],
-        :examples => [],
-        :doc_url => "#{Apipie.configuration.doc_base_url}/development/users/two_urls",
-        :formats=>["json"],
-        :full_description => '',
-        :params => [{:full_name=>"oauth",
-                     :required=>false,
-                     :allow_nil => false,
-                     :allow_blank => false,
-                     :validator=>"Must be a String",
-                     :description=>"\n<p>Authorization</p>\n",
-                     :name=>"oauth",
-                     :show=>true,
-                     :expected_type=>"string"},
-                    {:validator=>"Must be a Hash",
-                     :description=>"\n<p>Deprecated parameter not documented</p>\n",
-                     :expected_type=>"hash",
-                     :allow_nil=>false,
-                     :allow_blank => false,
-                     :name=>"legacy_param",
-                     :required=>false,
-                     :full_name=>"legacy_param",
-                     :show=>false,
-                     :params=>
-                      [{:validator=>"Must be a Hash",
-                        :description=>"\n<p>Param description for all methods</p>\n",
-                        :expected_type=>"hash",
-                        :allow_nil=>false,
-                       :allow_blank => false,
-                        :name=>"resource_param",
-                        :required=>false,
-                        :full_name=>"resource_param",
-                        :show=>true,
-                        :params=>
-                        [{:required=>true,
-                          :allow_nil => false,
-                          :allow_blank => false,
-                          :validator=>"Must be a String",
-                          :description=>"\n<p>Username for login</p>\n",
-                          :name=>"ausername", :full_name=>"resource_param[ausername]",
-                          :show=>true,
-                          :expected_type=>"string"},
-                         {:required=>true,
-                          :allow_nil => false,
-                          :allow_blank => false,   
-                          :validator=>"Must be a String",
-                          :description=>"\n<p>Password for login</p>\n",
-                          :name=>"apassword", :full_name=>"resource_param[apassword]",
-                          :show=>true,
-                          :expected_type=>"string"}
-                        ]}
-                      ]
-                    },
-                    {:required=>false, :validator=>"Parameter has to be Integer.",
-                     :allow_nil => false,
-                     :allow_blank => false,
-                     :description=>"\n<p>Company ID</p>\n",
-                     :name=>"id", :full_name=>"id",
-                     :show=>true,
-                     :expected_type=>"numeric"},
-       ],
-        :name => 'two_urls',
-        :show => true,
-        :apis => [
+      expected_hash = expected_hash = {
+        responses: [
+          {
+            code: 404,
+            body: 'Not Found',
+            metadata:
+            {
+              some: 'metadata'
+            }
+          },
+          {
+            code: 500,
+            body: 'Server crashed for some <%= reason %>'
+          }
+        ],
+        examples: [],
+        doc_url: "#{Apipie.configuration.doc_base_url}/development/users/two_urls",
+        formats: ['json'],
+        full_description: '',
+        params: [
+          {
+            full_name: 'oauth',
+            required: false,
+            allow_nil: false,
+            allow_blank: false,
+            validator: 'Must be a String',
+            description: "\n<p>Authorization</p>\n",
+            name: 'oauth',
+            show: true,
+            expected_type: 'string'
+          },
+          {
+            validator: 'Must be a Hash',
+            description: "\n<p>Deprecated parameter not documented</p>\n",
+            expected_type: 'object',
+            allow_nil: false,
+            allow_blank: false,
+            name: 'legacy_param',
+            required: false,
+            full_name: 'legacy_param',
+            show: false,
+            params: [
+              {
+                validator: 'Must be a Hash',
+                description: "\n<p>Param description for all methods</p>\n",
+                expected_type: 'object',
+                allow_nil: false,
+                allow_blank: false,
+                name: 'resource_param',
+                required: false,
+                full_name: 'resource_param',
+                show: true,
+                params: [
+                  {
+                    required: true,
+                    allow_nil: false,
+                    allow_blank: false,
+                    validator: 'Must be a String',
+                    description: "\n<p>Username for login</p>\n",
+                    name: 'ausername',
+                    full_name: 'resource_param[ausername]',
+                    show: true,
+                    expected_type: 'string'
+                  },
+                  {
+                    required: true,
+                    allow_nil: false,
+                    allow_blank: false,
+                    validator: 'Must be a String',
+                    description: "\n<p>Password for login</p>\n",
+                    name: 'apassword',
+                    full_name: 'resource_param[apassword]',
+                    show: true,
+                    expected_type: 'string'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            required: false,
+            validator: 'Parameter has to be Integer.',
+            allow_nil: false,
+            allow_blank: false,
+            description: "\n<p>Company ID</p>\n",
+            name: 'id',
+            full_name: 'id',
+            show: true,
+            expected_type: 'number'
+          }
+        ],
+        name: 'two_urls',
+        show: true,
+        apis: [
+          {
+            http_method: 'GET',
+            short_description: 'Get company users',
+            api_url: "#{Apipie.api_base_url}/company_users"
+          },
           {
-            :http_method => 'GET',
-            :short_description => 'Get company users',
-            :api_url => "#{Apipie.api_base_url}/company_users"
-          },{
-            :http_method => 'GET',
-            :short_description => 'Get users working in given company',
-            :api_url =>"#{Apipie.api_base_url}/company/:id/users"
+            http_method: 'GET',
+            short_description: 'Get users working in given company',
+            api_url: "#{Apipie.api_base_url}/company/:id/users"
           }
         ]
       }
diff --git a/spec/dummy/app/controllers/users_controller.rb b/spec/dummy/app/controllers/users_controller.rb
index 7b70cea3..19c31b38 100644
--- a/spec/dummy/app/controllers/users_controller.rb
+++ b/spec/dummy/app/controllers/users_controller.rb
@@ -12,7 +12,7 @@ class UsersController < ApplicationController
       end
     end
     api_version "development"
-    error 404, "Missing", :meta => {:some => "metadata"}
+    error 404, "Not Found", :meta => {:some => "metadata"}
     error 500, "Server crashed for some <%= reason %>"
     meta :new_style => true, :author => { :name => 'John', :surname => 'Doe' }
     description <<-EOS
@@ -172,7 +172,7 @@ class UsersController < ApplicationController
   show false
   formats ['json', 'jsonp']
   error 401, "Unauthorized"
-  error :code => 404, :description => "Not Found"
+  error 404, "Not Found"
   param :id, Integer, :desc => "user id", :required => true
   param :session, String, :desc => "user is logged in", :required => true, :missing_message => lambda { "session_parameter_is_required" }
   param :regexp_param, /^[0-9]* years/, :desc => "regexp param"
@@ -242,8 +242,8 @@ def admin_create
   end
 
   api :GET, "/users", "List users"
-  error :code => 401, :desc => "Unauthorized"
-  error :code => 404, :desc => "Not Found"
+  error 401, "Unauthorized"
+  error 404, "Not Found"
   desc "List all users."
   param :oauth, nil,
         :desc => "Hide this global param (eg dont need auth here)"
diff --git a/spec/dummy/config/initializers/apipie.rb b/spec/dummy/config/initializers/apipie.rb
index a2546bcc..73795de8 100644
--- a/spec/dummy/config/initializers/apipie.rb
+++ b/spec/dummy/config/initializers/apipie.rb
@@ -50,7 +50,7 @@
   # set default version info, to describe specific version use
   # config.app_info[version] = description
   # or put this in your base or application controller
-  config.app_info = "Dummy app for testing"
+  config.app_info = "Dummy app for development"
 
   # show debug informations
   config.debug = false
@@ -103,6 +103,6 @@ def description
   end
 
   def expected_type
-    'numeric'
+    'number'
   end
 end
diff --git a/spec/lib/rake_spec.rb b/spec/lib/renderers/html_spec.rb
similarity index 53%
rename from spec/lib/rake_spec.rb
rename to spec/lib/renderers/html_spec.rb
index a0d2f86a..be2b2c3a 100644
--- a/spec/lib/rake_spec.rb
+++ b/spec/lib/renderers/html_spec.rb
@@ -1,6 +1,6 @@
 require 'spec_helper'
 
-describe 'rake tasks' do
+describe 'rake render' do
   include_context "rake"
 
   let(:doc_path)  { "user_specified_doc_path" }
@@ -11,7 +11,7 @@
     subject.invoke(*task_args)
   end
 
-  describe 'static pages' do
+  describe 'html pages' do
 
     let(:apidoc_html) do
       File.read("#{doc_output}.html")
@@ -22,11 +22,11 @@
     end
 
     after do
-      Dir["#{doc_output}*"].each { |static_file| FileUtils.rm_rf(static_file) }
+      Dir["#{doc_output}*"].each { |html_file| FileUtils.rm_rf(html_file) }
     end
 
-    describe 'apipie:static' do
-      it "generates static files for the default version of apipie docs" do
+    describe 'apipie:render:html' do
+      it "generates html files for the default version of apipie docs" do
         expect(apidoc_html).to match(/Test app #{Apipie.configuration.default_version}/)
       end
 
@@ -36,8 +36,8 @@
       end
     end
 
-    describe 'apipie:static[2.0]' do
-      it "generates static files for the default version of apipie docs" do
+    describe 'apipie:render:html[2.0]' do
+      it "generates html files for the default version of apipie docs" do
         expect(apidoc_html).to match(/Test app 2.0/)
       end
 
@@ -48,24 +48,4 @@
     end
   end
 
-  describe 'apipie:cache' do
-    let(:cache_output) do
-      File.join(::Rails.root, 'public', 'apipie-cache')
-    end
-
-    let(:apidoc_html) do
-      File.read("#{cache_output}.html")
-    end
-
-    after do
-      Dir["#{cache_output}*"].each { |static_file| FileUtils.rm_rf(static_file) }
-    end
-
-    it "generates cache files" do
-      expect(File).to exist(File.join(cache_output, 'apidoc.html'))
-      expect(File).to exist(File.join(cache_output, 'apidoc/development.html'))
-      expect(File).to exist(File.join(cache_output, 'apidoc/development/users.html'))
-
-    end
-  end
 end
diff --git a/spec/lib/renderers/json_spec.rb b/spec/lib/renderers/json_spec.rb
new file mode 100644
index 00000000..af9d612a
--- /dev/null
+++ b/spec/lib/renderers/json_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe 'rake render' do
+  include_context "rake"
+
+  let(:doc_path)  { "user_specified_doc_path" }
+
+  before do
+    Apipie.configuration.doc_path = doc_path
+    allow(Apipie).to receive(:reload_documentation)
+    subject.invoke(*task_args)
+  end
+
+  describe 'json pages' do
+
+    let(:json_doc) do
+      JSON.parse(File.read(json_path))
+    end
+
+    let(:json_path) do
+      "#{doc_output}/schema_apipie.json"
+    end
+
+    let(:doc_output) do
+      File.join(::Rails.root, doc_path, 'apidoc')
+    end
+
+    after do
+      Dir["#{doc_output}*"].each { |json_file| FileUtils.rm_rf(json_file) }
+    end
+
+    describe 'apipie:render:json' do
+      it "generates json files for the default version of apipie docs" do
+        expect(File).to exist(json_path)
+        expect(json_doc['docs']['name']).to match(/Test app/)
+        expect(json_doc['docs']['info']).to match(/#{Apipie.configuration.default_version}/)
+      end
+
+    end
+
+    describe 'apipie:render:json[2.0]' do
+      it "generates json files for the default version of apipie docs" do
+        expect(File).to exist(json_path)
+        expect(json_doc['docs']['name']).to match(/Test app/)
+        expect(json_doc['docs']['info']).to match(/2.0/)
+      end
+    end
+  end
+
+end
diff --git a/spec/lib/renderers/markdown_spec.rb b/spec/lib/renderers/markdown_spec.rb
new file mode 100644
index 00000000..e47eb408
--- /dev/null
+++ b/spec/lib/renderers/markdown_spec.rb
@@ -0,0 +1,45 @@
+require 'spec_helper'
+
+describe 'rake render' do
+  include_context "rake"
+
+  let(:doc_path)  { "user_specified_doc_path" }
+
+  before do
+    Apipie.configuration.doc_path = doc_path
+    allow(Apipie).to receive(:reload_documentation)
+    subject.invoke(*task_args)
+  end
+
+  describe 'markdown pages' do
+
+    let(:apidoc_md) do
+      File.read("#{doc_output}/apidoc-onepage.md")
+    end
+
+    let(:doc_output) do
+      File.join(::Rails.root, doc_path)
+    end
+
+    after do
+      Dir["#{doc_output}*"].each { |markdown_file| FileUtils.rm_rf(markdown_file) }
+    end
+
+    describe 'apipie:render:markdown' do
+      it "generates markdown files for the default version of apipie docs" do
+        expect(apidoc_md).to match(/# Test app/)
+        expect(apidoc_md).to match(/Dummy app for #{Apipie.configuration.default_version}/)
+      end
+
+    end
+
+    describe 'apipie:render:markdown[2.0]' do
+      it "generates markdown files for the default version of apipie docs" do
+        expect(apidoc_md).to match(/# Test app/)
+        expect(apidoc_md).to match(/Version 2.0 description/)
+      end
+
+    end
+  end
+
+end
diff --git a/spec/lib/validator_spec.rb b/spec/lib/validator_spec.rb
index badcc346..01cc8442 100644
--- a/spec/lib/validator_spec.rb
+++ b/spec/lib/validator_spec.rb
@@ -20,9 +20,9 @@
 
     context "expected type" do
 
-      it "should return hash for type Hash" do
+      it "should return object for type Hash" do
         validator = Apipie::Validator::TypeValidator.new(params_desc, Hash)
-        expect(validator.expected_type).to eq('hash')
+        expect(validator.expected_type).to eq('object')
       end
 
       it "should return array for type Array" do
@@ -30,9 +30,9 @@
         expect(validator.expected_type).to eq('array')
       end
 
-      it "should return numeric for type Numeric" do
+      it "should return number for type Numeric" do
         validator = Apipie::Validator::TypeValidator.new(params_desc, Numeric)
-        expect(validator.expected_type).to eq('numeric')
+        expect(validator.expected_type).to eq('number')
       end
 
       it "should return string by default" do
diff --git a/spec/support/rake.rb b/spec/support/rake.rb
index fd8ed5ab..0f4170fb 100644
--- a/spec/support/rake.rb
+++ b/spec/support/rake.rb
@@ -5,16 +5,23 @@
   let(:rake)      { Rake::Application.new }
   let(:task_name) { rake.parse_task_string(self.class.description).first }
   let(:task_args) { rake.parse_task_string(self.class.description).last }
-  let(:task_path) { "lib/tasks/apipie" }
+  let(:task_path) { "lib/tasks" }
   subject         { rake[task_name] }
 
   def loaded_files_excluding_current_rake_file
     $".reject {|file| file == File.expand_path("#{task_path}.rake", APIPIE_ROOT) }
+    ($" - rake_files.map(&File.method(:realpath)))
+  end
+
+  def rake_files
+    Dir["#{task_path}/**/*.rake"]
   end
 
   before do
     Rake.application = rake
-    Rake.application.rake_require(task_path, [APIPIE_ROOT], loaded_files_excluding_current_rake_file)
+    rake_files.each do |file|
+      Rake.application.rake_require(file.gsub(/.rake$/, ''), [APIPIE_ROOT], loaded_files_excluding_current_rake_file)
+    end
 
     Rake::Task.define_task(:environment)
   end