Jordan Smalls

Software Engineer

Go Home

Rail

Compares JSON API contracts, catches breaking changes before deployment, and stops risky builds before downstream clients are affected.

Summary

Rail is an API contract testing tool that detects breaking changes before they reach production. It compares two JSON responses, identifies the exact paths that changed, classifies each change as safe or breaking, and gives CI a reason to stop incompatible code from being deployed.

Problem

APIs rarely break because someone intentionally removes a critical field. More often, breaking changes are hidden inside otherwise reasonable refactors: a property is renamed, a number becomes a string, a nested object disappears, or the structure of an array changes.

These updates may look harmless from the backend, but downstream clients have built their own assumptions around the existing response. A single unexpected change can break a frontend, mobile application, generated SDK, or third-party integration.

The problem is timing. These incompatibilities are often discovered only after deployment—through failed requests, production errors, or reports from another team. At that point, the change has already become an incident.

Existing schema tools can help, but they often require teams to maintain extensive specifications or adopt a larger API-management workflow. I wanted something more direct: compare the response that existed before a pull request with the response it produces now, then report exactly what changed.

That became Rail.

Solution

Rail compares a baseline JSON contract against a candidate contract and recursively analyzes every object, property, and array position.

Each detected change includes its JSON path, previous value, current value, change type, and compatibility classification. Removing a field or changing its type is considered breaking, while additive changes are treated as safe.

Developers can explore comparisons through an interactive browser playground or run the same engine locally through the rail check CLI. Because the CLI returns CI-friendly exit codes, it can also block a pull request when a breaking contract change is detected.

The goal is simple: make API compatibility visible while a change is still being reviewed—not after it reaches production.

Features

  • JSON contract comparison: Compare baseline and candidate responses to see exactly how an API contract has changed.
  • Breaking-change detection: Rail identifies removed fields, removed array items, and value-type changes as potentially breaking.
  • Exact JSON paths: Every result points to the affected location, making it clear which field and downstream consumer may require attention.
  • Interactive playground: Paste or edit two JSON responses in the browser and inspect the results immediately. Processing happens locally, so contract data never leaves the browser.
  • Command-line interface: Run contract checks from the terminal with readable output or return structured JSON for other development tools.
  • CI-friendly exit codes: Rail exits successfully when a contract is compatible, fails when breaking changes are found, and distinguishes invalid input from compatibility failures.
  • GitHub Actions support: The CLI can compare a pull request’s contract with the version from its base commit, allowing teams to enforce compatibility through branch-protection rules.
  • Reusable comparison engine: The diff engine is independent of the interface, allowing the browser, CLI, and future GitHub integrations to share the same comparison behavior.

Architecture

  • Frontend: Next.js, React, TypeScript, Tailwind CSS
  • Core engine: Framework-independent TypeScript comparison and JSON-validation modules
  • CLI: Node.js, TypeScript, TSX
  • Testing: Vitest

Rail separates its recursive comparison engine from the Next.js application. This keeps the compatibility rules consistent across the interactive playground, local CLI, and future GitHub Action.

The engine walks both contracts recursively and produces structured change records containing the affected path, previous and current values, change type, and breaking status. These records can then be rendered for the web, formatted for the terminal, or serialized as JSON for automation.

Results

Rail turns API compatibility from an implicit assumption into an automated, testable part of development.

Instead of manually inspecting large JSON responses, developers receive a focused list of the fields that changed and whether each change could break a client. The same comparison logic works interactively in the browser, locally from the terminal, and inside continuous integration.

The current version includes a tested comparison engine, interactive contract playground, local CLI, machine-readable output, and CI-compatible status codes. A packaged CLI and first-party GitHub Action are planned as the next stage of the product.

By surfacing incompatible changes during code review, Rail helps teams catch the API break before they deploy.