PHPackages                             studio-design/openapi-contract-testing - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. studio-design/openapi-contract-testing

Abandoned → [studio-design/gesso](/?search=studio-design%2Fgesso)Library[Testing &amp; Quality](/categories/testing)

studio-design/openapi-contract-testing
======================================

Gesso — OpenAPI 3.0/3.1/3.2 contract testing for PHP. Framework-independent core with Laravel, Symfony, Pest, and PSR-7 adapters. PHPUnit coverage, request/response validation, fuzzing, and drift detection.

v2.2.0(2w ago)53.7k↓38.7%[5 issues](https://github.com/studio-design/gesso/issues)[1 PRs](https://github.com/studio-design/gesso/pulls)MITPHPPHP ^8.3CI passing

Since Feb 19Pushed 3w agoCompare

[ Source](https://github.com/studio-design/gesso)[ Packagist](https://packagist.org/packages/studio-design/openapi-contract-testing)[ Docs](https://studio-design.github.io/gesso/)[ RSS](/packages/studio-design-openapi-contract-testing/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (10)Dependencies (52)Versions (73)Used By (0)

 [![Gesso logo](images/gesso-logo.png)](images/gesso-logo.png)

Gesso
=====

[](#gesso)

**/ˈdʒɛs.so/** — pronounced “JESS-so”

Gesso is the primer applied to a canvas before painting—a stable, receptive ground on which the finished work can be built. Gesso brings that same idea to APIs, providing a dependable foundation for OpenAPI contract testing in PHP.

[![CI](https://github.com/studio-design/gesso/actions/workflows/ci.yml/badge.svg)](https://github.com/studio-design/gesso/actions/workflows/ci.yml)[![Latest Version](https://camo.githubusercontent.com/4e6853cec54889fa1eb2dffc3a58a9bdf0257b4d6f87fd7e442db74d3ca9a19e/68747470733a2f2f706f7365722e707567782e6f72672f73747564696f2d64657369676e2f676573736f2f76)](https://packagist.org/packages/studio-design/gesso)[![Total Downloads](https://camo.githubusercontent.com/a997766a801264aee7e16b7f948d806336283b3d132a3e2cb9582eb5c14cd129/68747470733a2f2f706f7365722e707567782e6f72672f73747564696f2d64657369676e2f676573736f2f646f776e6c6f616473)](https://packagist.org/packages/studio-design/gesso)[![PHP Version Require](https://camo.githubusercontent.com/03aed0e7fc00a863dbb6534052d01db9d964e1dbcaefdd313d772b891cdc6166/68747470733a2f2f706f7365722e707567782e6f72672f73747564696f2d64657369676e2f676573736f2f726571756972652f706870)](https://packagist.org/packages/studio-design/gesso)[![License](https://camo.githubusercontent.com/eb118f213b4f9210c806b7dd301d15bb87fda00f141da837c25e4a6e17a68526/68747470733a2f2f706f7365722e707567782e6f72672f73747564696f2d64657369676e2f676573736f2f6c6963656e7365)](https://packagist.org/packages/studio-design/gesso)

Gesso provides framework-agnostic OpenAPI 3.0/3.1/3.2 contract testing for PHPUnit **with endpoint coverage tracking**.

Validate your API responses against your OpenAPI specification during testing, and get a coverage report showing which endpoints have been tested.

Gesso 2 is distributed as `studio-design/gesso` and declares its public PHP API under `Studio\Gesso\`. Follow the [staged v2 migration guide](docs/migration/v2.md)when upgrading from `studio-design/openapi-contract-testing` v1.10.

**[Search the documentation](https://studio-design.github.io/gesso/)** · [Core quickstart](https://studio-design.github.io/gesso/quickstarts/core) · [Laravel](https://studio-design.github.io/gesso/quickstarts/laravel) · [Symfony](https://studio-design.github.io/gesso/quickstarts/symfony) · [Pest](https://studio-design.github.io/gesso/quickstarts/pest)

Features
--------

[](#features)

- **OpenAPI 3.0, 3.1 &amp; 3.2 support** — Explicit version detection, including 3.2 `QUERY`, custom `additionalOperations`, form `querystring`, `discriminator.defaultMapping`, and observable streaming limitations
- **Response &amp; request validation** — dialect-aware JSON Schema via opis/json-schema: Draft 07 compatibility for OpenAPI 3.0 and native 2020-12 semantics for OpenAPI 3.1/3.2; `application/json` and any `+json` content type
- **Endpoint coverage tracking** — Unique PHPUnit extension that reports which spec endpoints are covered by tests, at `(method, path, status, content-type)` granularity
- **Laravel route/spec parity** — `openapi:routes` finds documented operations without routes and registered routes without OpenAPI operations, with filters, stable JSON, and independent CI gates
- **Schema-driven request fuzzing** — Valid boundaries, composition branches, targeted negative cases with explicit expected status classes, deterministic replay/reduction, whole-spec filters, lifecycle/auth hooks, and explicit skip reasons
- **Named negative contract checks** — Opt-in `unsupported_method` probes that dispatch an undocumented HTTP method per documented path and expect 405, with deterministic replay and collect-then-assert reporting. See [`docs/fuzzing.md`](docs/fuzzing.md#named-contract-checks).
- **Enum drift detection** — Static comparison between PHP backed enums and their `enum:` spec arrays, with PHPUnit-extension auto-discovery
- **Schema under-description detection** — Optional strict mode that flags response fields the implementation always returns but the spec marks as optional, catching the spec gaps that conformance checks alone can't. See [`docs/strict-required.md`](docs/strict-required.md) for current scope and limitations.
- **Undocumented response-property detection** — Optional strict mode that names returned fields absent from `properties` / `patternProperties` when a schema silently defaults open. See [`docs/strict-additional-properties.md`](docs/strict-additional-properties.md).
- **Skip-by-status-code** — Configurable regex list of status codes whose bodies are not validated (default: every `5xx`); per-request via `skipResponseCode()`
- **PSR-7, Laravel, Symfony &amp; Pest adapters** — First-class PSR-7 request/response/exchange validation, auto-assert / auto-validate-request integration for Laravel, HttpFoundation assertions for Symfony, and Pest expectations
- **Parallel-runner safe** — Coordinated sidecar+merge workflow for paratest / `pest --parallel`
- **Multi-format reports** — Markdown / JUnit XML / JSON / HTML output with one-click GitHub Step Summary
- **Zero runtime overhead** — Only used in test suites

Why this library?
-----------------

[](#why-this-library)

Choose based on the workflow you need rather than on a single yes/no feature count:

- Choose **this library** when you need response-level coverage at `(method, path, status, content-type)` granularity, several CI report formats, OpenAPI 3.1/3.2 JSON Schema semantics, schema-driven exploration, or drift detection across a framework-agnostic core and Laravel, Symfony, and Pest adapters.
- Choose **[Spectator](https://github.com/hotmeteor/spectator/tree/v3.0.2)** for a Laravel 12 application when generated test stubs or JSON assertion failures matter more than response-level coverage granularity and broader framework support. (Remote and private-GitHub spec sources are supported here too via [`remoteSpecs`](docs/setup.md#remote-spec-sources-opt-in).)
- Choose **[league/openapi-psr7-validator](https://github.com/thephpleague/openapi-psr7-validator/tree/0.24)** when you want a low-level PSR-7 validator or PSR-15 middleware and will build the test/reporting integration yourself.
- Choose **[osteel/openapi-httpfoundation-testing](https://github.com/osteel/openapi-httpfoundation-testing/tree/v0.14)** when you want a small HttpFoundation-to-PSR-7 validation bridge, or **[laravel-openapi-validator](https://github.com/kirschbaum-development/laravel-openapi-validator/tree/2.0.2)** when automatic validation around Laravel HTTP tests is the main requirement.

### Feature comparison (checked 2026-07-10)

[](#feature-comparison-checked-2026-07-10)

Capability**This library**[Spectator v3.0.2](https://github.com/hotmeteor/spectator/tree/v3.0.2)[league/psr7 v0.24](https://github.com/thephpleague/openapi-psr7-validator/tree/0.24)[osteel v0.14](https://github.com/osteel/openapi-httpfoundation-testing/tree/v0.14)[kirschbaum v2.0.2](https://github.com/kirschbaum-development/laravel-openapi-validator/tree/2.0.2)OpenAPI versions explicitly supported[3.0, 3.1, 3.2](docs/supported-features.md)Version scope not stated[3.0.x](https://github.com/thephpleague/openapi-psr7-validator/tree/0.24#openapi-psr-7-message-httprequestresponse-validator)[3+; delegates to League v0.22](https://github.com/osteel/openapi-httpfoundation-testing/blob/v0.14/composer.json)[Delegates to League v0.14–0.24](https://github.com/kirschbaum-development/laravel-openapi-validator/blob/2.0.2/composer.json)Request + response validation✅[✅ Laravel](https://github.com/hotmeteor/spectator/tree/v3.0.2)[✅ PSR-7](https://github.com/thephpleague/openapi-psr7-validator/tree/0.24#openapi-psr-7-message-httprequestresponse-validator)[✅ HttpFoundation / PSR-7](https://github.com/osteel/openapi-httpfoundation-testing/tree/v0.14#usage)[✅ Laravel HTTP tests](https://github.com/kirschbaum-development/laravel-openapi-validator/tree/2.0.2#usage)Coverage granularity[`method, path, status, content-type`](docs/coverage.md)[`method, path` operation](https://github.com/hotmeteor/spectator/blob/v3.0.2/src/Coverage/CoverageTracker.php)———Coverage outputs[Markdown, JUnit XML, JSON, HTML, GitHub Step Summary](docs/coverage.md)[Text, JSON](https://github.com/hotmeteor/spectator/tree/v3.0.2#contract-coverage-tracking)———Parallel coverage merge[Sidecar + merge CLI](docs/parallel.md)Not documented———Route/spec parity[`openapi:routes`](docs/laravel-route-parity.md) with text/JSON and CI gates[`spectator:routes`](https://github.com/hotmeteor/spectator/tree/v3.0.2#artisan-commands)———CLI diagnostics / scaffolding[`doctor`](docs/doctor.md), [`openapi:routes`](docs/laravel-route-parity.md), coverage merge; no scaffolding[`validate`, `coverage`, `routes`, `stubs`](https://github.com/hotmeteor/spectator/tree/v3.0.2#artisan-commands)———Structured validation failures[`issues()` + versioned JSON failure output](docs/validation-json-schema.md)[JSON `{errors: [...]}`](https://github.com/hotmeteor/spectator/tree/v3.0.2#machine-readable-error-output)[PHP exception hierarchy](https://github.com/thephpleague/openapi-psr7-validator/tree/0.24#exceptions)[Wrapper exception](https://github.com/osteel/openapi-httpfoundation-testing/tree/v0.14#usage)[PHPUnit failure text](https://github.com/kirschbaum-development/laravel-openapi-validator/blob/2.0.2/src/ValidatesOpenApiSpec.php#L271-L289)Schema-driven exploration[Deterministic endpoint + whole-spec generation](docs/fuzzing.md)————Drift / under-description checks[Enum drift](docs/enum-drift.md), [strict required](docs/strict-required.md)————First-class integration[PSR-7](docs/psr7.md), [Laravel, Symfony, Pest](docs/setup.md)[Laravel](https://github.com/hotmeteor/spectator/tree/v3.0.2)[PSR-7, PSR-15 middleware](https://github.com/thephpleague/openapi-psr7-validator/tree/0.24#psr-15-middleware)[HttpFoundation, PSR-7](https://github.com/osteel/openapi-httpfoundation-testing/tree/v0.14#usage)[Laravel auto-validation](https://github.com/kirschbaum-development/laravel-openapi-validator/tree/2.0.2#usage)Declared runtime floorPHP 8.3 core; [Testbench 9–11](composer.json) ([Laravel 11–12](https://packages.tools/testbench#version-compatibility); [Laravel 13 / PHP 8.3](https://github.com/orchestral/testbench/blob/v11.1.0/composer.json))[PHP 8.3, Laravel 12](https://github.com/hotmeteor/spectator/blob/v3.0.2/composer.json)[PHP 7.2](https://github.com/thephpleague/openapi-psr7-validator/blob/0.24/composer.json)[PHP 8.0, HttpFoundation 5–8](https://github.com/osteel/openapi-httpfoundation-testing/blob/v0.14/composer.json)[PHP 8.0, Illuminate 10–13](https://github.com/kirschbaum-development/laravel-openapi-validator/blob/2.0.2/composer.json)**Legend**: ✅ supported · — no equivalent feature documented. “Not documented” is intentionally different from “unsupported”.

**Methodology**: This is a documentation/source audit, not a benchmark. Claims are limited to the linked, tag-pinned public documentation and Composer constraints checked on 2026-07-10. This-library claims describe [`main` at `8c6416d`](https://github.com/studio-design/gesso/commit/8c6416dcd7edf179010f5f1cdc71a1e146a5c403); competitor versions are shown in the table header. Re-check this matrix using the [release checklist](docs/versioning.md#release-checklist) at least quarterly or before a release when three months have elapsed.

Requirements
------------

[](#requirements)

- PHP 8.3+
- PHPUnit 12 or 13
- A PSR-18 HTTP client + PSR-17 request factory (e.g. Guzzle, Symfony HttpClient) — only required when resolving HTTP(S) `$ref`s

Installation
------------

[](#installation)

```
composer require --dev "studio-design/gesso:^2.0"
```

> **YAML specs require `symfony/yaml`.** It is listed under `suggest` so it isn't installed automatically. If your spec is JSON, you can skip this. If your spec is `.yaml` / `.yml`, add it explicitly:
>
> ```
> composer require --dev symfony/yaml
> ```
>
>
>
> Without it, the loader throws `InvalidOpenApiSpecException` with a clear "requires symfony/yaml" message the first time it tries to read a YAML file.

Quick start
-----------

[](#quick-start)

Choose the CI-tested five-minute path matching your stack:

StackPassing exampleWhat it demonstratesFramework-independent PHPUnit[`examples/core`](examples/core)Direct response validation and coverageLaravel[`examples/laravel`](examples/laravel)Explicit assertion, `auto_assert`, and request validationSymfony[`examples/symfony`](examples/symfony)HttpFoundation request/response assertionsPest[`examples/pest`](examples/pest)Laravel response and request expectationsPSR-7[`examples/psr7`](examples/psr7)Request/response exchange validationAll paths start with the same development dependency:

```
composer require --dev "studio-design/gesso:^2.0"
```

The example below uses a PSR-7 request and response. The searchable documentation contains the complete [core](https://studio-design.github.io/gesso/quickstarts/core), [Laravel](https://studio-design.github.io/gesso/quickstarts/laravel), [Symfony](https://studio-design.github.io/gesso/quickstarts/symfony), and [Pest](https://studio-design.github.io/gesso/quickstarts/pest) quickstarts.

### 1. Provide your OpenAPI spec

[](#1-provide-your-openapi-spec)

Point the loader at your spec's entry file. Internal and local-filesystem `$ref` are resolved automatically — no pre-bundling required:

```
openapi/
├── root.yaml          # paths reference ./schemas/*.yaml
└── schemas/
    ├── pet.yaml
    └── error.json

```

### 2. Register the PHPUnit extension

[](#2-register-the-phpunit-extension)

Before running your first test, verify that the package can load and enforce the contract:

```
vendor/bin/gesso doctor \
  --spec=openapi/root.yaml \
  --strip-prefix=/api \
  --phpunit-snippet
```

The command resolves local references, checks the OpenAPI/JSON Schema dialect, reports unsupported enforcement features, counts discovered operations and responses, and exits non-zero for incompatible specs. Use `--format=json` in CI. See the [doctor command reference](docs/doctor.md) for multiple specs, HTTP references, output categories, and exit codes.

Then register the emitted configuration:

```

```

### 3. Validate a PSR-7 exchange

[](#3-validate-a-psr-7-exchange)

When your application or HTTP client already returns PSR-7 messages, validate both sides and record coverage with one framework-independent call:

```
use Studio\Gesso\Psr7\OpenApiPsr7Validator;

$validator = new OpenApiPsr7Validator('front');
$result = $validator->validateExchange($request, $response);

$this->assertTrue($result->isValid(), $result->errorMessage());
```

The adapter accepts any `psr/http-message` implementation; no concrete PSR-7 package is added to production dependencies. A PHPUnit assertion trait, response-only operation addressing, PSR-15 test recipe, and stream guarantees are covered in the [PSR-7 guide](docs/psr7.md).

### Laravel adapter

[](#laravel-adapter)

```
php artisan vendor:publish --tag=gesso
```

Set `default_spec` in the published `config/gesso.php`, then mix in the trait:

```
use Studio\Gesso\Laravel\ValidatesOpenApiSchema;

class GetPetsTest extends TestCase
{
    use ValidatesOpenApiSchema;

    public function test_list_pets(): void
    {
        $response = $this->get('/api/v1/pets');
        $response->assertOk();
        $this->assertResponseMatchesOpenApiSchema($response);
    }
}
```

Before running tests, compare Laravel's registered routes with the spec:

```
php artisan openapi:routes --fail-on-undocumented --fail-on-unimplemented
```

To validate every response automatically, set `'auto_assert' => true` and drop the explicit assert call. To also catch request-side drift, set `'auto_validate_request' => true`. See [`docs/setup.md`](docs/setup.md) for the full configuration and opt-out reference.

Documentation
-------------

[](#documentation)

TopicReferencePSR-7 request / response / exchange validation and PSR-15 test recipe[`docs/psr7.md`](docs/psr7.md)Full setup, Laravel / Symfony / framework-agnostic adapters, auto-assert, opt-out attributes, request validation, HTTP `$ref`[`docs/setup.md`](docs/setup.md)Pre-test compatibility diagnostics (`gesso doctor`)[`docs/doctor.md`](docs/doctor.md)Laravel route/spec parity (`openapi:routes`)[`docs/laravel-route-parity.md`](docs/laravel-route-parity.md)Pest plugin: `expect()->toMatchOpenApiResponseSchema()` and friends[`docs/pest-plugin.md`](docs/pest-plugin.md)Schema-driven request fuzzing &amp; named contract checks[`docs/fuzzing.md`](docs/fuzzing.md)Enum drift detection[`docs/enum-drift.md`](docs/enum-drift.md)Schema under-description detection (`strict_required`)[`docs/strict-required.md`](docs/strict-required.md)Undocumented response-property detection (`strict_additional_properties`)[`docs/strict-additional-properties.md`](docs/strict-additional-properties.md)Violation baseline: adopt on a legacy API, fail only on new violations[`docs/baseline.md`](docs/baseline.md)Coverage report modes &amp; threshold gate[`docs/coverage.md`](docs/coverage.md)HTML coverage output[`docs/coverage-html-output.md`](docs/coverage-html-output.md)JSON coverage output schema[`docs/coverage-json-schema.md`](docs/coverage-json-schema.md)JSON validation result output schema[`docs/validation-json-schema.md`](docs/validation-json-schema.md)Parallel test runners (paratest / Pest `--parallel`)[`docs/parallel.md`](docs/parallel.md)CI integration (GitHub Actions, PR comments, output formats, partial-run handling)[`docs/ci.md`](docs/ci.md)API reference (`OpenApiResponseValidator`, `OpenApiSpecLoader`, `OpenApiCoverageTracker`)[`docs/api-reference.md`](docs/api-reference.md)Supported features, known limitations, warning channel[`docs/supported-features.md`](docs/supported-features.md)Versioning policy &amp; support matrix[`docs/versioning.md`](docs/versioning.md)Development
-----------

[](#development)

```
composer install

# Run tests
vendor/bin/phpunit

# Static analysis
vendor/bin/phpstan analyse

# Code style
vendor/bin/php-cs-fixer fix
vendor/bin/php-cs-fixer fix --dry-run --diff  # Check only
```

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

###  Health Score

48

—

FairBetter than 94% of packages

Maintenance76

Regular maintenance activity

Popularity28

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 93.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Total

41

Last Release

17d ago

Major Versions

v0.19.0 → v1.0.02026-05-01

v1.10.0 → v2.0.0-beta.12026-07-15

PHP version history (2 changes)v0.1.0PHP ^8.2

v2.0.0-beta.1PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/6fc976536b6b21ad39ca38269c6c59eceabc5fd57d6627e6742279cff53c387a?d=identicon)[wadakatu](/maintainers/wadakatu)

---

Top Contributors

[![wadakatu](https://avatars.githubusercontent.com/u/72595463?v=4)](https://github.com/wadakatu "wadakatu (413 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (16 commits)")[![renovate[bot]](https://avatars.githubusercontent.com/in/2740?v=4)](https://github.com/renovate[bot] "renovate[bot] (12 commits)")

---

Tags

api-testingcode-coveragecontract-testingjson-schemalaravelopenapiopenapi3openapi31pestphpphp-libraryphpunittestingphpunitsymfonypestlaravelvalidationcoverageopenapipsr7api testingopenapi3contract-testingopenapi31fuzzinggessoopenapi-validator

###  Code Quality

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/studio-design-openapi-contract-testing/health.svg)

```
[![Health](https://phpackages.com/badges/studio-design-openapi-contract-testing/health.svg)](https://phpackages.com/packages/studio-design-openapi-contract-testing)
```

###  Alternatives

[tempest/framework

The PHP framework that gets out of your way.

2.3k37.6k21](/packages/tempest-framework)[cakephp/cakephp

The CakePHP framework

8.9k20.0M1.9k](/packages/cakephp-cakephp)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

86337.5k](/packages/flow-php-flow)[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

36826.2k2](/packages/telnyx-telnyx-php)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[growthbook/growthbook

PHP SDK for GrowthBook, the feature flagging and A/B testing platform

203.7M4](/packages/growthbook-growthbook)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
