From d6358f35f42b3abea1ff5bdde44f48e57685496b Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 23 Aug 2018 12:14:09 +0100 Subject: [PATCH 01/31] Moved rendering into a separate class --- lib/govuk_tech_docs.rb | 2 +- .../api_reference/api_reference.rb | 173 ------------------ .../api_reference/api_reference_extension.rb | 97 ++++++++++ .../api_reference/api_reference_renderer.rb | 90 +++++++++ .../templates/api_reference_full.html.erb | 2 +- .../api_reference/templates/path.html.erb | 4 +- .../api_reference/templates/schema.html.erb | 4 +- 7 files changed, 193 insertions(+), 179 deletions(-) delete mode 100644 lib/govuk_tech_docs/api_reference/api_reference.rb create mode 100644 lib/govuk_tech_docs/api_reference/api_reference_extension.rb create mode 100644 lib/govuk_tech_docs/api_reference/api_reference_renderer.rb diff --git a/lib/govuk_tech_docs.rb b/lib/govuk_tech_docs.rb index 79474236..41dfc6de 100644 --- a/lib/govuk_tech_docs.rb +++ b/lib/govuk_tech_docs.rb @@ -20,7 +20,7 @@ require 'govuk_tech_docs/tech_docs_html_renderer' require 'govuk_tech_docs/unique_identifier_extension' require 'govuk_tech_docs/unique_identifier_generator' -require 'govuk_tech_docs/api_reference/api_reference' +require 'govuk_tech_docs/api_reference/api_reference_extension' module GovukTechDocs # Configure the tech docs template diff --git a/lib/govuk_tech_docs/api_reference/api_reference.rb b/lib/govuk_tech_docs/api_reference/api_reference.rb deleted file mode 100644 index 410c2fd4..00000000 --- a/lib/govuk_tech_docs/api_reference/api_reference.rb +++ /dev/null @@ -1,173 +0,0 @@ -require 'erb' -require 'openapi3_parser' -require 'uri' -require 'pry' - -module GovukTechDocs - class ApiReference < Middleman::Extension - expose_to_application api: :api - - def initialize(app, options_hash = {}, &block) - super - - @app = app - @config = @app.config[:tech_docs] - @api_parser = false - - # If no api path then just return. - if @config['api_path'].to_s.empty? - return - end - - # Is the api_path a url or path? - if uri?(@config['api_path']) - @api_parser = true - @document = Openapi3Parser.load_url(@config['api_path']) - elsif File.exist?(@config['api_path']) - # Load api file and set existence flag. - @api_parser = true - @document = Openapi3Parser.load_file(@config['api_path']) - else - raise 'Unable to load api path from tech-docs.yml' - end - - # Load template files - @render_api_full = get_renderer('api_reference_full.html.erb') - @render_path = get_renderer('path.html.erb') - @render_schema = get_renderer('schema.html.erb') - end - - def uri?(string) - uri = URI.parse(string) - %w(http https).include?(uri.scheme) - rescue URI::BadURIError - false - rescue URI::InvalidURIError - false - end - - def api(text) - if @api_parser == true - - keywords = { - 'api>' => 'default', - 'api_schema>' => 'schema' - } - - regexp = keywords.map { |k, _| Regexp.escape(k) }.join('|') - - md = text.match(/^

(#{regexp})/) - if md - key = md.captures[0] - type = keywords[key] - - text.gsub!(/#{ Regexp.escape(key) }\s+?/, '') - - # Strip paragraph tags from text - text = text.gsub(/<\/?[^>]*>/, '') - text = text.strip - - if type == 'default' - api_path_render(text) - else - api_schema_render(text) - end - - else - return text - end - else - text - end - end - - def api_path_render(text) - if text == 'api>' - api_full - else - # Call api parser on text - path = @document.paths[text] - output = @render_path.result(binding) - output - end - end - - def api_schema_render(text) - schemas = '' - schemas_data = @document.components.schemas - schemas_data.each do |schema_data| - if schema_data[0] == text - title = schema_data[0] - schema = schema_data[1] - output = @render_schema.result(binding) - return output - end - end - end - - def api_full - info = api_info - server = api_server - - paths = '' - paths_data = @document.paths - paths_data.each do |path_data| - # For some reason paths.each returns an array of arrays [title, object] - # instead of an array of objects - text = path_data[0] - path = path_data[1] - paths += @render_path.result(binding) - end - schemas = '' - schemas_data = @document.components.schemas - schemas_data.each do |schema_data| - title = schema_data[0] - schema = schema_data[1] - schemas += @render_schema.result(binding) - end - @render_api_full.result(binding) - end - - def render_markdown(text) - if text - Tilt['markdown'].new(context: @app) { text }.render - end - end - - private - - def get_renderer(file) - template_path = File.join(File.dirname(__FILE__), 'templates/' + file) - template = File.open(template_path, 'r').read - ERB.new(template) - end - - def get_operations(path) - operations = {} - operations['get'] = path.get if defined? path.get - operations['put'] = path.put if defined? path.put - operations['post'] = path.post if defined? path.post - operations['delete'] = path.delete if defined? path.delete - operations['patch'] = path.patch if defined? path.patch - operations - end - - def api_info - @document.info - end - - def api_server - @document.servers[0] - end - - def get_schema_name(text) - unless text.is_a?(String) - return nil - end - # Schema dictates that it's always components['schemas'] - text.gsub(/#\/components\/schemas\//, '') - end - end -end - -::Middleman::Extensions.register(:api_reference, GovukTechDocs::ApiReference) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_extension.rb b/lib/govuk_tech_docs/api_reference/api_reference_extension.rb new file mode 100644 index 00000000..160548d2 --- /dev/null +++ b/lib/govuk_tech_docs/api_reference/api_reference_extension.rb @@ -0,0 +1,97 @@ +require 'erb' +require 'openapi3_parser' +require 'uri' +require 'pry' +require 'govuk_tech_docs/api_reference/api_reference_renderer' + +module GovukTechDocs + module ApiReference + class Extension < Middleman::Extension + expose_to_application api: :api + + def initialize(app, options_hash = {}, &block) + super + + @app = app + @config = @app.config[:tech_docs] + + # If no api path then just return. + if @config['api_path'].to_s.empty? + raise 'No api path defined in tech-docs.yml' + end + + # Is the api_path a url or path? + if uri?(@config['api_path']) + @api_parser = true + @document = Openapi3Parser.load_url(@config['api_path']) + elsif File.exist?(@config['api_path']) + # Load api file and set existence flag. + @api_parser = true + @document = Openapi3Parser.load_file(@config['api_path']) + else + @api_parser = false + raise 'Unable to load api path from tech-docs.yml' + end + @render = Renderer.new(@app, @document) + end + + def uri?(string) + uri = URI.parse(string) + %w(http https).include?(uri.scheme) + rescue URI::BadURIError + false + rescue URI::InvalidURIError + false + end + + def api(text) + if @api_parser == true + + keywords = { + 'api>' => 'default', + 'api_schema>' => 'schema' + } + + regexp = keywords.map { |k, _| Regexp.escape(k) }.join('|') + + md = text.match(/^

(#{regexp})/) + if md + key = md.captures[0] + type = keywords[key] + + text.gsub!(/#{ Regexp.escape(key) }\s+?/, '') + + # Strip paragraph tags from text + text = text.gsub(/<\/?[^>]*>/, '') + text = text.strip + + if text == 'api>' + @render.api_full(api_info, api_server) + elsif type == 'default' + @render.path(text) + else + @render.path.schema(text) + end + + else + return text + end + else + text + end + end + + private + + def api_info + @document.info + end + + def api_server + @document.servers[0] + end + end + end +end + +::Middleman::Extensions.register(:api_reference, GovukTechDocs::ApiReference::Extension) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb new file mode 100644 index 00000000..a7542b21 --- /dev/null +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -0,0 +1,90 @@ +require 'erb' + +module GovukTechDocs + module ApiReference + class Renderer + def initialize(app, document) + @app = app + @document = document + + # Load template files + @template_api_full = get_renderer('api_reference_full.html.erb') + @template_path = get_renderer('path.html.erb') + @template_schema = get_renderer('schema.html.erb') + end + + def api_full(info, server) + paths = '' + paths_data = @document.paths + paths_data.each do |path_data| + # For some reason paths.each returns an array of arrays [title, object] + # instead of an array of objects + text = path_data[0] + path = path_data[1] + paths += @template_path.result(binding) + end + schemas = '' + schemas_data = @document.components.schemas + schemas_data.each do |schema_data| + title = schema_data[0] + schema = schema_data[1] + schemas += @template_schema.result(binding) + end + @template_api_full.result(binding) + end + + def path(text) + path = @document.paths[text] + operations = get_operations(path) + output = @template_path.result(binding) + output + end + + def schema(text) + schemas = '' + schemas_data = @document.components.schemas + schemas_data.each do |schema_data| + if schema_data[0] == text + title = schema_data[0] + schema = schema_data[1] + output = @template_schema.result(binding) + return output + end + end + end + + def markdown(text) + if text + Tilt['markdown'].new(context: @app) { text }.render + end + end + + private + + def get_renderer(file) + template_path = File.join(File.dirname(__FILE__), 'templates/' + file) + template = File.open(template_path, 'r').read + ERB.new(template) + end + + def get_operations(path) + operations = {} + operations['get'] = path.get if defined? path.get + operations['put'] = path.put if defined? path.put + operations['post'] = path.post if defined? path.post + operations['delete'] = path.delete if defined? path.delete + operations['patch'] = path.patch if defined? path.patch + operations + end + + def get_schema_name(text) + unless text.is_a?(String) + return nil + end + # Schema dictates that it's always components['schemas'] + text.gsub(/#\/components\/schemas\//, '') + end + end + end +end + diff --git a/lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb b/lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb index b56aeb59..292fda40 100644 --- a/lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb @@ -1,5 +1,5 @@

<%= info.title %> v<%= info.version %>

-<%= render_markdown(info.description) %> +<%= markdown(info.description) %> <% if server %>

Base URL

<%= server.url %>

diff --git a/lib/govuk_tech_docs/api_reference/templates/path.html.erb b/lib/govuk_tech_docs/api_reference/templates/path.html.erb index 58cc9f84..9c24cfe2 100644 --- a/lib/govuk_tech_docs/api_reference/templates/path.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/path.html.erb @@ -9,7 +9,7 @@

<%= operation.summary %>

<% end %> <% if operation.description %> -

<%= render_markdown(operation.description) %>

+

<%= markdown(operation.description) %>

<% end %> <% if operation.parameters.any? %>

Parameters

@@ -24,7 +24,7 @@ <%= parameter.in %> <%= parameter.schema.type %> <%= parameter.required? %> -<%= render_markdown(parameter.description) %> +<%= markdown(parameter.description) %> <% end %> diff --git a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb index 8258be0d..72fc483c 100644 --- a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb @@ -1,5 +1,5 @@

<%= title %>

-<%= render_markdown(schema.description) %> +<%= markdown(schema.description) %> <% if schema.properties.any? %> @@ -11,7 +11,7 @@ - + <% end %> From ae6b562a4f2639ae07d1620f8204fd49e86e7ba7 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 23 Aug 2018 14:01:54 +0100 Subject: [PATCH 02/31] Move operations rendering into a seperate file --- .../api_reference/api_reference_renderer.rb | 28 +++++---- .../templates/operation.html.erb | 50 ++++++++++++++++ .../api_reference/templates/path.html.erb | 58 +------------------ 3 files changed, 70 insertions(+), 66 deletions(-) create mode 100644 lib/govuk_tech_docs/api_reference/templates/operation.html.erb diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index a7542b21..bb5a521b 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -11,6 +11,7 @@ def initialize(app, document) @template_api_full = get_renderer('api_reference_full.html.erb') @template_path = get_renderer('path.html.erb') @template_schema = get_renderer('schema.html.erb') + @template_operation = get_renderer('operation.html.erb') end def api_full(info, server) @@ -20,24 +21,22 @@ def api_full(info, server) # For some reason paths.each returns an array of arrays [title, object] # instead of an array of objects text = path_data[0] - path = path_data[1] - paths += @template_path.result(binding) + paths += path(text) end schemas = '' schemas_data = @document.components.schemas schemas_data.each do |schema_data| - title = schema_data[0] - schema = schema_data[1] - schemas += @template_schema.result(binding) + text = schema_data[0] + schemas += schema(text) end @template_api_full.result(binding) end def path(text) path = @document.paths[text] - operations = get_operations(path) - output = @template_path.result(binding) - output + id = text.parameterize + operations = operations(path, id) + @template_path.result(binding) end def schema(text) @@ -47,12 +46,21 @@ def schema(text) if schema_data[0] == text title = schema_data[0] schema = schema_data[1] - output = @template_schema.result(binding) - return output + return @template_schema.result(binding) end end end + def operations(path, path_id) + output = '' + operations = get_operations(path) + operations.compact.each do |key, operation| + id = "#{path_id}-#{key.parameterize}" + output += @template_operation.result(binding) + end + output + end + def markdown(text) if text Tilt['markdown'].new(context: @app) { text }.render diff --git a/lib/govuk_tech_docs/api_reference/templates/operation.html.erb b/lib/govuk_tech_docs/api_reference/templates/operation.html.erb new file mode 100644 index 00000000..ceb40654 --- /dev/null +++ b/lib/govuk_tech_docs/api_reference/templates/operation.html.erb @@ -0,0 +1,50 @@ +

<%= key %>

+<% if operation.summary %> +

<%= operation.summary %>

+<% end %> +<% if operation.description %> +

<%= markdown(operation.description) %>

+<% end %> +<% if operation.parameters.any? %> +

Parameters

+
<%= property[0] %> <%= property[1].type %> <%= property[1].required.present? %><%= render_markdown(property[1].description) %><%= markdown(property[1].description) %>
+ + + + +<% operation.parameters.each do |parameter| %> + + + + + + + +<% end %> + +
ParameterInTypeRequiredDescription
<%= parameter.name %><%= parameter.in %><%= parameter.schema.type %><%= parameter.required? %><%= markdown(parameter.description) %>
+<% end %> +<% if operation.responses.any? %> +

Responses

+ + + + + +<% operation.responses.each do |key,response| %> + + + + + +<% end %> + +
StatusDescriptionSchema
<%= key %><%= response.description %> +<% if response.content['application/json'] + schema_name = get_schema_name(response.content['application/json'].schema.node_context.source_location.to_s) + if !schema_name.nil? %> +<%= schema_name %> +<% end %> +<% end %> +
+<% end %> diff --git a/lib/govuk_tech_docs/api_reference/templates/path.html.erb b/lib/govuk_tech_docs/api_reference/templates/path.html.erb index 9c24cfe2..72db5e1a 100644 --- a/lib/govuk_tech_docs/api_reference/templates/path.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/path.html.erb @@ -1,58 +1,4 @@ -
-<% operations = get_operations(path) %> -<% operations.compact.each do |key,operation| %> <% if text %> -<% id = key + text; %> -

<%= key.upcase %> <%= text %>

+

<%= text %>

<% end %> -<% if operation.summary %> -

<%= operation.summary %>

-<% end %> -<% if operation.description %> -

<%= markdown(operation.description) %>

-<% end %> -<% if operation.parameters.any? %> -

Parameters

- - - - - -<% operation.parameters.each do |parameter| %> - - - - - - - -<% end %> - -
ParameterInTypeRequiredDescription
<%= parameter.name %><%= parameter.in %><%= parameter.schema.type %><%= parameter.required? %><%= markdown(parameter.description) %>
-<% end %> -<% if operation.responses.any? %> -

Responses

- - - - - -<% operation.responses.each do |key,response| %> - - - - - -<% end %> - -
StatusDescriptionSchema
<%= key %><%= response.description %> -<% if response.content['application/json'] - schema_name = get_schema_name(response.content['application/json'].schema.node_context.source_location.to_s) - if !schema_name.nil? %> -<%= schema_name %> -<% end %> -<% end %> -
-<% end %> -<% end %> -
+<%= operations %> From 0a59bd08aaf2a9c3ea7af3719e3b20aaf6757445 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 23 Aug 2018 14:22:29 +0100 Subject: [PATCH 03/31] Moved paramters rendering into a seperate file --- .../api_reference/api_reference_renderer.rb | 9 ++++++++ .../templates/operation.html.erb | 22 +++---------------- .../templates/parameters.html.erb | 19 ++++++++++++++++ 3 files changed, 31 insertions(+), 19 deletions(-) create mode 100644 lib/govuk_tech_docs/api_reference/templates/parameters.html.erb diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index bb5a521b..e7521dfb 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -12,6 +12,7 @@ def initialize(app, document) @template_path = get_renderer('path.html.erb') @template_schema = get_renderer('schema.html.erb') @template_operation = get_renderer('operation.html.erb') + @template_parameters = get_renderer('parameters.html.erb') end def api_full(info, server) @@ -56,11 +57,19 @@ def operations(path, path_id) operations = get_operations(path) operations.compact.each do |key, operation| id = "#{path_id}-#{key.parameterize}" + parameters = parameters(operation, id) output += @template_operation.result(binding) end output end + def parameters(operation, operation_id) + parameters = operation.parameters + id = "#{operation_id}-parameters" + output = @template_parameters.result(binding) + output + end + def markdown(text) if text Tilt['markdown'].new(context: @app) { text }.render diff --git a/lib/govuk_tech_docs/api_reference/templates/operation.html.erb b/lib/govuk_tech_docs/api_reference/templates/operation.html.erb index ceb40654..4f5da7b7 100644 --- a/lib/govuk_tech_docs/api_reference/templates/operation.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/operation.html.erb @@ -5,25 +5,9 @@ <% if operation.description %>

<%= markdown(operation.description) %>

<% end %> -<% if operation.parameters.any? %> -

Parameters

- - - - - -<% operation.parameters.each do |parameter| %> - - - - - - - -<% end %> - -
ParameterInTypeRequiredDescription
<%= parameter.name %><%= parameter.in %><%= parameter.schema.type %><%= parameter.required? %><%= markdown(parameter.description) %>
-<% end %> + +<%= parameters %> + <% if operation.responses.any? %>

Responses

diff --git a/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb b/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb new file mode 100644 index 00000000..a0990a57 --- /dev/null +++ b/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb @@ -0,0 +1,19 @@ +<% if parameters.any? %> +

Parameters

+
+ + + + +<% parameters.each do |parameter| %> + + + + + + + +<% end %> + +
ParameterInTypeRequiredDescription
<%= parameter.name %><%= parameter.in %><%= parameter.schema.type %><%= parameter.required? %><%= markdown(parameter.description) %>
+<% end %> From 4e2793934a2eb85389349d157759e1584a95a7a3 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 23 Aug 2018 14:27:15 +0100 Subject: [PATCH 04/31] Moved responses rendering into a seperate file --- .../api_reference/api_reference_renderer.rb | 9 +++++++ .../templates/operation.html.erb | 25 +------------------ .../templates/responses.html.erb | 24 ++++++++++++++++++ 3 files changed, 34 insertions(+), 24 deletions(-) create mode 100644 lib/govuk_tech_docs/api_reference/templates/responses.html.erb diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index e7521dfb..1ab23a7f 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -13,6 +13,7 @@ def initialize(app, document) @template_schema = get_renderer('schema.html.erb') @template_operation = get_renderer('operation.html.erb') @template_parameters = get_renderer('parameters.html.erb') + @template_responses = get_renderer('responses.html.erb') end def api_full(info, server) @@ -58,6 +59,7 @@ def operations(path, path_id) operations.compact.each do |key, operation| id = "#{path_id}-#{key.parameterize}" parameters = parameters(operation, id) + responses = responses(operation, id) output += @template_operation.result(binding) end output @@ -70,6 +72,13 @@ def parameters(operation, operation_id) output end + def responses(operation, operation_id) + responses = operation.responses + id = "#{operation_id}-responses" + output = @template_responses.result(binding) + output + end + def markdown(text) if text Tilt['markdown'].new(context: @app) { text }.render diff --git a/lib/govuk_tech_docs/api_reference/templates/operation.html.erb b/lib/govuk_tech_docs/api_reference/templates/operation.html.erb index 4f5da7b7..3a8a447b 100644 --- a/lib/govuk_tech_docs/api_reference/templates/operation.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/operation.html.erb @@ -8,27 +8,4 @@ <%= parameters %> -<% if operation.responses.any? %> -

Responses

- - - - - -<% operation.responses.each do |key,response| %> - - - - - -<% end %> - -
StatusDescriptionSchema
<%= key %><%= response.description %> -<% if response.content['application/json'] - schema_name = get_schema_name(response.content['application/json'].schema.node_context.source_location.to_s) - if !schema_name.nil? %> -<%= schema_name %> -<% end %> -<% end %> -
-<% end %> +<%= responses %> diff --git a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb new file mode 100644 index 00000000..80416a39 --- /dev/null +++ b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb @@ -0,0 +1,24 @@ +<% if responses.any? %> +

Responses

+ + + + + +<% responses.each do |key,response| %> + + + + + +<% end %> + +
StatusDescriptionSchema
<%= key %><%= response.description %> +<% if response.content['application/json'] + schema_name = get_schema_name(response.content['application/json'].schema.node_context.source_location.to_s) + if !schema_name.nil? %> +<%= schema_name %> +<% end %> +<% end %> +
+<% end %> From b05450668de1a6f63ab59b4e83dc3f51c0ed1705 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Tue, 28 Aug 2018 14:37:21 +0100 Subject: [PATCH 05/31] Add support for enum type in parameters --- .../api_reference/templates/parameters.html.erb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb b/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb index a0990a57..a2ca5d40 100644 --- a/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb @@ -11,7 +11,16 @@ <%= parameter.in %> <%= parameter.schema.type %> <%= parameter.required? %> -<%= markdown(parameter.description) %> +<%= markdown(parameter.description) %> +<% if parameter.schema.enum %> +Available items: +
    +<% parameter.schema.enum.each do |item| %> +
  • <%= item %>
  • +<% end %> +
+<% end %> + <% end %> From e21bec7418431aff9457905d5951b29b1f46fcae Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Tue, 28 Aug 2018 15:56:50 +0100 Subject: [PATCH 06/31] Fix inserting schema objects with api_schema> --- lib/govuk_tech_docs/api_reference/api_reference_extension.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_extension.rb b/lib/govuk_tech_docs/api_reference/api_reference_extension.rb index 160548d2..a7af3a90 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_extension.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_extension.rb @@ -70,7 +70,7 @@ def api(text) elsif type == 'default' @render.path(text) else - @render.path.schema(text) + @render.schema(text) end else From dabc6820936a85e7210779ed262eec4dc8f750b7 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Tue, 28 Aug 2018 16:43:21 +0100 Subject: [PATCH 07/31] Render schemas below an individual path --- .../api_reference/api_reference_extension.rb | 5 +++- .../api_reference/api_reference_renderer.rb | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_extension.rb b/lib/govuk_tech_docs/api_reference/api_reference_extension.rb index a7af3a90..3d7b4956 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_extension.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_extension.rb @@ -68,7 +68,9 @@ def api(text) if text == 'api>' @render.api_full(api_info, api_server) elsif type == 'default' - @render.path(text) + output = @render.path(text) + # Render any schemas referenced in the above path + output += @render.schemas_from_path(text) else @render.schema(text) end @@ -90,6 +92,7 @@ def api_info def api_server @document.servers[0] end + end end end diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 1ab23a7f..021421fc 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -53,6 +53,33 @@ def schema(text) end end + def schemas_from_path(text) + path = @document.paths[text] + operations = get_operations(path) + # Get all referenced schemas + schemas = [] + operations.compact.each do |key, operation| + responses = operation.responses + responses.each do |key,response| + if response.content['application/json'] + schema_name = get_schema_name(response.content['application/json'].schema.node_context.source_location.to_s) + if !schema_name.nil? + schemas.push schema_name + end + end + end + end + # Render all referenced schemas + output = '' + schemas.uniq.each do |schema_name| + output += schema(schema_name) + end + if !output.empty? + output.prepend('

Schemas

') + end + output + end + def operations(path, path_id) output = '' operations = get_operations(path) From fdbdbc8a9c349da9600370b930a0a82e6de3350a Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Wed, 29 Aug 2018 14:06:01 +0100 Subject: [PATCH 08/31] Add paragraph tags to enum parameters --- lib/govuk_tech_docs/api_reference/templates/parameters.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb b/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb index a2ca5d40..16372550 100644 --- a/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb @@ -13,7 +13,7 @@ <%= parameter.required? %> <%= markdown(parameter.description) %> <% if parameter.schema.enum %> -Available items: +

Available items:

    <% parameter.schema.enum.each do |item| %>
  • <%= item %>
  • From d134307009ec42fcad48d5196ea7bd59d9d5b9fd Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Wed, 29 Aug 2018 14:06:58 +0100 Subject: [PATCH 09/31] Add schema link support to nested schema objects. Move functionality to a reuseable private method. --- .../api_reference/api_reference_renderer.rb | 9 +++++++++ .../api_reference/templates/responses.html.erb | 9 +++------ .../api_reference/templates/schema.html.erb | 7 ++++++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 021421fc..705b9d99 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -137,6 +137,15 @@ def get_schema_name(text) # Schema dictates that it's always components['schemas'] text.gsub(/#\/components\/schemas\//, '') end + + def get_schema_link(schema) + schema_name = get_schema_name schema.node_context.source_location.to_s + if !schema_name.nil? + id = "schema-#{schema_name.parameterize}" + output = "#{schema_name}" + output + end + end end end end diff --git a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb index 80416a39..87eb7d3b 100644 --- a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb @@ -10,12 +10,9 @@ <%= key %> <%= response.description %> -<% if response.content['application/json'] - schema_name = get_schema_name(response.content['application/json'].schema.node_context.source_location.to_s) - if !schema_name.nil? %> -<%= schema_name %> -<% end %> -<% end %> +<%= if response.content['application/json'] + get_schema_link(response.content['application/json'].schema) +end %> <% end %> diff --git a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb index 72fc483c..2fa4d749 100644 --- a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb @@ -3,7 +3,7 @@ <% if schema.properties.any? %> - + <% schema.properties.each do |property| %> @@ -12,6 +12,11 @@ + <% end %> From 8156fa8cf8f6b47f0af1c6c9298fd0e0816ff6df Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Wed, 29 Aug 2018 14:26:50 +0100 Subject: [PATCH 10/31] Also print schema links to reference within schema array properties --- .../api_reference/templates/schema.html.erb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb index 2fa4d749..7f4dc788 100644 --- a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb @@ -14,8 +14,13 @@ <% end %> From 38b3af144fa89a1a5fd9783ff06f3c229daaa3c0 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Wed, 29 Aug 2018 15:24:25 +0100 Subject: [PATCH 11/31] Add start of json response output --- .../api_reference/api_reference_renderer.rb | 28 +++++++++++++++++++ .../templates/responses.html.erb | 9 ++++++ 2 files changed, 37 insertions(+) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 705b9d99..2eae9739 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -1,4 +1,5 @@ require 'erb' +require 'json' module GovukTechDocs module ApiReference @@ -112,6 +113,33 @@ def markdown(text) end end + def json_output(schema_path) + return schema_properties(schema_path) + end + + def schema_properties(text) + + schemas_data = @document.components.schemas + schemas_data.each do |schema_data| + if schema_data[0] == text + title = schema_data[0] + properties = schema_data[1].properties + properties_hash = Hash.new + properties.each do |key, item| + if item.example.nil? + value = item.type + else + value = item.example + end + properties_hash[key] = value + # if $ref return referenced + end + output = JSON.generate(properties_hash) + return output + end + end + end + private def get_renderer(file) diff --git a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb index 87eb7d3b..dadd7c62 100644 --- a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb @@ -15,6 +15,15 @@ end %> +<% if response.content['application/json'] %> + + + +<% end %> <% end %>
    NameTypeRequiredDescription
    NameTypeRequiredDescriptionSchema
    <%= property[1].type %> <%= property[1].required.present? %> <%= markdown(property[1].description) %> + <%= + # Only print a link if it's a referenced object. + get_schema_link(property[1]) if property[1].node_context.referenced_by %> +
    <%= markdown(property[1].description) %> <%= + schema = property[1] + # If property is an array, check the items property for a reference. + if property[1].type == 'array' + schema = property[1]['items'] + end # Only print a link if it's a referenced object. - get_schema_link(property[1]) if property[1].node_context.referenced_by %> + get_schema_link(schema) if schema.node_context.referenced_by %>
    +
    +<%= json_output(get_schema_name response.content['application/json'].schema.node_context.source_location.to_s) %>
    +
    +
    From 35b2386719a072562cac5048099ab404c8faa9b8 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Wed, 29 Aug 2018 16:03:17 +0100 Subject: [PATCH 12/31] Simplified the json output generation for the response body --- .../api_reference/api_reference_renderer.rb | 35 ++++++++----------- .../templates/responses.html.erb | 17 +++++---- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 2eae9739..2065d20b 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -113,31 +113,24 @@ def markdown(text) end end - def json_output(schema_path) - return schema_properties(schema_path) + def json_output(schema) + return schema_properties(schema) end - def schema_properties(text) - - schemas_data = @document.components.schemas - schemas_data.each do |schema_data| - if schema_data[0] == text - title = schema_data[0] - properties = schema_data[1].properties - properties_hash = Hash.new - properties.each do |key, item| - if item.example.nil? - value = item.type - else - value = item.example - end - properties_hash[key] = value - # if $ref return referenced - end - output = JSON.generate(properties_hash) - return output + def schema_properties(schema_data) + properties = schema_data.properties + properties_hash = Hash.new + properties.each do |key, item| + if item.example.nil? + value = item.type + else + value = item.example end + properties_hash[key] = value + # if $ref return referenced end + output = JSON.generate(properties_hash) + return output end private diff --git a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb index dadd7c62..976e5d3c 100644 --- a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb @@ -8,7 +8,17 @@ <% responses.each do |key,response| %> <%= key %> -<%= response.description %> + +<%= response.description %> +<% if response.content['application/json'] + request_body = json_output(response.content['application/json'].schema) +end %> +<% if !request_body.blank? %> +
    +  <%= request_body %>
    +
    +<% end %> + <%= if response.content['application/json'] get_schema_link(response.content['application/json'].schema) @@ -17,11 +27,6 @@ end %> <% if response.content['application/json'] %> - -
    -<%= json_output(get_schema_name response.content['application/json'].schema.node_context.source_location.to_s) %>
    -
    - <% end %> <% end %> From 0d7599f5bd08a22c5c17996698a3d27d5bdf8f5c Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Wed, 29 Aug 2018 16:55:14 +0100 Subject: [PATCH 13/31] Lovely pretty JSON --- lib/govuk_tech_docs/api_reference/api_reference_renderer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 2065d20b..fb748129 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -129,7 +129,7 @@ def schema_properties(schema_data) properties_hash[key] = value # if $ref return referenced end - output = JSON.generate(properties_hash) + output = JSON.pretty_generate(properties_hash) return output end From b601b4efdad1a1798e02c252f1a51d6dcdaf7cde Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 30 Aug 2018 09:40:56 +0100 Subject: [PATCH 14/31] Display referenced data structures in response bodies --- .../api_reference/api_reference_renderer.rb | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index fb748129..09fa73aa 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -114,23 +114,27 @@ def markdown(text) end def json_output(schema) - return schema_properties(schema) + properties = schema_properties(schema) + JSON.pretty_generate(properties) end def schema_properties(schema_data) properties = schema_data.properties properties_hash = Hash.new properties.each do |key, item| - if item.example.nil? - value = item.type + if item.type == 'object' + properties_hash[key] = schema_properties(item) else - value = item.example + if item.example.nil? + value = item.type + else + value = item.example + end + properties_hash[key] = value + # if $ref return referenced end - properties_hash[key] = value - # if $ref return referenced end - output = JSON.pretty_generate(properties_hash) - return output + properties_hash end private From b315d2d4f013fbbca265b868651bf9d577f4ef96 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Thu, 30 Aug 2018 09:46:12 +0100 Subject: [PATCH 15/31] Remove extra table row and space --- .../api_reference/templates/responses.html.erb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb index 976e5d3c..d9e2dc6a 100644 --- a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb @@ -14,9 +14,7 @@ request_body = json_output(response.content['application/json'].schema) end %> <% if !request_body.blank? %> -
    -  <%= request_body %>
    -
    +
    <%= request_body %>
    <% end %> @@ -25,10 +23,6 @@ end %> end %> -<% if response.content['application/json'] %> - - -<% end %> <% end %> From 0b229ecd47641b5d966589a839f234b0a54ee02a Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Thu, 30 Aug 2018 10:08:50 +0100 Subject: [PATCH 16/31] Support array type in responses --- lib/govuk_tech_docs/api_reference/api_reference_renderer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 09fa73aa..ddc78ec9 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -122,7 +122,7 @@ def schema_properties(schema_data) properties = schema_data.properties properties_hash = Hash.new properties.each do |key, item| - if item.type == 'object' + if item.type == 'object' || item.type == 'array' properties_hash[key] = schema_properties(item) else if item.example.nil? From 61f9b97c7fc9ed3f861f7e57d3c668f536f3b59c Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 30 Aug 2018 11:32:52 +0100 Subject: [PATCH 17/31] Prevented response bodies from breaking page layout --- .../modules/_technical-documentation.scss | 27 +++++++++++-------- .../templates/responses.html.erb | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/assets/stylesheets/modules/_technical-documentation.scss b/lib/assets/stylesheets/modules/_technical-documentation.scss index 205e4b02..cdb0c570 100644 --- a/lib/assets/stylesheets/modules/_technical-documentation.scss +++ b/lib/assets/stylesheets/modules/_technical-documentation.scss @@ -3,11 +3,11 @@ @mixin heading-offset($tabletTopMargin) { // Scale margins with font size on mobile (16/19ths) $mobileTopMargin: ceil($tabletTopMargin * (16 / 19)); - + // Offset headings down on mobile so that linking to anchors they appear after // the sticky 'table of contents' element $stickyTocOffset: 20px + $gutter-half + 10px + 1px; - + // Pad the heading so that when linking to an anchor there is at most a // $gutter-half (mobile) or $gutter (tablet and above) sized gap between the // top of the viewport and the heading. @@ -25,9 +25,9 @@ display: block; margin: 0 $gutter-half 10px; max-width: 40em; - + line-height: 1.4; - + color: $text-colour; @include media(tablet) { @@ -45,14 +45,14 @@ @include bold-48; @include heading-offset($gutter * 2); border-top: 5px solid $text-colour; - + &:first-of-type { @include heading-offset($gutter); border-top: none; } } - h2 { + h2 { @include bold-36; @include heading-offset($gutter * 1.5); } @@ -125,7 +125,7 @@ ol + p, ul + p, .table-container + p { margin-top: ceil($gutter * (16 / 19)); - + @include media(tablet) { margin-top: $gutter; } @@ -144,6 +144,11 @@ overflow: auto; position: relative; border: 1px solid $code-02; + // Restrict the width of pre tags, as they have a tendency grow larger than + // the viewport when placed within table cells. + // @todo: Use table-layout: fixed, and remove the max-width definition from + // .technical-documentation so tables can fill the viewport. + max-width: 40em; } pre code { @@ -156,11 +161,11 @@ background: $code-01; padding: 3px 5px; border-radius: 1px; - + font-family: monaco, Consolas, "Lucida Console", monospace; font-size: 15px; color: $code-0E; - + @include media(tablet) { font-size: 16px; } @@ -191,11 +196,11 @@ display: block; max-width: 100%; overflow-x: auto; - + margin-top: $gutter-half; } - table { + table { width: 100%; border-collapse: collapse; diff --git a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb index d9e2dc6a..0740b82a 100644 --- a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb @@ -14,7 +14,7 @@ request_body = json_output(response.content['application/json'].schema) end %> <% if !request_body.blank? %> -
    <%= request_body %>
    +
    <%= request_body %>
    <% end %> From fd28f5fe0a9bd6f8b497ef29e212d1b107ceed6f Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 30 Aug 2018 14:11:43 +0100 Subject: [PATCH 18/31] Printed nested references to schemas, currently one level deep --- .../api_reference/api_reference_renderer.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index ddc78ec9..bde46bdb 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -63,10 +63,12 @@ def schemas_from_path(text) responses = operation.responses responses.each do |key,response| if response.content['application/json'] - schema_name = get_schema_name(response.content['application/json'].schema.node_context.source_location.to_s) + schema = response.content['application/json'].schema + schema_name = get_schema_name(schema.node_context.source_location.to_s) if !schema_name.nil? schemas.push schema_name end + schemas.concat(schemas_from_schema(schema)) end end end @@ -81,6 +83,21 @@ def schemas_from_path(text) output end + def schemas_from_schema(schema) + schemas = [] + properties = schema.properties + properties.each do |key, property| + # Must be a schema be referenced by another schema + if property.node_context.referenced_by.to_s.include? '#/components/schemas' + schema_name = get_schema_name(property.node_context.source_location.to_s) + end + if !schema_name.nil? + schemas.push schema_name + end + end + schemas + end + def operations(path, path_id) output = '' operations = get_operations(path) From b6cc92f294481850f1d62ae1baae28a1d03c55b7 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 30 Aug 2018 15:27:31 +0100 Subject: [PATCH 19/31] Recursively render schemas referenced by other schemas referenced by operation parameters --- lib/govuk_tech_docs/api_reference/api_reference_renderer.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index bde46bdb..52d68666 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -88,12 +88,15 @@ def schemas_from_schema(schema) properties = schema.properties properties.each do |key, property| # Must be a schema be referenced by another schema - if property.node_context.referenced_by.to_s.include? '#/components/schemas' + # And not a property of a schema + if property.node_context.referenced_by.to_s.include? '#/components/schemas' and !property.node_context.source_location.to_s.include? '/properties/' schema_name = get_schema_name(property.node_context.source_location.to_s) end if !schema_name.nil? schemas.push schema_name end + # Check sub-properties for references + schemas.concat(schemas_from_schema(property)) end schemas end From 369ae2ba3d60133e15e888baee338fe2e35974bd Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Thu, 30 Aug 2018 15:39:26 +0100 Subject: [PATCH 20/31] Start of allOf support --- .../api_reference/api_reference_renderer.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index bde46bdb..a92e2a26 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -46,6 +46,20 @@ def schema(text) schemas = '' schemas_data = @document.components.schemas schemas_data.each do |schema_data| + + allOf = schema_data[1]["allOf"] + + properties = [] + + if !allOf.blank? + schema_data[1]["allOf"].each do |schema_nested| + # pry(schema_nested.properties) + properties.concat(schema_nested.properties) + end + end + + puts properties + if schema_data[0] == text title = schema_data[0] schema = schema_data[1] From 66cb0e6514aee390f1a7446073db8eb141a0039e Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 30 Aug 2018 16:22:36 +0100 Subject: [PATCH 21/31] Render AllOf properties --- .../api_reference/api_reference_renderer.rb | 12 ++++++------ .../api_reference/templates/schema.html.erb | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index da2eb763..12949ab0 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -48,17 +48,17 @@ def schema(text) schemas_data.each do |schema_data| allOf = schema_data[1]["allOf"] - properties = [] - if !allOf.blank? schema_data[1]["allOf"].each do |schema_nested| - # pry(schema_nested.properties) - properties.concat(schema_nested.properties) + schema_nested.properties.each do |property| + properties.push property + end end end - - puts properties + schema_data[1].properties.each do |property| + properties.push property + end if schema_data[0] == text title = schema_data[0] diff --git a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb index 7f4dc788..272e5460 100644 --- a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb @@ -1,12 +1,12 @@

    <%= title %>

    <%= markdown(schema.description) %> -<% if schema.properties.any? %> +<% if properties.any? %> -<% schema.properties.each do |property| %> +<% properties.each do |property| %> From 8ccf86e18178be9c1c7a11c9317722798fcc7c7c Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 30 Aug 2018 16:26:49 +0100 Subject: [PATCH 22/31] Do not print schema links of properties of referenced schema objects --- lib/govuk_tech_docs/api_reference/templates/schema.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb index 272e5460..4e593228 100644 --- a/lib/govuk_tech_docs/api_reference/templates/schema.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/schema.html.erb @@ -20,7 +20,7 @@ schema = property[1]['items'] end # Only print a link if it's a referenced object. - get_schema_link(schema) if schema.node_context.referenced_by %> + get_schema_link(schema) if schema.node_context.referenced_by.to_s.include? '#/components/schemas' and !schema.node_context.source_location.to_s.include? '/properties/' %> <% end %> From 31c02fd54264bf46d018e595b2843be26ae7dddd Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 30 Aug 2018 17:16:10 +0100 Subject: [PATCH 23/31] Print schema objects referenced in arrays for single paths --- .../api_reference/api_reference_renderer.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 12949ab0..51456e87 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -99,8 +99,14 @@ def schemas_from_path(text) def schemas_from_schema(schema) schemas = [] - properties = schema.properties - properties.each do |key, property| + properties = [] + schema.properties.each do |property| + properties.push property[1] + end + if schema.type == 'array' + properties.push schema.items + end + properties.each do |property| # Must be a schema be referenced by another schema # And not a property of a schema if property.node_context.referenced_by.to_s.include? '#/components/schemas' and !property.node_context.source_location.to_s.include? '/properties/' From aaef8d5b6c6e856e63fdd1e71ab2b408474df395 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 30 Aug 2018 17:22:44 +0100 Subject: [PATCH 24/31] Add AllOf support to schemas referenced by a single printed path --- .../api_reference/api_reference_renderer.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 51456e87..1751cc84 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -106,6 +106,14 @@ def schemas_from_schema(schema) if schema.type == 'array' properties.push schema.items end + allOf = schema["allOf"] + if !allOf.blank? + allOf.each do |schema_nested| + schema_nested.properties.each do |property| + properties.push property[1] + end + end + end properties.each do |property| # Must be a schema be referenced by another schema # And not a property of a schema @@ -121,6 +129,9 @@ def schemas_from_schema(schema) schemas end + + + def operations(path, path_id) output = '' operations = get_operations(path) From b51feec3ad6a06438ff20102bff0499eb2a106fc Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Thu, 6 Sep 2018 10:04:40 +0100 Subject: [PATCH 25/31] Support example responses inline --- .../api_reference/templates/responses.html.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb index 0740b82a..a8486419 100644 --- a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb @@ -11,7 +11,11 @@
    NameTypeRequiredDescriptionSchema
    <%= property[0] %> <%= property[1].type %>
    <%= response.description %> <% if response.content['application/json'] +if response.content['application/json']["example"] + request_body = response.content['application/json']["example"] +else request_body = json_output(response.content['application/json'].schema) +end end %> <% if !request_body.blank? %>
    <%= request_body %>
    From f593b794033a937b54842df424535b3b4e1559a4 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Thu, 6 Sep 2018 11:33:02 +0100 Subject: [PATCH 26/31] Pretty print example response --- .../api_reference/api_reference_renderer.rb | 7 ++++--- .../api_reference/templates/responses.html.erb | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 1751cc84..6a12881e 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -129,9 +129,6 @@ def schemas_from_schema(schema) schemas end - - - def operations(path, path_id) output = '' operations = get_operations(path) @@ -169,6 +166,10 @@ def json_output(schema) JSON.pretty_generate(properties) end + def json_prettyprint(data) + JSON.pretty_generate(data) + end + def schema_properties(schema_data) properties = schema_data.properties properties_hash = Hash.new diff --git a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb index a8486419..4ddfb71f 100644 --- a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb @@ -12,7 +12,7 @@ <%= response.description %> <% if response.content['application/json'] if response.content['application/json']["example"] - request_body = response.content['application/json']["example"] + request_body = json_prettyprint(response.content['application/json']["example"]) else request_body = json_output(response.content['application/json'].schema) end From aa920b31e7e591b39f1b8a907e88a90cb8b6f041 Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Thu, 6 Sep 2018 13:36:30 +0100 Subject: [PATCH 27/31] Add support for markdown in response descriptions --- lib/govuk_tech_docs/api_reference/templates/responses.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb index 4ddfb71f..5cdce831 100644 --- a/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +++ b/lib/govuk_tech_docs/api_reference/templates/responses.html.erb @@ -9,7 +9,7 @@
    <%= key %> -<%= response.description %> +<%= markdown(response.description) %> <% if response.content['application/json'] if response.content['application/json']["example"] request_body = json_prettyprint(response.content['application/json']["example"]) From ff44e2799588845ab714d6a6bb1e17a566a716c6 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 6 Sep 2018 14:20:50 +0100 Subject: [PATCH 28/31] Correctly render nested array and items, with allOf support, in response examples --- .../api_reference/api_reference_renderer.rb | 118 +++++++++++++----- 1 file changed, 84 insertions(+), 34 deletions(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 1751cc84..b75257e8 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -47,15 +47,7 @@ def schema(text) schemas_data = @document.components.schemas schemas_data.each do |schema_data| - allOf = schema_data[1]["allOf"] - properties = [] - if !allOf.blank? - schema_data[1]["allOf"].each do |schema_nested| - schema_nested.properties.each do |property| - properties.push property - end - end - end + properties = get_all_of_array(schema_data[1]) schema_data[1].properties.each do |property| properties.push property end @@ -100,38 +92,32 @@ def schemas_from_path(text) def schemas_from_schema(schema) schemas = [] properties = [] - schema.properties.each do |property| - properties.push property[1] - end - if schema.type == 'array' - properties.push schema.items - end - allOf = schema["allOf"] - if !allOf.blank? - allOf.each do |schema_nested| - schema_nested.properties.each do |property| - properties.push property[1] - end + if defined? schema.properties + schema.properties.each do |property| + properties.push property[1] end end + properties.concat get_items(schema) + properties.concat get_all_of_array(schema) properties.each do |property| # Must be a schema be referenced by another schema # And not a property of a schema - if property.node_context.referenced_by.to_s.include? '#/components/schemas' and !property.node_context.source_location.to_s.include? '/properties/' + if defined? property.node_context and + property.node_context.referenced_by.to_s.include? '#/components/schemas' and + !property.node_context.source_location.to_s.include? '/properties/' schema_name = get_schema_name(property.node_context.source_location.to_s) end if !schema_name.nil? schemas.push schema_name end # Check sub-properties for references - schemas.concat(schemas_from_schema(property)) + if !property.nil? + schemas.concat(schemas_from_schema(property)) + end end schemas end - - - def operations(path, path_id) output = '' operations = get_operations(path) @@ -170,26 +156,90 @@ def json_output(schema) end def schema_properties(schema_data) - properties = schema_data.properties + properties = Hash.new + if defined? schema_data.properties + schema_data.properties.each do |key, property| + properties[key] = property + end + end + properties.merge! get_all_of_hash(schema_data) properties_hash = Hash.new - properties.each do |key, item| - if item.type == 'object' || item.type == 'array' - properties_hash[key] = schema_properties(item) + properties.each do |pkey, property| + if property.type == 'object' + properties_hash[pkey] = Hash.new + items = property.items + if !items.blank? + properties_hash[pkey] = schema_properties(items) + end + if !property.properties.blank? + properties_hash[pkey] = schema_properties(property) + end + elsif property.type == 'array' + properties_hash[pkey] = Array.new + items = property.items + if !items.blank? + properties_hash[pkey].push schema_properties(items) + end else - if item.example.nil? - value = item.type + if !property.example.nil? + value = property.example else - value = item.example + value = property.type end - properties_hash[key] = value + properties_hash[pkey] = value # if $ref return referenced end end + properties_hash end private + def get_all_of_array(schema) + properties = Array.new + # Sometimes allOf is a keyed array that containing an array + if schema[0] == "allOf" + all_of = schema[1] + end + if !all_of.blank? + all_of.each do |schema_nested| + schema_nested.properties.each do |property| + properties.push property + end + end + end + properties + end + + def get_all_of_hash(schema) + properties = Hash.new + if schema["allOf"] + all_of = schema["allOf"] + end + if !all_of.blank? + all_of.each do |schema_nested| + schema_nested.properties.each do |key, property| + properties[key] = property + end + end + end + properties + end + + def get_items(schema) + properties = [] + if defined? schema.items + items = schema.items + if !items.blank? + items.each do |property| + properties.push property + end + end + end + properties + end + def get_renderer(file) template_path = File.join(File.dirname(__FILE__), 'templates/' + file) template = File.open(template_path, 'r').read From a93c41f387f830e1038fc746d1ee240a3d7e5399 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 6 Sep 2018 17:36:21 +0100 Subject: [PATCH 29/31] Fixed the rendering of schemas on a single path, the template expects an array of [title, object] arrays --- .../api_reference/api_reference_renderer.rb | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 405787ba..60e13a67 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -47,7 +47,16 @@ def schema(text) schemas_data = @document.components.schemas schemas_data.each do |schema_data| - properties = get_all_of_array(schema_data[1]) + allOf = schema_data[1]["allOf"] + properties = [] + if !allOf.blank? + schema_data[1]["allOf"].each do |schema_nested| + schema_nested.properties.each do |property| + properties.push property + end + end + end + schema_data[1].properties.each do |property| properties.push property end @@ -92,32 +101,36 @@ def schemas_from_path(text) def schemas_from_schema(schema) schemas = [] properties = [] - if defined? schema.properties - schema.properties.each do |property| - properties.push property[1] + schema.properties.each do |property| + properties.push property[1] + end + if schema.type == 'array' + properties.push schema.items + end + allOf = schema["allOf"] + if !allOf.blank? + allOf.each do |schema_nested| + schema_nested.properties.each do |property| + properties.push property[1] + end end end - properties.concat get_items(schema) - properties.concat get_all_of_array(schema) properties.each do |property| # Must be a schema be referenced by another schema # And not a property of a schema - if defined? property.node_context and - property.node_context.referenced_by.to_s.include? '#/components/schemas' and - !property.node_context.source_location.to_s.include? '/properties/' + if property.node_context.referenced_by.to_s.include? '#/components/schemas' and !property.node_context.source_location.to_s.include? '/properties/' schema_name = get_schema_name(property.node_context.source_location.to_s) end if !schema_name.nil? schemas.push schema_name end # Check sub-properties for references - if !property.nil? - schemas.concat(schemas_from_schema(property)) - end + schemas.concat(schemas_from_schema(property)) end schemas end + def operations(path, path_id) output = '' operations = get_operations(path) @@ -202,13 +215,18 @@ def schema_properties(schema_data) def get_all_of_array(schema) properties = Array.new - # Sometimes allOf is a keyed array that containing an array - if schema[0] == "allOf" - all_of = schema[1] + if schema.is_a?(Array) + schema = schema[1] + end + if schema["allOf"] + all_of = schema["allOf"] end if !all_of.blank? all_of.each do |schema_nested| schema_nested.properties.each do |property| + if property.is_a?(Array) + property = property[1] + end properties.push property end end @@ -231,19 +249,6 @@ def get_all_of_hash(schema) properties end - def get_items(schema) - properties = [] - if defined? schema.items - items = schema.items - if !items.blank? - items.each do |property| - properties.push property - end - end - end - properties - end - def get_renderer(file) template_path = File.join(File.dirname(__FILE__), 'templates/' + file) template = File.open(template_path, 'r').read From 89aa8a16d673d87289d881803b37205ed8d9fb34 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Thu, 6 Sep 2018 19:34:31 +0100 Subject: [PATCH 30/31] Fixed linting errors --- .rubocop.yml | 3 ++ .../api_reference/api_reference_extension.rb | 2 +- .../api_reference/api_reference_renderer.rb | 32 +++++++------------ 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index ff792b14..6f862958 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,3 +6,6 @@ Naming/HeredocDelimiterNaming: Lint/NestedMethodDefinition: Enabled: false + +Performance/HashEachMethods: + Enabled: false diff --git a/lib/govuk_tech_docs/api_reference/api_reference_extension.rb b/lib/govuk_tech_docs/api_reference/api_reference_extension.rb index 3d7b4956..8e457241 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_extension.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_extension.rb @@ -71,6 +71,7 @@ def api(text) output = @render.path(text) # Render any schemas referenced in the above path output += @render.schemas_from_path(text) + output else @render.schema(text) end @@ -92,7 +93,6 @@ def api_info def api_server @document.servers[0] end - end end end diff --git a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb index 60e13a67..50dea183 100644 --- a/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +++ b/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb @@ -46,11 +46,10 @@ def schema(text) schemas = '' schemas_data = @document.components.schemas schemas_data.each do |schema_data| - - allOf = schema_data[1]["allOf"] + all_of = schema_data[1]["allOf"] properties = [] - if !allOf.blank? - schema_data[1]["allOf"].each do |schema_nested| + if !all_of.blank? + all_of.each do |schema_nested| schema_nested.properties.each do |property| properties.push property end @@ -74,9 +73,9 @@ def schemas_from_path(text) operations = get_operations(path) # Get all referenced schemas schemas = [] - operations.compact.each do |key, operation| + operations.compact.each_value do |operation| responses = operation.responses - responses.each do |key,response| + responses.each do |_rkey, response| if response.content['application/json'] schema = response.content['application/json'].schema schema_name = get_schema_name(schema.node_context.source_location.to_s) @@ -107,9 +106,9 @@ def schemas_from_schema(schema) if schema.type == 'array' properties.push schema.items end - allOf = schema["allOf"] - if !allOf.blank? - allOf.each do |schema_nested| + all_of = schema["allOf"] + if !all_of.blank? + all_of.each do |schema_nested| schema_nested.properties.each do |property| properties.push property[1] end @@ -118,7 +117,8 @@ def schemas_from_schema(schema) properties.each do |property| # Must be a schema be referenced by another schema # And not a property of a schema - if property.node_context.referenced_by.to_s.include? '#/components/schemas' and !property.node_context.source_location.to_s.include? '/properties/' + if property.node_context.referenced_by.to_s.include?('#/components/schemas') && + !property.node_context.source_location.to_s.include?('/properties/') schema_name = get_schema_name(property.node_context.source_location.to_s) end if !schema_name.nil? @@ -130,7 +130,6 @@ def schemas_from_schema(schema) schemas end - def operations(path, path_id) output = '' operations = get_operations(path) @@ -198,13 +197,7 @@ def schema_properties(schema_data) properties_hash[pkey].push schema_properties(items) end else - if !property.example.nil? - value = property.example - else - value = property.type - end - properties_hash[pkey] = value - # if $ref return referenced + properties_hash[pkey] = !property.example.nil? ? property.example : property.type end end @@ -214,7 +207,7 @@ def schema_properties(schema_data) private def get_all_of_array(schema) - properties = Array.new + properties = Array.new if schema.is_a?(Array) schema = schema[1] end @@ -284,4 +277,3 @@ def get_schema_link(schema) end end end - From b2ce26b377e6898860b71744d5cace9e49411153 Mon Sep 17 00:00:00 2001 From: lewisnyman Date: Fri, 7 Sep 2018 11:54:42 +0200 Subject: [PATCH 31/31] Update tests --- spec/features/integration_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/features/integration_spec.rb b/spec/features/integration_spec.rb index 2ab6723f..2e02cee3 100644 --- a/spec/features/integration_spec.rb +++ b/spec/features/integration_spec.rb @@ -136,7 +136,9 @@ def then_there_is_correct_api_info_content def then_there_is_correct_api_path_content # Path title - expect(page).to have_css('h2#get-pets', text: 'GET /pets') + expect(page).to have_css('h2#pets', text: '/pets') + # Operation title + expect(page).to have_css('h3#pets-get', text: 'get') # Path parameters expect(page).to have_css('table', text: /\b(How many items to return at one time)\b/) # Link to schema