From db77d1591c154e56cded25e6cb6fcac5b640bd97 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 23 Jun 2023 16:00:01 +1000 Subject: [PATCH] Add test examples to DFC API documentation In other API specs, you provide example values in the schema. So the specs contain examples which can be used for the documentation. But instead of defining example data separately, we can use the generated data by the specs. This way we document real output and don't have to double up on documentation. Note that we don't have schema definitions for the DFC API yet. And it wouldn't make sense to replicate the DFC Ontology manually in JSON Schema for this purpose. The DFC Connector ensures already that we comply with the ontology. But I hope that we can use a tool at some point to generate JSON Schema from the DFC Ontology which would add more detail to the Swagger docs, I think. --- .../spec/requests/enterprises_spec.rb | 2 +- .../spec/requests/persons_spec.rb | 2 +- .../spec/requests/supplied_products_spec.rb | 2 +- script/rswag | 15 ++++- spec/base_spec_helper.rb | 19 ++++++ swagger/dfc-v1.7/swagger.yaml | 67 +++++++++++++++++++ 6 files changed, 102 insertions(+), 5 deletions(-) diff --git a/engines/dfc_provider/spec/requests/enterprises_spec.rb b/engines/dfc_provider/spec/requests/enterprises_spec.rb index 01079f88f6..ed440b3ecc 100644 --- a/engines/dfc_provider/spec/requests/enterprises_spec.rb +++ b/engines/dfc_provider/spec/requests/enterprises_spec.rb @@ -3,7 +3,7 @@ require "swagger_helper" require DfcProvider::Engine.root.join("spec/spec_helper") -describe "Enterprises", type: :request, swagger_doc: "dfc-v1.7/swagger.yaml" do +describe "Enterprises", type: :request, swagger_doc: "dfc-v1.7/swagger.yaml", rswag_autodoc: true do let!(:user) { create(:oidc_user) } let!(:enterprise) { create(:distributor_enterprise, owner: user) } let!(:product) { create(:simple_product, supplier: enterprise ) } diff --git a/engines/dfc_provider/spec/requests/persons_spec.rb b/engines/dfc_provider/spec/requests/persons_spec.rb index 7b4fbf9e74..ba0bd9549b 100644 --- a/engines/dfc_provider/spec/requests/persons_spec.rb +++ b/engines/dfc_provider/spec/requests/persons_spec.rb @@ -3,7 +3,7 @@ require "swagger_helper" require DfcProvider::Engine.root.join("spec/spec_helper") -describe "Persons", type: :request, swagger_doc: "dfc-v1.7/swagger.yaml" do +describe "Persons", type: :request, swagger_doc: "dfc-v1.7/swagger.yaml", rswag_autodoc: true do let(:user) { create(:oidc_user) } let(:other_user) { create(:oidc_user) } diff --git a/engines/dfc_provider/spec/requests/supplied_products_spec.rb b/engines/dfc_provider/spec/requests/supplied_products_spec.rb index 9579c1447e..2e332b8bbf 100644 --- a/engines/dfc_provider/spec/requests/supplied_products_spec.rb +++ b/engines/dfc_provider/spec/requests/supplied_products_spec.rb @@ -3,7 +3,7 @@ require "swagger_helper" require DfcProvider::Engine.root.join("spec/spec_helper") -describe "SuppliedProducts", type: :request, swagger_doc: "dfc-v1.7/swagger.yaml" do +describe "SuppliedProducts", type: :request, swagger_doc: "dfc-v1.7/swagger.yaml", rswag_autodoc: true do let!(:user) { create(:oidc_user) } let!(:enterprise) { create(:distributor_enterprise, owner: user) } let!(:product) { create(:simple_product, supplier: enterprise ) } diff --git a/script/rswag b/script/rswag index 52d7336a66..00d725bb6f 100755 --- a/script/rswag +++ b/script/rswag @@ -2,5 +2,16 @@ # Generate the API documentation based on our specs. # -# The PATTERN argument is adding engines to the search path. -exec ./bin/rake rswag PATTERN="spec/requests/api/**/*_spec.rb,engines/dfc_provider/spec/requests/**/*_spec.rb" +# The standard way to generate the documentation is `rake rswag` which calls +# rspec under the hood. We have a few customisations to the rspec call though +# which only work when calling rspec ourselves. +# +# - We actually run the specs to generate examples instead of a dry run. +# While rswag has an RSWAG_DRY_RUN switch, it doesn't work with our setup. +# - We add relevant engines to the pattern. +# - We run only tagged swagger specs instead of all matching the pattern. +exec ./bin/rspec\ + --pattern "spec/requests/api/**/*_spec.rb,engines/dfc_provider/spec/requests/**/*_spec.rb"\ + --tag "swagger_doc"\ + --format "Rswag::Specs::SwaggerFormatter"\ + --order "defined" diff --git a/spec/base_spec_helper.rb b/spec/base_spec_helper.rb index a691951bc8..23b47476ac 100644 --- a/spec/base_spec_helper.rb +++ b/spec/base_spec_helper.rb @@ -106,6 +106,25 @@ RSpec.configure do |config| ActionController::Base.perform_caching = caching end + # Take example responses from Rswag specs for API documentation. + # https://github.com/rswag/rswag#enable-auto-generation-examples-from-responses + config.after(:each, :rswag_autodoc) do |example| + next if response&.body.blank? + + example.metadata[:response][:content] ||= {} + example.metadata[:response][:content].deep_merge!( + { + "application/json" => { + examples: { + test_example: { + value: JSON.parse(response.body, symbolize_names: true) + } + } + } + } + ) + end + # Show javascript errors in test output with `js_debug: true` config.after(:each, :js_debug) do errors = page.driver.browser.manage.logs.get(:browser) diff --git a/swagger/dfc-v1.7/swagger.yaml b/swagger/dfc-v1.7/swagger.yaml index b30c3a66a1..60c560815f 100644 --- a/swagger/dfc-v1.7/swagger.yaml +++ b/swagger/dfc-v1.7/swagger.yaml @@ -37,6 +37,43 @@ paths: responses: '200': description: successful + content: + application/json: + examples: + test_example: + value: + "@context": http://static.datafoodconsortium.org/ontologies/context.json + "@graph": + - "@id": http://test.host/api/dfc-v1.7/enterprises/473 + "@type": dfc-b:Enterprise + dfc-b:hasName: '' + dfc-b:hasDescription: '' + dfc-b:VATnumber: '' + dfc-b:supplies: http://test.host/api/dfc-v1.7/enterprises/473/supplied_products/298 + dfc-b:manages: http://test.host/api/dfc-v1.7/enterprises/473/catalog_items/298 + - "@id": http://test.host/api/dfc-v1.7/enterprises/473/supplied_products/298 + "@type": dfc-b:SuppliedProduct + dfc-b:name: 'Product #2 - 8569' + dfc-b:description: |- + Voluptatem sequi hic expedita reprehenderit ad veniam recusandae explicabo. Occaecati eum cumque exercitationem culpa dolor. Velit accusamus blanditiis quia laboriosam fuga corrupti maiores ut. + Consectetur illo necessitatibus porro eveniet. Similique est error labore inventore exercitationem. Similique nulla iusto tenetur reiciendis. + Quis laborum saepe illo magnam dolorem distinctio sed eligendi. Suscipit et iure vitae facilis nam quia placeat. Vero ea accusantium corrupti possimus error ad. Repellendus tenetur atque minima architecto. Optio cum magni quisquam aliquid rerum. + Laborum quae tempora iure accusamus sed blanditiis enim. Debitis earum omnis voluptate accusantium deserunt nisi nemo ad. Ea nihil architecto eius odit illo aut. Totam corporis error illum voluptatem. Repellendus eius adipisci eaque amet porro occaecati. + dfc-b:hasType: dfc-pt:non-local-vegetable + dfc-b:hasQuantity: + "@type": dfc-b:QuantitativeValue + dfc-b:hasUnit: dfc-m:Gram + dfc-b:value: 1.0 + dfc-b:alcoholPercentage: 0.0 + dfc-b:lifetime: '' + dfc-b:usageOrStorageCondition: '' + dfc-b:totalTheoreticalStock: 0.0 + - "@id": http://test.host/api/dfc-v1.7/enterprises/473/catalog_items/298 + "@type": dfc-b:CatalogItem + dfc-b:references: http://test.host/api/dfc-v1.7/enterprises/473/supplied_products/298 + dfc-b:sku: '' + dfc-b:stockLimitation: 5 + dfc-b:offeredThrough: http://test.host/api/dfc-v1.7/enterprises/473/offers/298 '404': description: not found "/api/dfc-v1.7/persons/{id}": @@ -51,6 +88,14 @@ paths: responses: '200': description: successful + content: + application/json: + examples: + test_example: + value: + "@context": http://static.datafoodconsortium.org/ontologies/context.json + "@id": http://test.host/api/dfc-v1.7/persons/910 + "@type": dfc-b:Person '404': description: not found "/api/dfc-v1.7/enterprises/{enterprise_id}/supplied_products": @@ -89,6 +134,28 @@ paths: responses: '200': description: success + content: + application/json: + examples: + test_example: + value: + "@context": http://static.datafoodconsortium.org/ontologies/context.json + "@id": http://test.host/api/dfc-v1.7/enterprises/478/supplied_products/303 + "@type": dfc-b:SuppliedProduct + dfc-b:name: 'Product #6 - 8953' + dfc-b:description: Magni nemo enim saepe harum corporis nobis + facilis. Nostrum facilis molestiae at quaerat exercitationem + itaque veritatis. Incidunt eaque asperiores assumenda eveniet + doloribus qui voluptatibus quidem. + dfc-b:hasType: dfc-pt:non-local-vegetable + dfc-b:hasQuantity: + "@type": dfc-b:QuantitativeValue + dfc-b:hasUnit: dfc-m:Gram + dfc-b:value: 1.0 + dfc-b:alcoholPercentage: 0.0 + dfc-b:lifetime: '' + dfc-b:usageOrStorageCondition: '' + dfc-b:totalTheoreticalStock: 0.0 '404': description: not found put: