From 08159eb6200b3e7156e8b2c76a7cc7a6616748ea Mon Sep 17 00:00:00 2001 From: Ilya Bylich Date: Wed, 18 Mar 2015 21:13:13 +0300 Subject: [PATCH] Added support for defining headers for resources and api methods. --- app/views/apipie/apipies/_headers.html.erb | 26 ++++++++++ app/views/apipie/apipies/_method_detail.erb | 2 + app/views/apipie/apipies/resource.html.erb | 2 + config/locales/en.yml | 2 + lib/apipie/dsl_definition.rb | 19 ++++++- lib/apipie/method_description.rb | 6 ++- lib/apipie/resource_description.rb | 8 ++- spec/controllers/users_controller_spec.rb | 52 +++++++++++++++++++ .../dummy/app/controllers/users_controller.rb | 6 +++ 9 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 app/views/apipie/apipies/_headers.html.erb diff --git a/app/views/apipie/apipies/_headers.html.erb b/app/views/apipie/apipies/_headers.html.erb new file mode 100644 index 00000000..ff5528de --- /dev/null +++ b/app/views/apipie/apipies/_headers.html.erb @@ -0,0 +1,26 @@ +<% unless headers.blank? %> + <%= heading(t('apipie.headers'), h_level) %> + + + + + + + + + <% headers.each do |header| %> + + + + + <% end %> + +
<%= t('apipie.header_name') %><%= t('apipie.description') %>
+ <%= header[:name] %>
+ + <%= header[:options][:required] ? t('apipie.required') : t('apipie.optional') %> + +
+ <%= header[:description].html_safe %> +
+<% end %> diff --git a/app/views/apipie/apipies/_method_detail.erb b/app/views/apipie/apipies/_method_detail.erb index 431e828b..6c28dd1a 100644 --- a/app/views/apipie/apipies/_method_detail.erb +++ b/app/views/apipie/apipies/_method_detail.erb @@ -44,3 +44,5 @@ <% end %> + +<%= render(:partial => "headers", :locals => {:headers => method[:headers], :h_level => h_level }) %> diff --git a/app/views/apipie/apipies/resource.html.erb b/app/views/apipie/apipies/resource.html.erb index 0e88f5e6..d08a2931 100644 --- a/app/views/apipie/apipies/resource.html.erb +++ b/app/views/apipie/apipies/resource.html.erb @@ -32,6 +32,8 @@ <%= @resource[:formats].join(', ') %> <% end %> +<%= render(:partial => 'headers', :locals => { headers: @resource[:headers], h_level: 2 }) %> +
<% @resource[:methods].each do |m| %> diff --git a/config/locales/en.yml b/config/locales/en.yml index ef81df85..509f8b5b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -24,4 +24,6 @@ en: enable_javascript_html: Please enable JavaScript to view the %{comments_href}. comments_powered_by_disqus: comments powered by %{disqus} api_documentation: API documentation + headers: Headers + header_name: Header name diff --git a/lib/apipie/dsl_definition.rb b/lib/apipie/dsl_definition.rb index a31d6260..5d8d599a 100644 --- a/lib/apipie/dsl_definition.rb +++ b/lib/apipie/dsl_definition.rb @@ -25,6 +25,7 @@ def _apipie_dsl_data_init :api_from_routes => nil, :errors => [], :params => [], + :headers => [], :resouce_id => nil, :short_description => nil, :description => nil, @@ -129,7 +130,6 @@ def resource_description(options = {}, &block) #:doc: end Apipie.set_controller_versions(self, versions) end - end module Common @@ -268,6 +268,23 @@ 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 diff --git a/lib/apipie/method_description.rb b/lib/apipie/method_description.rb index 6f30a3d8..376630d5 100644 --- a/lib/apipie/method_description.rb +++ b/lib/apipie/method_description.rb @@ -17,7 +17,7 @@ def initialize(method, path, desc, options) end - attr_reader :full_description, :method, :resource, :apis, :examples, :see, :formats, :metadata + attr_reader :full_description, :method, :resource, :apis, :examples, :see, :formats, :metadata, :headers def initialize(method, resource, dsl_data) @method = method.to_s @@ -48,6 +48,7 @@ def initialize(method, resource, dsl_data) Apipie::ParamDescription.from_dsl_data(self, args) end @params_ordered = ParamDescription.unify(@params_ordered) + @headers = dsl_data[:headers] end def id @@ -142,7 +143,8 @@ def to_json(lang=nil) :params => params_ordered.map{ |param| param.to_json(lang) }.flatten, :examples => @examples, :metadata => @metadata, - :see => see.map(&:to_json) + :see => see.map(&:to_json), + :headers => headers } end diff --git a/lib/apipie/resource_description.rb b/lib/apipie/resource_description.rb index ef54b500..083d6c25 100644 --- a/lib/apipie/resource_description.rb +++ b/lib/apipie/resource_description.rb @@ -9,10 +9,12 @@ module Apipie # name - human readable alias of resource (Articles) # id - resouce name # formats - acceptable request/response format types + # headers - array of headers class ResourceDescription attr_reader :controller, :_short_description, :_full_description, :_methods, :_id, - :_path, :_name, :_params_args, :_errors_args, :_formats, :_parent, :_metadata + :_path, :_name, :_params_args, :_errors_args, :_formats, :_parent, :_metadata, + :_headers def initialize(controller, resource_name, dsl_data = nil, version = nil, &block) @@ -39,6 +41,7 @@ def update_from_dsl_data(dsl_data) @_params_args = dsl_data[:params] @_metadata = dsl_data[:meta] @_api_base_url = dsl_data[:api_base_url] + @_headers = dsl_data[:headers] if dsl_data[:app_info] Apipie.configuration.app_info[_version] = dsl_data[:app_info] @@ -105,7 +108,8 @@ def to_json(method_name = nil, lang = nil) :version => _version, :formats => @_formats, :metadata => @_metadata, - :methods => methods + :methods => methods, + :headers => _headers } end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index d5f11445..9066d2c4 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -35,6 +35,7 @@ def compare_hashes(h1, h2) methods.keys.should include(:create) methods.keys.should include(:update) methods.keys.should include(:two_urls) + methods.keys.should include(:action_with_headers) end it "should contain info about resource" do @@ -444,6 +445,57 @@ def reload_controllers a.instance_variable_get('@params_ordered').count.should == 9 end + context 'headers' do + context 'for methods' do + let(:expected_required_header) do + { + name: :RequredHeaderName, + description: 'Required header description', + options: { + required: true + } + } + end + + let(:expected_optional_header) do + { + name: :OptionalHeaderName, + description: 'Optional header description', + options: { + required: false + } + } + end + + it 'contains all headers description in method doc' do + headers = Apipie.get_method_description(UsersController, :action_with_headers).headers + headers.should be_an(Array) + + compare_hashes headers[0], expected_required_header + compare_hashes headers[1], expected_optional_header + end + end + + context 'for resource' do + let(:expected_resource_header) do + { + name: :CommonHeader, + description: 'Common header description', + options: { + required: true + } + } + end + + it 'contains all headers description in resource doc' do + headers = Apipie.get_resource_description(UsersController)._headers + headers.should be_an(Array) + + compare_hashes headers[0], expected_resource_header + end + end + end + it "should contain all api method description" do method_description = Apipie[UsersController, :two_urls] method_description.class.should be(Apipie::MethodDescription) diff --git a/spec/dummy/app/controllers/users_controller.rb b/spec/dummy/app/controllers/users_controller.rb index 50ae04b7..088e4011 100644 --- a/spec/dummy/app/controllers/users_controller.rb +++ b/spec/dummy/app/controllers/users_controller.rb @@ -39,6 +39,7 @@ class UsersController < ApplicationController By default, Rails will compile each template to a method in order to render it. When you alter a template, Rails will check the file's modification time and recompile it in development mode. EOS + header :CommonHeader, 'Common header description', required: true end description <<-eos @@ -278,4 +279,9 @@ def desc_from_file def create_route end + api :GET, '/users/action_with_headers' + header :RequredHeaderName, 'Required header description', required: true + header :OptionalHeaderName, 'Optional header description', required: false + def action_with_headers + end end