Metadata-Version: 2.4
Name: apicmp
Version: 0.1.0
Summary: Structurally diff two JSON responses or files — find added, removed, type-changed, and drifted fields
Project-URL: Homepage, https://github.com/gitwingo/apicmp
Project-URL: Repository, https://github.com/gitwingo/apicmp
Project-URL: Bug Tracker, https://github.com/gitwingo/apicmp/issues
Author-email: gitwingo <gitwingo@users.noreply.github.com>
License: MIT
License-File: LICENSE
Keywords: api,cli,developer-tools,diff,http,json,rest,testing
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Requires-Dist: httpx<1.0,>=0.27.0
Requires-Dist: rich>=13.7.0
Requires-Dist: typer>=0.12.0
Description-Content-Type: text/markdown

<div align="center">

<h1>apicmp</h1>

<p>Did this API quietly change? Find out in one command.</p>

[![PyPI version](https://img.shields.io/pypi/v/apicmp?color=d2a8ff&labelColor=0d1117&logo=pypi&logoColor=white)](https://pypi.org/project/apicmp)
[![Python](https://img.shields.io/pypi/pyversions/apicmp?color=d2a8ff&labelColor=0d1117&logo=python&logoColor=white)](https://pypi.org/project/apicmp)
[![License: MIT](https://img.shields.io/badge/license-MIT-d2a8ff?labelColor=0d1117)](LICENSE)
[![Downloads](https://img.shields.io/pypi/dm/apicmp?color=d2a8ff&labelColor=0d1117)](https://pypi.org/project/apicmp)

<img src="https://raw.githubusercontent.com/gitwingo/apicmp/main/docs/images/screenshot.png" alt="apicmp terminal screenshot" width="820">

</div>

---

APIs change silently. A field gets renamed. A type flips from string to integer. A key disappears. A number drifts 15% without anyone noticing.

`apicmp` compares two JSON responses — from URLs, files, or stdin — and tells you exactly what changed: fields added, fields removed, type changes, value changes, and numeric drift beyond a threshold.

No auth setup. No config files. No enterprise pricing. Just point it at two things and see the diff.

---

## Install

```bash
pip install apicmp
```

Or with pipx:

```bash
pipx install apicmp
```

---

## Usage

```bash
# Two live URLs
apicmp https://api.example.com/v1/user https://api.example.com/v2/user

# Two local files
apicmp before.json after.json

# File vs live URL
apicmp snapshot.json https://api.example.com/endpoint

# Pipe first response from stdin
curl https://api.example.com/v1 | apicmp - https://api.example.com/v2

# Flag numeric drift over 10% (default is 5%)
apicmp a.json b.json --threshold 0.1

# Add auth or custom headers
apicmp a.json b.json -H "Authorization: Bearer TOKEN"
apicmp a.json b.json -H "X-Api-Key: abc123"

# Export diff as Markdown
apicmp a.json b.json --output diff.md

# JSON output — pipe to jq
apicmp a.json b.json --format json | jq '.added'
```

---

## What it compares

`apicmp` flattens nested JSON to dot-notation paths and compares them structurally:

| Category | What it catches |
|---|---|
| **Added** | Keys present in B but not in A |
| **Removed** | Keys present in A but not in B |
| **Type changed** | Same key, different type (`string` → `integer`, `null` → `object`) |
| **Value changed** | Same key, same type, different value |
| **Numeric drift** | Numbers that changed beyond your threshold (default 5%) |

Nested objects are flattened — `user.address.city` is a single comparable path. Arrays are compared by index up to 20 elements, and array lengths are tracked separately.

---

## Output formats

**`--format table`** (default) — colour-coded rich terminal tables, one per change category.

**`--format markdown`** — GitHub-flavored Markdown, paste into PRs, wikis, or incident reports.

**`--format json`** — machine-readable, pipe to `jq` or use in scripts.

---

## All options

```
Arguments:
  SOURCE_A      First JSON source (URL, file, or '-' for stdin).
  SOURCE_B      Second JSON source (URL or file).

Options:
  -t, --threshold   Flag numeric values that differ by more than this fraction
                    (default: 0.05 = 5%).
  -H, --header      Extra HTTP headers (format: 'Name: Value'). Repeatable.
  --timeout         HTTP request timeout in seconds (default: 15).
  -o, --output      Write Markdown diff to this file.
  -f, --format      Output format: table | markdown | json (default: table).
  --help            Show this message and exit.
```

---

## Examples

**Snapshot an API before a deploy, diff after:**
```bash
curl https://api.example.com/user/1 > before.json
# deploy...
apicmp before.json https://api.example.com/user/1
```

**Compare staging vs production:**
```bash
apicmp https://staging.api.example.com/config \
         https://api.example.com/config \
         -H "Authorization: Bearer $TOKEN"
```

**Export diff for a PR comment:**
```bash
apicmp before.json after.json --output diff.md
cat diff.md
```

**Use in CI — fail if APIs diverge:**
```bash
apicmp snapshot.json https://api.example.com/endpoint \
  --format json | python -c "
import json, sys
d = json.load(sys.stdin)
if d['added'] or d['removed'] or d['type_changed']:
    sys.exit(1)
"
```

---

## Development

```bash
git clone https://github.com/gitwingo/apicmp
cd apicmp
pip install -e .
```
---
## Support

If apicmp has been useful to you, consider supporting its development:

<a href="https://ko-fi.com/gitwingo">
  <img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Buy Me a Ko-Fi" />
</a>


## Connect

- GitHub: [@gitwingo](https://github.com/gitwingo)
- Reddit: [u/gitwingo](https://reddit.com/user/gitwingo)
- X / Twitter: [@gitwingo](https://x.com/gitwingo)

---

<div align="center">
  <sub>Made with 💖 by <a href="https://github.com/gitwingo">Gitwingo</a></sub>
</div>

---

## License

MIT © [gitwingo](https://github.com/gitwingo)
