{"id":15240451,"url":"https://github.com/mkon/openapi_contracts","last_synced_at":"2026-04-11T12:12:43.447Z","repository":{"id":37960308,"uuid":"487317176","full_name":"mkon/openapi_contracts","owner":"mkon","description":"Openapi schemas as API contracts","archived":false,"fork":false,"pushed_at":"2024-04-24T19:50:53.000Z","size":171,"stargazers_count":23,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-24T21:09:17.924Z","etag":null,"topics":["json-schema","openapi","redoc","rspec","ruby","swagger"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mkon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-30T15:47:21.000Z","updated_at":"2024-06-13T14:12:32.702Z","dependencies_parsed_at":"2023-09-22T08:56:55.714Z","dependency_job_id":"fd1852c3-046b-40cd-bd99-40a9d22fcc95","html_url":"https://github.com/mkon/openapi_contracts","commit_stats":{"total_commits":54,"total_committers":5,"mean_commits":10.8,"dds":0.537037037037037,"last_synced_commit":"f0420608fc7173719212657820cc9cd78e304a1e"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkon%2Fopenapi_contracts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkon%2Fopenapi_contracts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkon%2Fopenapi_contracts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkon%2Fopenapi_contracts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mkon","download_url":"https://codeload.github.com/mkon/openapi_contracts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248226276,"owners_count":21068173,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json-schema","openapi","redoc","rspec","ruby","swagger"],"created_at":"2024-09-29T11:04:58.412Z","updated_at":"2026-04-11T12:12:43.417Z","avatar_url":"https://github.com/mkon.png","language":"Ruby","readme":"# OpenapiContracts\n\n[![Push \u0026 PR](https://github.com/mkon/openapi_contracts/actions/workflows/main.yml/badge.svg)](https://github.com/mkon/openapi_contracts/actions/workflows/main.yml)\n[![Gem Version](https://badge.fury.io/rb/openapi_contracts.svg)](https://badge.fury.io/rb/openapi_contracts)\n[![Depfu](https://badges.depfu.com/badges/8ac57411497df02584bbf59685634e45/overview.svg)](https://depfu.com/github/mkon/openapi_contracts?project_id=35354)\n\nUse OpenAPI documentation as an API contract.\n\nCurrently supports OpenAPI documentation in the structure as used by [Redocly](https://github.com/Redocly/create-openapi-repo), but should also work for single file schemas.\n\nAdds RSpec matchers to easily verify that your requests and responses match the OpenAPI documentation.\n\n## Usage\n\nFirst, parse your API documentation:\n\n```ruby\n# This must point to the folder where the OAS file is stored\n$doc = OpenapiContracts::Doc.parse(Rails.root.join('spec/fixtures/openapi/api-docs'), '\u003cfilename\u003e')\n```\n\nIn case the `filename` argument is not set, parser will by default search for the file named `openapi.yaml`.\n\nIdeally you do this once in an RSpec `before(:suite)` hook. Then you can use these matchers in your request specs:\n\n```ruby\nsubject { make_request and response }\n\nlet(:make_request) { get '/some/path' }\n\nit { is_expected.to match_openapi_doc($doc) }\n```\n\nYou can assert a specific http status to make sure the response is of the right status:\n\n```ruby\nit { is_expected.to match_openapi_doc($doc).with_http_status(:ok) }\n\n# This is equal to\nit 'responds with 200 and matches the doc' do\n  expect(subject).to have_http_status(:ok)\n  expect(subject).to match_openapi_doc($doc)\nend\n```\n\n### Options\n\nThe `match_openapi_doc($doc)` method allows passing options as a 2nd argument.\n\n* `path` allows overriding the default `request.path` lookup in case it does not find the\n  correct response definition in your schema. This is especially important when there are\n  dynamic parameters in the path and the matcher fails to resolve the request path to\n  an endpoint in the OAS file.\n\n```ruby\nit { is_expected.to match_openapi_doc($doc, path: '/messages/{id}').with_http_status(:ok) }\n```\n\n* `request_body` can be set to `true` in case the validation of the request body against the OpenAPI _requestBody_ schema is required.\n\n```ruby\nit { is_expected.to match_openapi_doc($doc, request_body: true).with_http_status(:created) }\n```\n\n* `parameters` can be set to `true` to validate request parameters against the parameter definitions\n\n```ruby\nit { is_expected.to match_openapi_doc($doc, parameters: true) }\n```\n\nBoth options can as well be used simultaneously.\n\n### Without RSpec\n\nYou can also use the Validator directly:\n\n```ruby\n# Let's raise an error if the response does not match\nresult = OpenapiContracts.match($doc, response, options = {})\nraise result.errors.merge(\"/n\") unless result.valid?\n```\n\n## Coverage reporting\n\nYou can generate a coverage report, giving an indication how many of your OpenApi operations and\nresponses are verified.\n\nTo enable the report, set the configuration `OpenapiContracts.collect_coverage = true`.\n\nAfter the tests completed, you can generate the JSON file, for example:\n\n```ruby\nRSpec.configure do |c|\n  c.after(:suite) do\n    $your_api_doc.coverage.report.generate(Rails.root.join(\"openapi_coverage.json\"))\n  end\nend\n```\n\nIn case you run tests on multiple nodes and need to merge reports:\n\n```ruby\nOpenapiContracts::Coverage.merge_reports(\n  $your_api_doc,\n  *Dir[Rails.root.join(\"openapi_coverage_*.json\")]\n).generate(Rails.root.join(\"openapi_coverage.json\"))\n\n```\n\n## How it works\n\nIt uses the `request.path`, `request.method`, `status` and `headers` on the test subject\n(which must be the response) to find the request and response schemas in the OpenAPI document.\nThen it does the following checks:\n\n* The response is documented\n* Required headers are present\n* Documented headers match the schema (via json_schemer)\n* The response body matches the schema (via json_schemer)\n* The request body matches the schema (via json_schemer) - if `request_body: true`\n\n## Known Issues\n\nNone at the moment :)\n\n## Future plans\n\n* Validate Webmock stubs against the OpenAPI doc\n* Generate example payloads from the OpenAPI doc\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkon%2Fopenapi_contracts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmkon%2Fopenapi_contracts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkon%2Fopenapi_contracts/lists"}