Skip to content

Commit eb8db63

Browse files
committed
Removes utf-8 from JSON requests because it's redundant
JSON requests should use UTF-8 by default according to http://www.ietf.org/rfc/rfc4627.txt, so we will remove `charset=utf-8` when we find it to avoid redundancy. In the process, I moved code that was only used by APIB into the APIB classes, such as exposing `content_type` to the templates. If I changed the `content-type` for all templates it would break unrelated things. Connects to #235.
1 parent 2f894bb commit eb8db63

File tree

4 files changed

+166
-30
lines changed

4 files changed

+166
-30
lines changed

features/api_blueprint_documentation.feature

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ Feature: Generate API Blueprint documentation from test examples
131131
put 'Updates a single order' do
132132
explanation "This is used to update orders."
133133
134-
header "Content-Type", "application/json"
134+
header "Content-Type", "application/json; charset=utf-16"
135135
136136
context "with a valid id" do
137137
let(:id) { 1 }
@@ -406,11 +406,11 @@ Feature: Generate API Blueprint documentation from test examples
406406
407407
### Updates a single order [PUT]
408408
409-
+ Request Invalid request (application/json)
409+
+ Request Invalid request (application/json; charset=utf-16)
410410
411411
+ Headers
412412
413-
Content-Type: application/json
413+
Content-Type: application/json; charset=utf-16
414414
Host: example.org
415415
416416
+ Response 400 (application/json)
@@ -420,11 +420,11 @@ Feature: Generate API Blueprint documentation from test examples
420420
Content-Type: application/json
421421
Content-Length: 0
422422
423-
+ Request Update an order (application/json)
423+
+ Request Update an order (application/json; charset=utf-16)
424424
425425
+ Headers
426426
427-
Content-Type: application/json
427+
Content-Type: application/json; charset=utf-16
428428
Host: example.org
429429
430430
+ Body

lib/rspec_api_documentation/views/api_blueprint_example.rb

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,22 @@ def parameters
2020

2121
def requests
2222
super.map do |request|
23-
request[:request_body] = body_to_json(request, :request)
24-
request[:response_body] = body_to_json(request, :response)
23+
request[:request_headers_text] = remove_utf8_for_json(request[:request_headers_text])
24+
request[:request_headers_text] = indent(request[:request_headers_text])
25+
request[:request_content_type] = content_type(request[:request_headers])
26+
request[:request_content_type] = remove_utf8_for_json(request[:request_content_type])
27+
request[:request_body] = body_to_json(request, :request)
28+
request[:request_body] = indent(request[:request_body])
2529

26-
request[:request_body] = indent(request[:request_body])
27-
request[:request_headers_text] = indent(request[:request_headers_text])
28-
request[:response_body] = indent(request[:response_body])
30+
request[:response_headers_text] = remove_utf8_for_json(request[:response_headers_text])
2931
request[:response_headers_text] = indent(request[:response_headers_text])
32+
request[:response_content_type] = content_type(request[:response_headers])
33+
request[:response_content_type] = remove_utf8_for_json(request[:response_content_type])
34+
request[:response_body] = body_to_json(request, :response)
35+
request[:response_body] = indent(request[:response_body])
36+
37+
request[:has_request?] = has_request?(request)
38+
request[:has_response?] = has_response?(request)
3039
request
3140
end
3241
end
@@ -37,11 +46,21 @@ def extension
3746

3847
private
3948

49+
def has_request?(metadata)
50+
metadata.any? do |key, value|
51+
[:request_body, :request_headers, :request_content_type].include?(key) && value
52+
end
53+
end
54+
55+
def has_response?(metadata)
56+
metadata.any? do |key, value|
57+
[:response_status, :response_body, :response_headers, :response_content_type].include?(key) && value
58+
end
59+
end
60+
4061
def indent(string)
4162
string.tap do |str|
42-
if str
43-
str.gsub!(/\n/, "\n" + (" " * TOTAL_SPACES_INDENTATION))
44-
end
63+
str.gsub!(/\n/, "\n" + (" " * TOTAL_SPACES_INDENTATION)) if str
4564
end
4665
end
4766

@@ -52,12 +71,34 @@ def body_to_json(http_call, message_direction)
5271
content_type = http_call["#{message_direction}_content_type".to_sym]
5372
body = http_call["#{message_direction}_body".to_sym] # e.g request_body
5473

55-
if content_type =~ /application\/.*json/ && body
74+
if json?(content_type) && body
5675
body = JSON.pretty_generate(JSON.parse(body))
5776
end
5877

5978
body
6079
end
80+
81+
# JSON requests should use UTF-8 by default according to
82+
# http://www.ietf.org/rfc/rfc4627.txt, so we will remove `charset=utf-8`
83+
# when we find it to remove noise.
84+
def remove_utf8_for_json(headers)
85+
return unless headers
86+
headers
87+
.split("\n")
88+
.map { |header|
89+
header.gsub!(/; *charset=utf-8/, "") if json?(header)
90+
header
91+
}
92+
.join("\n")
93+
end
94+
95+
def content_type(headers)
96+
headers && headers.fetch("Content-Type", nil)
97+
end
98+
99+
def json?(string)
100+
string =~ /application\/.*json/
101+
end
61102
end
62103
end
63104
end

lib/rspec_api_documentation/views/markup_example.rb

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,9 @@ def response_fields
4747

4848
def requests
4949
super.map do |hash|
50-
hash[:request_content_type] = content_type(hash[:request_headers])
5150
hash[:request_headers_text] = format_hash(hash[:request_headers])
5251
hash[:request_query_parameters_text] = format_hash(hash[:request_query_parameters])
53-
hash[:response_content_type] = content_type(hash[:response_headers])
5452
hash[:response_headers_text] = format_hash(hash[:response_headers])
55-
hash[:has_request?] = has_request?(hash)
56-
hash[:has_response?] = has_response?(hash)
5753
if @host
5854
if hash[:curl].is_a? RspecApiDocumentation::Curl
5955
hash[:curl] = hash[:curl].output(@host, @filter_headers)
@@ -71,18 +67,6 @@ def extension
7167

7268
private
7369

74-
def has_request?(metadata)
75-
metadata.any? do |key, value|
76-
[:request_body, :request_headers, :request_content_type].include?(key) && value
77-
end
78-
end
79-
80-
def has_response?(metadata)
81-
metadata.any? do |key, value|
82-
[:response_status, :response_body, :response_headers, :response_content_type].include?(key) && value
83-
end
84-
end
85-
8670
def format_hash(hash = {})
8771
return nil unless hash.present?
8872
hash.collect do |k, v|
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# -*- coding: utf-8 -*-
2+
require 'spec_helper'
3+
4+
describe RspecApiDocumentation::Views::ApiBlueprintExample do
5+
let(:metadata) { { :resource_name => "Orders" } }
6+
let(:group) { RSpec::Core::ExampleGroup.describe("Orders", metadata) }
7+
let(:rspec_example) { group.example("Ordering a cup of coffee") {} }
8+
let(:rad_example) do
9+
RspecApiDocumentation::Example.new(rspec_example, configuration)
10+
end
11+
let(:configuration) { RspecApiDocumentation::Configuration.new }
12+
let(:html_example) { described_class.new(rad_example, configuration) }
13+
14+
let(:content_type) { "application/json; charset=utf-8" }
15+
let(:requests) do
16+
[{
17+
request_body: "{}",
18+
request_headers: {
19+
"Content-Type" => content_type,
20+
"Another" => "header; charset=utf-8"
21+
},
22+
request_content_type: "",
23+
response_body: "{}",
24+
response_headers: {
25+
"Content-Type" => content_type,
26+
"Another" => "header; charset=utf-8"
27+
},
28+
response_content_type: ""
29+
}]
30+
end
31+
32+
before do
33+
rspec_example.metadata[:requests] = requests
34+
end
35+
36+
subject(:view) { described_class.new(rad_example, configuration) }
37+
38+
describe '#requests' do
39+
describe 'request_content_type' do
40+
subject { view.requests[0][:request_content_type] }
41+
42+
context 'when charset=utf-8 is present' do
43+
it "just strips that because it's the default for json" do
44+
expect(subject).to eq "application/json"
45+
end
46+
end
47+
48+
context 'when charset=utf-16 is present' do
49+
let(:content_type) { "application/json; charset=utf-16" }
50+
51+
it "keeps that because it's NOT the default for json" do
52+
expect(subject).to eq "application/json; charset=utf-16"
53+
end
54+
end
55+
end
56+
57+
describe 'request_headers_text' do
58+
subject { view.requests[0][:request_headers_text] }
59+
60+
context 'when charset=utf-8 is present' do
61+
it "just strips that because it's the default for json" do
62+
expect(subject).to eq "Content-Type: application/json\n Another: header; charset=utf-8"
63+
end
64+
end
65+
66+
context 'when charset=utf-16 is present' do
67+
let(:content_type) { "application/json; charset=utf-16" }
68+
69+
it "keeps that because it's NOT the default for json" do
70+
expect(subject).to eq "Content-Type: application/json; charset=utf-16\n Another: header; charset=utf-8"
71+
end
72+
end
73+
end
74+
75+
describe 'response_content_type' do
76+
subject { view.requests[0][:response_content_type] }
77+
78+
context 'when charset=utf-8 is present' do
79+
it "just strips that because it's the default for json" do
80+
expect(subject).to eq "application/json"
81+
end
82+
end
83+
84+
context 'when charset=utf-16 is present' do
85+
let(:content_type) { "application/json; charset=utf-16" }
86+
87+
it "keeps that because it's NOT the default for json" do
88+
expect(subject).to eq "application/json; charset=utf-16"
89+
end
90+
end
91+
end
92+
93+
describe 'response_headers_text' do
94+
subject { view.requests[0][:response_headers_text] }
95+
96+
context 'when charset=utf-8 is present' do
97+
it "just strips that because it's the default for json" do
98+
expect(subject).to eq "Content-Type: application/json\n Another: header; charset=utf-8"
99+
end
100+
end
101+
102+
context 'when charset=utf-16 is present' do
103+
let(:content_type) { "application/json; charset=utf-16" }
104+
105+
it "keeps that because it's NOT the default for json" do
106+
expect(subject).to eq "Content-Type: application/json; charset=utf-16\n Another: header; charset=utf-8"
107+
end
108+
end
109+
end
110+
end
111+
end

0 commit comments

Comments
 (0)