From f51707bd1aa0ef3585b620bcffc98a063fcd6b8d Mon Sep 17 00:00:00 2001 From: Ken Mayer <ken@pactapp.com> Date: Wed, 5 Mar 2014 22:08:55 -0800 Subject: [PATCH 1/3] Filter request and/or response headers by configuration New configuration variables: - response_headers_to_include - request_headers_to_include --- README.md | 8 +++++++- features/html_documentation.feature | 6 +++++- features/step_definitions/html_steps.rb | 9 +++++++++ lib/rspec_api_documentation/configuration.rb | 2 ++ lib/rspec_api_documentation/views/markup_example.rb | 11 +++++++++-- spec/configuration_spec.rb | 2 ++ 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 390bd05d..912a922a 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,13 @@ RspecApiDocumentation.configure do |config| # Allows you to filter out headers that are not needed in the cURL request, # such as "Host" and "Cookie". Set as an array. config.curl_headers_to_filter = nil - + + # By default, when these settings are nil, all headers are shown, + # which is sometimes too chatty. Setting the parameters to an + # array of headers will render *only* those headers. + config.request_headers_to_include = nil + config.response_headers_to_include = nil + # By default examples and resources are ordered by description. Set to true keep # the source order. config.keep_source_order = false diff --git a/features/html_documentation.feature b/features/html_documentation.feature index dfe4ffd1..f3b8be2f 100644 --- a/features/html_documentation.feature +++ b/features/html_documentation.feature @@ -21,6 +21,8 @@ Feature: Generate HTML documentation from test examples RspecApiDocumentation.configure do |config| config.app = App config.api_name = "Example API" + config.request_headers_to_include = %w[Cookie] + config.response_headers_to_include = %w[Content-Type] end resource "Greetings" do @@ -70,8 +72,9 @@ Feature: Generate HTML documentation from test examples And I navigate to "Greeting your favorite gem" Then I should see the route is "GET /greetings?target=rspec_api_documentation" And I should see the following request headers: - | Host | example.org | | Cookie | | + And I should not see the following request headers: + | Host | example.org | And I should see the following query parameters: | target | rspec_api_documentation | @@ -81,6 +84,7 @@ Feature: Generate HTML documentation from test examples Then I should see the response status is "200 OK" And I should see the following response headers: | Content-Type | application/json | + And I should not see the following response headers: | Content-Length | 35 | And I should see the following response body: """ diff --git a/features/step_definitions/html_steps.rb b/features/step_definitions/html_steps.rb index 5c812d36..60be4e28 100644 --- a/features/step_definitions/html_steps.rb +++ b/features/step_definitions/html_steps.rb @@ -26,6 +26,15 @@ end end +Then /^I should not see the following (request|response) headers:$/ do |part, table| + actual_headers = page.find("pre.#{part}.headers").text + expected_headers = table.raw.map { |row| row.join(": ") } + + expected_headers.each do |row| + actual_headers.should_not include(row.strip) + end +end + Then /^I should see the route is "([^"]*)"$/ do |route| page.should have_css(".request.route", :text => route) end diff --git a/lib/rspec_api_documentation/configuration.rb b/lib/rspec_api_documentation/configuration.rb index 94e99d2c..3afd896e 100644 --- a/lib/rspec_api_documentation/configuration.rb +++ b/lib/rspec_api_documentation/configuration.rb @@ -59,6 +59,8 @@ def self.add_setting(name, opts = {}) add_setting :keep_source_order, :default => false add_setting :api_name, :default => "API Documentation" add_setting :io_docs_protocol, :default => "http" + add_setting :request_headers_to_include, :default => nil + add_setting :response_headers_to_include, :default => nil def client_method=(new_client_method) RspecApiDocumentation::DSL::Resource.module_eval <<-RUBY diff --git a/lib/rspec_api_documentation/views/markup_example.rb b/lib/rspec_api_documentation/views/markup_example.rb index 40d3236a..406076fc 100644 --- a/lib/rspec_api_documentation/views/markup_example.rb +++ b/lib/rspec_api_documentation/views/markup_example.rb @@ -7,6 +7,8 @@ def initialize(example, configuration) @example = example @host = configuration.curl_host @filter_headers = configuration.curl_headers_to_filter + @request_headers_to_include = configuration.request_headers_to_include + @response_headers_to_include = configuration.response_headers_to_include self.template_path = configuration.template_path end @@ -30,9 +32,9 @@ def filename def requests super.map do |hash| - hash[:request_headers_text] = format_hash(hash[:request_headers]) + hash[:request_headers_text] = format_hash(filter_hash(hash[:request_headers], @request_headers_to_include)) hash[:request_query_parameters_text] = format_hash(hash[:request_query_parameters]) - hash[:response_headers_text] = format_hash(hash[:response_headers]) + hash[:response_headers_text] = format_hash(filter_hash(hash[:response_headers], @response_headers_to_include)) if @host if hash[:curl].is_a? RspecApiDocumentation::Curl hash[:curl] = hash[:curl].output(@host, @filter_headers) @@ -56,6 +58,11 @@ def format_hash(hash = {}) "#{k}: #{v}" end.join("\n") end + + def filter_hash(hash = {}, selection_set = nil) + return hash unless selection_set + hash.select{ |key, value| selection_set.include?(key) } + end end end end diff --git a/spec/configuration_spec.rb b/spec/configuration_spec.rb index 3458a361..f72f97c8 100644 --- a/spec/configuration_spec.rb +++ b/spec/configuration_spec.rb @@ -54,6 +54,8 @@ its(:api_name) { should == "API Documentation" } its(:client_method) { should == :client } its(:io_docs_protocol) { should == "http" } + its(:request_headers_to_include) { should be_nil } + its(:response_headers_to_include) { should be_nil } end describe "#define_groups" do From dd71da1ad4c3b93c1952860c502c0504d04f0832 Mon Sep 17 00:00:00 2001 From: Ken Mayer <ken@pactapp.com> Date: Wed, 5 Mar 2014 22:08:55 -0800 Subject: [PATCH 2/3] Filter request and/or response headers by configuration New configuration variables: - response_headers_to_include - request_headers_to_include --- features/combined_json.feature | 14 ++-- features/textile_documentation.feature | 10 +-- lib/rspec_api_documentation/example.rb | 24 +++++- .../views/markup_example.rb | 11 +-- spec/example_spec.rb | 78 +++++++++++++++++++ 5 files changed, 113 insertions(+), 24 deletions(-) diff --git a/features/combined_json.feature b/features/combined_json.feature index 6a6082a0..617a95b9 100644 --- a/features/combined_json.feature +++ b/features/combined_json.feature @@ -24,6 +24,8 @@ Feature: Combined text RspecApiDocumentation.configure do |config| config.app = App config.format = :combined_json + config.request_headers_to_include = %w[Host] + config.response_headers_to_include = %w[Content-Type] end resource "Greetings" do @@ -84,8 +86,7 @@ Feature: Combined text "request_path": "/greetings?target=rspec_api_documentation", "request_body": null, "request_headers": { - "Host": "example.org", - "Cookie": "" + "Host": "example.org" }, "request_query_parameters": { "target": "rspec_api_documentation" @@ -95,8 +96,7 @@ Feature: Combined text "response_status_text": "OK", "response_body": "Hello, rspec_api_documentation!", "response_headers": { - "Content-Type": "text/plain", - "Content-Length": "31" + "Content-Type": "text/plain" }, "response_content_type": "text/plain", "curl": null @@ -121,8 +121,7 @@ Feature: Combined text "request_path": "/greetings?target=Sam+%26+Eric", "request_body": null, "request_headers": { - "Host": "example.org", - "Cookie": "" + "Host": "example.org" }, "request_query_parameters": { "target": "Sam & Eric" @@ -132,8 +131,7 @@ Feature: Combined text "response_status_text": "OK", "response_body": "Hello, Sam & Eric!", "response_headers": { - "Content-Type": "text/plain", - "Content-Length": "18" + "Content-Type": "text/plain" }, "response_content_type": "text/plain", "curl": null diff --git a/features/textile_documentation.feature b/features/textile_documentation.feature index 9ddf25c0..1e4ebff8 100644 --- a/features/textile_documentation.feature +++ b/features/textile_documentation.feature @@ -45,6 +45,8 @@ Feature: Generate Textile documentation from test examples config.app = App config.api_name = "Example API" config.format = :textile + config.request_headers_to_include = %w[Content-Type Host] + config.response_headers_to_include = %w[Content-Type Content-Length] end resource 'Orders' do @@ -180,8 +182,7 @@ Feature: Generate Textile documentation from test examples h4. Headers <pre>Host: example.org - Content-Type: application/x-www-form-urlencoded - Cookie: </pre> + Content-Type: application/x-www-form-urlencoded</pre> h4. Route @@ -198,10 +199,7 @@ Feature: Generate Textile documentation from test examples h4. Headers <pre>Content-Type: text/html;charset=utf-8 - Content-Length: 0 - X-XSS-Protection: 1; mode=block - X-Content-Type-Options: nosniff - X-Frame-Options: SAMEORIGIN</pre> + Content-Length: 0</pre> h4. Status diff --git a/lib/rspec_api_documentation/example.rb b/lib/rspec_api_documentation/example.rb index 6062d7d9..7cd7d5d6 100644 --- a/lib/rspec_api_documentation/example.rb +++ b/lib/rspec_api_documentation/example.rb @@ -43,7 +43,29 @@ def explanation end def requests - metadata[:requests] || [] + filter_headers(metadata[:requests]) || [] + end + + private + + def filter_headers(requests) + requests = remap_headers(requests, :request_headers, configuration.request_headers_to_include) + requests = remap_headers(requests, :response_headers, configuration.response_headers_to_include) + requests + end + + def remap_headers(requests, key, headers_to_include) + requests.each.with_index do |request_hash, index| + next unless request_hash.key?(key) + headers = request_hash[key] + request_hash[key] = filter_hash(headers, headers_to_include) + requests[index] = request_hash + end + end + + def filter_hash(hash = {}, selection_set = nil) + return hash unless selection_set + hash.select{ |key, _| selection_set.include?(key) } end end end diff --git a/lib/rspec_api_documentation/views/markup_example.rb b/lib/rspec_api_documentation/views/markup_example.rb index 406076fc..40d3236a 100644 --- a/lib/rspec_api_documentation/views/markup_example.rb +++ b/lib/rspec_api_documentation/views/markup_example.rb @@ -7,8 +7,6 @@ def initialize(example, configuration) @example = example @host = configuration.curl_host @filter_headers = configuration.curl_headers_to_filter - @request_headers_to_include = configuration.request_headers_to_include - @response_headers_to_include = configuration.response_headers_to_include self.template_path = configuration.template_path end @@ -32,9 +30,9 @@ def filename def requests super.map do |hash| - hash[:request_headers_text] = format_hash(filter_hash(hash[:request_headers], @request_headers_to_include)) + hash[:request_headers_text] = format_hash(hash[:request_headers]) hash[:request_query_parameters_text] = format_hash(hash[:request_query_parameters]) - hash[:response_headers_text] = format_hash(filter_hash(hash[:response_headers], @response_headers_to_include)) + hash[:response_headers_text] = format_hash(hash[:response_headers]) if @host if hash[:curl].is_a? RspecApiDocumentation::Curl hash[:curl] = hash[:curl].output(@host, @filter_headers) @@ -58,11 +56,6 @@ def format_hash(hash = {}) "#{k}: #{v}" end.join("\n") end - - def filter_hash(hash = {}, selection_set = nil) - return hash unless selection_set - hash.select{ |key, value| selection_set.include?(key) } - end end end end diff --git a/spec/example_spec.rb b/spec/example_spec.rb index 858c44a2..932b1331 100644 --- a/spec/example_spec.rb +++ b/spec/example_spec.rb @@ -159,4 +159,82 @@ example.explanation.should == nil end end + + describe "request headers can be filtered" do + before do + configuration.request_headers_to_include = %w[Included] + metadata[:requests] = [ + { + :request_headers => { + "Included" => "data", + "Filtered" => "not seen" + }, + :request_method => "GET" + }, + { + :request_headers => { + "Included" => "data", + "Other" => "not seen" + }, + :request_method => "GET" + } + ] + end + + it "should filter out anything not explicitly mentioned" do + subject.requests.should == [ + { + :request_headers => { + "Included" => "data", + }, + :request_method => "GET" + }, + { + :request_headers => { + "Included" => "data", + }, + :request_method => "GET" + } + ] + end + end + + describe "response headers can be filtered" do + before do + configuration.response_headers_to_include = %w[Included] + metadata[:requests] = [ + { + :response_headers => { + "Included" => "data", + "Filtered" => "not seen" + }, + :request_method => "GET" + }, + { + :response_headers => { + "Included" => "data", + "Other" => "not seen" + }, + :request_method => "GET" + } + ] + end + + it "should filter out anything not explicitly mentioned" do + subject.requests.should == [ + { + :response_headers => { + "Included" => "data", + }, + :request_method => "GET" + }, + { + :response_headers => { + "Included" => "data", + }, + :request_method => "GET" + } + ] + end + end end From b2172684504dfb53c3690f2129b5b9b7e2f2aebd Mon Sep 17 00:00:00 2001 From: Ken Mayer <ken@pactapp.com> Date: Thu, 6 Mar 2014 12:14:26 -0800 Subject: [PATCH 3/3] Refactor --- lib/rspec_api_documentation/example.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/rspec_api_documentation/example.rb b/lib/rspec_api_documentation/example.rb index 7cd7d5d6..da7de75a 100644 --- a/lib/rspec_api_documentation/example.rb +++ b/lib/rspec_api_documentation/example.rb @@ -55,17 +55,13 @@ def filter_headers(requests) end def remap_headers(requests, key, headers_to_include) + return requests unless headers_to_include requests.each.with_index do |request_hash, index| next unless request_hash.key?(key) headers = request_hash[key] - request_hash[key] = filter_hash(headers, headers_to_include) + request_hash[key] = headers.select{ |key, _| headers_to_include.include?(key) } requests[index] = request_hash end end - - def filter_hash(hash = {}, selection_set = nil) - return hash unless selection_set - hash.select{ |key, _| selection_set.include?(key) } - end end end