Skooma Ruby Library

repository·main·Indexed 42 days ago

https://github.com/skryukov/skooma

A Ruby library for validating API implementations against OpenAPI 3.1.0 documents. It integrates with RSpec and Minitest to ensure request and response schemas match specifications using matchers like conform_schema and be_valid_document. Features include coverage reporting, support for multiple OpenAPI documents, and custom body parsers for various media types.

Tokens
5.9K
Snippets
32
Records
33
Agent score
52%

What's inside Skooma

  1. Configure Skooma with multiple OpenAPI documents in RSpec

    main

    To use Skooma in a Rails application with multiple OpenAPI documents, include the Skooma::RSpec module in your RSpec configuration. You can provide a path_prefix option if your API is mounted under a specific path. Each inclusion should be associated with a unique RSpec metadata filter (e.g., :bar_api) so you can target specific APIs in your tests.

    Example configuration in rails_helper.rb:

    RSpec.configure do |config|
      config.include Skooma::RSpec[bar_openapi, path_prefix: "/bar"], :bar_api
      config.include Skooma::RSpec[baz_openapi, path_prefix: "/baz"], :baz_api
    end
    RSpec.configure do |config|
      config.include Skooma::RSpec[bar_openapi, path_prefix: "/bar"], :bar_api
      config.include Skooma::RSpec[baz_openapi, path_prefix: "/baz"], :baz_api
    end
  2. Configure Skooma for Minitest

    main

    To use Skooma with Minitest, include Skooma::Minitest in your ActionDispatch::IntegrationTest class.

    Available options:

    • path_prefix: For APIs mounted under a prefix.
    • coverage: :report for coverage, :strict to raise errors on uncovered operations.
    • coverage_store: Custom object for coverage data.
    • enforce_access_modes: (Experimental) Enables support for readOnly and writeOnly keywords.
    • use_patterns_for_path_matching: (Experimental) Enables custom regex patterns for path parameters.
    # test/test_helper.rb
    path_to_openapi = Rails.root.join("docs", "openapi.yml")
    
    # Basic usage
    ActionDispatch::IntegrationTest.include Skooma::Minitest[path_to_openapi]
    
    # With path prefix
    # ActionDispatch::IntegrationTest.include Skooma::Minitest[path_to_openapi, path_prefix: "/internal/api"]
    
    # With coverage
    # ActionDispatch::IntegrationTest.include Skooma::Minitest[path_to_openapi, coverage: :report]
    
    # With custom coverage store
    # store = Skooma::CoverageStore.new(file_path: "tmp/skooma_coverage_#{ENV["TEST_ENV_NUMBER"]}.json")
    # ActionDispatch::IntegrationTest.include Skooma::Minitest[path_to_openapi, coverage: :report, coverage_store: store]
    
    # Experimental: access modes
    # ActionDispatch::IntegrationTest.include Skooma::Minitest[path_to_openapi, enforce_access_modes: true]
    
    # Experimental: path patterns
    # ActionDispatch::IntegrationTest.include Skooma::Minitest[path_to_openapi, use_patterns_for_path_matching: true]
  3. Configure Skooma for RSpec

    main

    To use Skooma with RSpec, include Skooma::RSpec in your RSpec.configure block. You must provide the path to your OpenAPI document. You can also configure path prefixes, coverage reporting, and custom coverage stores.

    Key configuration options:

    • path_prefix: Use this if your API is mounted under a specific prefix (e.g., /internal/api).
    • coverage: Set to :report to enable coverage reporting, or :strict to raise an error when an operation is not covered.
    • coverage_store: Pass a custom object implementing load_data, save_data(defined, covered), and clear to control where coverage data is stored.
    # spec/rails_helper.rb
    
    RSpec.configure do |config|
      path_to_openapi = Rails.root.join("docs", "openapi.yml")
      
      # Basic usage
      config.include Skooma::RSpec[path_to_openapi], type: :request
    
      # With path prefix
      # config.include Skooma::RSpec[path_to_openapi, path_prefix: "/internal/api"], type: :request
    
      # With coverage reporting
      # config.include Skooma::RSpec[path_to_openapi, coverage: :report], type: :request
    
      # With custom coverage store
      # store = Skooma::CoverageStore.new(file_path: "tmp/skooma_coverage_#{ENV["TEST_ENV_NUMBER"]}.json")
      # config.include Skooma::RSpec[path_to_openapi, coverage: :report, coverage_store: store], type: :request
    end
  4. Set up the development environment

    main

    If you are working with the repository source, follow these steps to prepare your environment:

    1. Run bin/setup to install all necessary dependencies.
    2. Use bin/console to open an interactive prompt for experimenting with the library.
    3. Run rake spec to execute the test suite.
    bin/setup
    bin/console
    rake spec
  5. Automatically apply API metadata using `define_derived_metadata`

    main

    To avoid manually adding API metadata filters (like :bar_api) to every spec file, use RSpec's config.define_derived_metadata. This allows you to automatically assign metadata based on the file path of the spec.

    RSpec.configure do |config|
      config.define_derived_metadata(file_path: %r{/spec/requests/bar}) do |metadata|
        metadata[:bar_api] = true
      end
    end
    RSpec.configure do |config|
      config.define_derived_metadata(file_path: %r{/spec/requests/bar}) do |metadata|
        metadata[:bar_api] = true
      end
    end
  6. Implement a custom `coverage_store` for parallel CI

    main

    To prevent coverage data collisions in parallel CI environments, you can pass a custom object to the coverage_store: option. The object must implement the following interface:

    • load_data
    • save_data
    • clear

    This allows you to write coverage data to separate files (e.g., one per parallel runner) and merge them in a subsequent step.

  7. Configure Skooma RSpec matchers

    main

    To use Skooma's OpenAPI schema validation matchers in your RSpec tests, include Skooma::RSpec in your RSpec configuration. You must provide the path to your OpenAPI specification file (e.g., openapi.yml) and can pass additional parameters. It is common practice to include it for the :request type so that schema validation is available in request specs.

    When initialized, Skooma also sets up an at_exit hook to automatically generate a coverage report after the test suite finishes.

    RSpec.configure do |config|
      # ...
      config.include Skooma::RSpec[Rails.root.join("docs", "openapi.yml")], type: :request
    end
  8. Validate requests and responses in RSpec

    main

    Use the conform_schema(status_code) matcher to validate that a request/response cycle matches the schema defined for a specific HTTP status code in your OpenAPI document.

    # spec/requests/feed_spec.rb
    
    require "rails_helper"
    
    describe "/animals/:animal_id/feed" do  
      let(:animal) { create(:animal, :unicorn) }
      
      describe "POST" do
        subject { post "/animals/#{animal.id}/feed", body:, as: :json }
        
        let(:body) { {food: "apple", quantity: 3} }
    
        it { is_expected.to conform_schema(200) }
    
        context "with wrong food type" do
          let(:body) { {food: "wood", quantity: 1} }
        
          it { is_expected.to conform_schema(422) }
        end
      end
    end
  9. Validate OpenAPI documents in RSpec

    main

    Use the skooma_openapi_schema helper and the be_valid_document matcher to ensure your OpenAPI specification is valid.

    # spec/openapi_spec.rb
    
    require "rails_helper"
    
    describe "OpenAPI document", type: :request do
      subject(:schema) { skooma_openapi_schema }
    
      it { is_expected.to be_valid_document }
    end