Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ADR-0017: YAML cassettes wherever symfony/yaml is installed

Status: Accepted · Supersedes: ADR-0002 · Reference: PLAN.md §7 decisions 2, 63, 65

Context

ADR-0002 made JSON the default because YAML costs a dependency and the record/replay path may depend on nothing but the PSR packages.

Using the library made the other half of the trade-off concrete. A cassette is committed and read in review, and the thing most often read in it is a response body. JSON has to escape every newline in one, so an HTML or XML response arrives in a diff as a single line thousands of characters wide. YAML writes the same body as a literal block. The format that is nicer to read is the one nobody selects, because selecting it means knowing it exists.

Decision

The default format follows the project rather than the library: YamlCassetteSerializer where symfony/yaml is installed, JsonCassetteSerializer where it isn’t. A serializer named in http-vcr.php still wins over both.

symfony/yaml stays out of require. The dependency promise in §1 is about what the record/replay path needs, and a default that adapts to what is present keeps that intact, where a hard dependency would not.

Consequences

Good. The readable format is what a project with Symfony components already installed — which is most Laravel and Symfony projects — gets without choosing it. Nothing is added to anyone’s dependency tree.

Bad. The format now depends on the contents of vendor/, so two projects on the same version of http-vcr can record differently, and a project can change format by installing an unrelated package. Pinning the serializer in http-vcr.php is the answer where that matters, and it is one line.

Worse, and the reason migrate exists. A cassette is only ever looked for under the extension its serializer owns, so the day the default flips, existing .json cassettes stop being found: RecordIfAbsent re-records the lot against the real API, PlaybackOnly raises CassetteNotFoundException for every one. vendor/bin/http-vcr migrate --to=yaml rewrites them in place, and the CLI reference says so where the format is documented. A silent format detection that read both extensions would have avoided the migration entirely — at the cost of a project permanently able to hold two formats at once with nothing pointing it out.