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