Skip to content
KayforkindPublic

About

api-watch

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

Repository files navigation

api-watch

Know about the API change before your users do.

api-watch keeps a contract for every API response your app depends on. It re-checks the live endpoints on a schedule and tells you what broke, with a rename hint when a field simply moved.

  • Snapshot a contract from reality: api-watch init records the shape of a live JSON response.
  • Catch breaking changes: missing fields, changed types, wrong status, unreachable endpoints, non-JSON responses.
  • Catch deprecations early: Deprecation and Sunset headers, with a loud alert when a sunset is under 60 days away.
  • Rename hints: when email disappears and mail appears with the same type, it says so. These are hints to verify, not automatic fixes.
  • CI-native: exit codes, JSON and Markdown reports, and a ready-to-copy GitHub Action.
  • Zero dependencies. Node 20+ only. Nothing is sent anywhere except the requests you configure.

Quick start

node watch.mjs init users https://api.example.com/users/1 --out contracts.json
node watch.mjs check contracts.json
# API watch — 2026-10-09T12:28:37.913Z

Breaking: 0 · Warnings: 0 · Info: 0

## users (200)
- no changes

When a field is renamed:

## users (200)
- **BREAKING** missing field "email" (string); hint: "mail" (string) may be the renamed "email"

Commands

api-watch check <contracts.json> [--json out.json] [--md out.md]
                [--timeout 10000] [--fail-on breaking|warning]
api-watch init <name> <url> [--out contracts.json] [--header "Name: ${ENV_VAR}"]...
Exit Meaning
0 Clean (or only warnings, unless --fail-on warning)
1 Breaking change found
2 Bad input or usage error

Contract format

[
  {
    "name": "users",
    "url": "https://api.example.com/users/1",
    "expect": {
      "status": 200,
      "fields": { "id": "number", "email": "string" }
    }
  }
]

Set "array": true when the response is a list. Fields are then checked against the first element.

Private APIs

Add "headers" with ${ENV_VAR} placeholders. The value is read from the environment when you run the check, so the secret never lives in contracts.json:

{
  "name": "me",
  "url": "https://api.example.com/me",
  "headers": { "Authorization": "Bearer ${API_TOKEN}" },
  "expect": { "status": 200, "fields": { "id": "number" } }
}
API_TOKEN=... node watch.mjs check contracts.json
node watch.mjs init me https://api.example.com/me --header 'Authorization: Bearer ${API_TOKEN}'
  • If a variable is unset or empty, the check reports it as BREAKING and sends no request.
  • init refuses to save a literal value for credential headers (Authorization, Cookie, names containing token, secret, key). Use ${ENV_VAR} instead.
  • Reports include the contract name, URL, status, and findings. They never include header values.

Run it in CI

.github/workflows/api-watch.yml runs the check every morning and uploads the report as an artifact. The job fails only on breaking changes by default. For private APIs, pass credentials from repository secrets as environment variables, for example env: { API_TOKEN: ${{ secrets.API_TOKEN }} } on the check step.

What it does not do

  • It checks the top-level shape of JSON responses. It does not validate nested objects, formats, or ranges.
  • Rename hints are heuristics (same type, not in the contract). A human should confirm them.
  • It sends only the headers you list in a contract. It does not log in, refresh tokens, or handle OAuth flows. For those, put a token in an environment variable and reference it.

Development

npm test

Tests run against a local fixture server, so they need no network access.

License

MIT

About

api-watch

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages