Skip to content

Commit 29362c9

Browse files
committed
Fix: Render OpenAPI Markdown with RedCarpet
As noted in [0], the ability to render a CommonMark document through OpenAPI specifications' `info.description` is breaking due to how the Table of Contents code works. We'd assumed that the `id` would always be set on headers - by the `TechDocsHTMLRenderer` - but as we've been rendering the markdown through `openapi3_parser`'s CommonMark implementation, these IDs are not being populated. Until the `openapi3_parser` gem supports making this configurable, which is unlikely, due to the way that CommonMark doesn't have this as a default extension, we can instead utilise our `TechDocsHTMLRenderer` to render the headings with IDs, as expected. To do this, we can create a new helper in `ApiReferenceRenderer` which will render the Markdown document as our custom Markdown, which requires we construct the `TechDocsHTMLRenderer` class, which needs the Middleman `ConfigContext` class injected in. As well as the original `info.description` that we'd planned to amend, we can also replace any other CommonMark->HTML rendering at the same time. This means that we won't be using CommonMark, as per the OpenAPI spec, and this is something we'll look to address in alphagov#282. The setup for our tests are now a little more complex, as we're not able to (easily) inject `RedCarpet`, so need to mock a bit more to make it work. [0]: alphagov/tdt-documentation#156
1 parent ee6b8aa commit 29362c9

File tree

7 files changed

+38
-9
lines changed

7 files changed

+38
-9
lines changed

lib/govuk_tech_docs/api_reference/api_reference_renderer.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class Renderer
77
def initialize(app, document)
88
@app = app
99
@document = document
10+
@redcarpet = build_redcarpet(app)
1011

1112
# Load template files
1213
@template_api_full = get_renderer("api_reference_full.html.erb")
@@ -137,6 +138,11 @@ def schema_properties(schema_data)
137138

138139
private
139140

141+
def build_redcarpet(app)
142+
renderer = GovukTechDocs::TechDocsHTMLRenderer.new(context: app.config_context)
143+
Redcarpet::Markdown.new(renderer)
144+
end
145+
140146
def get_renderer(file)
141147
template_path = File.join(File.dirname(__FILE__), "templates/" + file)
142148
template = File.open(template_path, "r").read
@@ -159,6 +165,10 @@ def get_schema_link(schema)
159165
id = "schema-#{schema.name.parameterize}"
160166
"<a href='\##{id}'>#{schema.name}</a>"
161167
end
168+
169+
def render_markdown(text)
170+
@redcarpet.render(text) if text
171+
end
162172
end
163173
end
164174
end

lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<h1 id="<%= info.title.parameterize %>"><%= info.title %> v<%= info.version %></h1>
2-
<%= info.description_html %>
2+
<%= render_markdown(info.description) %>
33

44
<%# OpenAPI files default to having a single server of URL "/" %>
55
<% if servers.length > 1 || servers[0].url != "/" %>

lib/govuk_tech_docs/api_reference/templates/operation.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<p><em><%= operation.summary %></em></p>
44
<% end %>
55
<% if operation.description %>
6-
<%= operation.description_html %>
6+
<%= render_markdown(operation.description) %>
77
<% end %>
88

99
<%= parameters %>

lib/govuk_tech_docs/api_reference/templates/parameters.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<td><%= parameter.in %></td>
1212
<td><%= parameter.schema.type %></td>
1313
<td><%= parameter.required? %></td>
14-
<td><%= parameter.description_html %>
14+
<td><%= render_markdown(parameter.description) %>
1515
<% if parameter.schema.enum %>
1616
<p>Available items:</p>
1717
<ul>

lib/govuk_tech_docs/api_reference/templates/responses.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<tr>
1010
<td><%= key %></td>
1111
<td>
12-
<%= response.description_html %>
12+
<%= render_markdown(response.description) %>
1313
<% if response.content['application/json']
1414
if response.content['application/json']["example"]
1515
request_body = json_prettyprint(response.content['application/json']["example"])

lib/govuk_tech_docs/api_reference/templates/schema.html.erb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<h3 id="<%= id = 'schema-' + title; id.parameterize %>"><%= title %></h3>
2-
<%= schema.description_html %>
2+
<%= render_markdown(schema.description) %>
33
<% if properties.any? %>
44
<table class='<%= id.parameterize %>'>
55
<thead>
@@ -11,7 +11,7 @@
1111
<td><%= property_name %></td>
1212
<td><%= property_attributes.type %></td>
1313
<td><%= schema.requires?(property_name) %></td>
14-
<td><%= property_attributes.description_html %></td>
14+
<td><%= render_markdown(property_attributes.description) %></td>
1515
<td>
1616
<%=
1717
linked_schema = property_attributes

spec/api_reference/renderer_spec.rb

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,34 @@
1111
"info": {
1212
"title": "title",
1313
"version": "0.0.1",
14+
"description": "# This is a header\n\nAnd a piece of _text_",
1415
},
1516
"paths": {},
1617
}
18+
@app = double("Middleman::Application")
19+
@config_context = double("Middleman::ConfigContext")
20+
allow(@app).to receive(:config_context).and_return @config_context
21+
allow(@config_context).to receive(:app).and_return @app
22+
allow(@app).to receive(:api) { |arg| arg }
23+
end
24+
25+
it "renders the description" do
26+
document = Openapi3Parser.load(@spec)
27+
28+
render = described_class.new(@app, document)
29+
rendered = render.api_full(document.info, document.servers)
30+
31+
rendered = Capybara::Node::Simple.new(rendered)
32+
expect(rendered).to have_css("h1", exact_text: "This is a header")
33+
expect(rendered).to have_css("h1#this-is-a-header")
34+
expect(rendered).to have_css("p", exact_text: "And a piece of text")
35+
expect(rendered).to have_css("p>em", exact_text: "text")
1736
end
1837

1938
it "renders no servers" do
2039
document = Openapi3Parser.load(@spec)
2140

22-
render = described_class.new(nil, document)
41+
render = described_class.new(@app, document)
2342
rendered = render.api_full(document.info, document.servers)
2443

2544
rendered = Capybara::Node::Simple.new(rendered)
@@ -33,7 +52,7 @@
3352
]
3453
document = Openapi3Parser.load(@spec)
3554

36-
render = described_class.new(nil, document)
55+
render = described_class.new(@app, document)
3756
rendered = render.api_full(document.info, document.servers)
3857

3958
rendered = Capybara::Node::Simple.new(rendered)
@@ -49,7 +68,7 @@
4968
]
5069
document = Openapi3Parser.load(@spec)
5170

52-
render = described_class.new(nil, document)
71+
render = described_class.new(@app, document)
5372
rendered = render.api_full(document.info, document.servers)
5473

5574
rendered = Capybara::Node::Simple.new(rendered)

0 commit comments

Comments
 (0)