Liminal OpenAPI

liminal-openapi compiles Liminal schema sources and dry-validation contracts into OpenAPI 3.0 Schema Objects. It also registers reusable components and validates generated OpenAPI documents without depending on Rswag.

Compile schemas and contracts

require "liminal/openapi"

schema = Liminal::Openapi.contract(
  Contracts::Users::Create,
  exclude: [[:current_user]],
  examples: {[:name] => "Mario"}
)

Both schema and contract compilation accept Liminal compiler options such as exclude, overrides, and predicates. Contract names are used as diagnostic context unless an explicit source_name is provided.

Passing a Hash treats it as a precompiled Schema Object. It is validated through Liminal::Schema.normalize, copied, and deeply frozen; compiler-only options are rejected because there is no dry-schema source to compile.

examples and overrides are path-keyed Hashes. Paths are canonicalized before they are merged, duplicate aliases fail fast, and an explicit override takes precedence over an example at the same path.

Register components

Liminal::Openapi.enrich(document) do |components|
  components.register_contract(:create_user, Contracts::Users::Create)
end

Registration validates the OpenAPI version and component container shape needed for the mutation. It rejects invalid names, ambiguous string/symbol registries, and component collisions, and returns immutable references. Use verification for full-document validation.

Verify generated documents

require "liminal/openapi/verification"

Liminal::Openapi::Verification.call(
  checked: "swagger/v1/actions.yaml",
  generated: "v1/actions.yaml"
) do |temporary_root|
  generate_document(temporary_root)
end

Verification validates both documents and compares their structure: object key order is ignored, while array order and scalar types remain significant. Documents must be bundled; external $ref targets are rejected because changes outside either compared file would otherwise escape drift detection.

To ignore generated examples without masking unrelated changes:

Liminal::Openapi::Verification.call(
  checked: "swagger/v1/actions.yaml",
  generated: "v1/actions.yaml",
  ignore: :operation_examples
) { |temporary_root| generate_document(temporary_root) }

This policy removes only inline OpenAPI-defined example fields beneath operations. Property names, component names, defaults, extensions, and arbitrary payload fields named example or examples remain part of the comparison.

Development

Run bundle exec rake for randomized RSpec and RuboCop checks, bundle exec rake coverage for enforced line and branch coverage, and bundle exec rake build to build the gem. The suite includes a real Dry::Validation::Contract integration.

Made with ❤️ by @olistik