A complete JavaScript/Node.js demo for:
The Complete Guide to API Versioning: Backward Compatibility Strategies for High-Traffic Systems
This project models a realistic social-commerce / marketplace backend with enough surface area to demonstrate how versioning decisions affect real APIs used by professional teams: products, orders, users, reviews, analytics, authentication, pagination, bulk operations, and webhooks.
It is designed for public Git hosting:
- No secrets are committed.
- No API keys are embedded.
- No fixed demo passwords are embedded in source control.
- Local demo credentials are generated at runtime unless you provide your own via environment variables.
- Production installs require an explicit
JWT_SECRET.
v1is deprecated and emitsDeprecation,Sunset, andLinkheaders.v2is the stable release.v3is the latest release with modern API patterns.
- URL-path versioning:
/api/v1,/api/v2,/api/v3 - Header-based version detection support:
API-Version: 2 - Media-type version detection support:
Accept: application/vnd.shopstream.v2+json - Query-param version detection support:
?api-version=2 - Field deprecation:
priceremains inv2, removed inv3 - Shape transformation adapters from one internal model to multiple public contracts
- Error contract evolution from legacy envelope to RFC 7807-style responses
- Auth migration from Basic Auth to JWT
- Pagination evolution from none -> offset -> cursor
- HATEOAS links and field selection in
v3 - Bulk endpoints and webhooks in
v3
The demo simulates a high-traffic commerce platform with:
- Users: buyers, sellers, admins
- Products: rich catalog entries with pricing, inventory, variants, media, SEO, shipping, ratings
- Orders: line items, payment, fulfillment, status history
- Reviews: verified-purchase flow and rating aggregation
- Analytics: seller dashboard
- Webhooks:
v3subscription model
server.js
src/
app.js
config/
data/
middleware/
routes/
v1/
v2/
v3/
services/
transformers/
utils/
validators/
tests/
The internal data model is version-neutral.
Public API contracts are produced through versioned transformers:
src/transformers/productTransformer.jssrc/transformers/userTransformer.jssrc/transformers/orderTransformer.js
That separation is the core backward-compatibility technique in this project.
npm installcopy .env.example .envFor local development, JWT_SECRET may be left empty and the app will generate an ephemeral value at runtime.
For production, set a strong JWT_SECRET explicitly.
npm run devor
npm start- Swagger UI:
http://localhost:3000/api-docs - OpenAPI JSON:
http://localhost:3000/api-docs.json - Frontend dashboard:
http://localhost:3000/dashboard - Health:
http://localhost:3000/health - Migration guide:
http://localhost:3000/docs/migration/v1-to-v2
If you do not provide seed passwords through environment variables, the app generates local credentials at startup and logs them to the console.
If you want deterministic local credentials, set these before startup:
SEED_ADMIN_PASSWORD=your-local-admin-password
SEED_SELLER_PASSWORD=your-local-seller-password
SEED_BUYER_PASSWORD=your-local-buyer-passwordThese values are optional and should not be committed.
Open the browser dashboard first if you want a visual side-by-side walkthrough:
http://localhost:3000/dashboardThe dashboard calls live endpoints and compares:
v1deprecated headers and flat fieldsv2transitional compatibility fields such aspricev3latest contract shape, cursor-oriented metadata, and richer nested objects
Then inspect the raw API directly:
curl http://localhost:3000/api/v1/productsNotice:
- Flat
price - Flat
stock images[]- No pagination
- Deprecation headers
curl http://localhost:3000/api/v2/products?page=1&limit=5Notice:
pricingobject added- deprecated
pricestill present - pagination metadata
X-Deprecated-Fields: price
curl "http://localhost:3000/api/v3/products?limit=3&fields=id,name,pricing.base"Notice:
- no
pricefield - cursor-based pagination metadata
- field selection
- richer
meta
v1 write flows accept Basic Auth.
v2 and v3 require JWT:
curl -X POST http://localhost:3000/api/v2/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"alice@shopstream.example","password":"YOUR_LOCAL_SELLER_PASSWORD"}'curl -X POST http://localhost:3000/api/v3/products/bulk \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"products": [
{
"name": "Bulk Demo Product",
"description": "Created via v3 bulk endpoint",
"pricing": { "base": 99, "currency": "USD" },
"inventory": { "sku": "BULK-001", "quantity": 10 }
}
]
}'- Deprecated
- Basic Auth allowed
- Legacy response envelope
- No pagination
- Simpler product and order shapes
- Stable
- JWT auth
- Offset pagination
- RFC 7807-style errors
- Transitional compatibility fields
- Seller analytics
- Latest
- Cursor pagination
- Field selection
- HATEOAS links
- Bulk operations
- Webhooks
- Scope-based authorization
Run the full test suite:
npm testTests cover:
v1deprecation headers and legacy shapev1route compatibility behaviorv2JWT login and transitional fieldsv3field selection and bulk route behavior- health/version state reporting
This repo is a demo, but it is structured so the upgrade path to a real production service is clear:
- Replace the in-memory store with PostgreSQL, MongoDB, or another persistent datastore.
- Move webhook secrets to encrypted-at-rest storage.
- Add refresh tokens, token rotation, and account lockout policies.
- Add structured request tracing and centralized log shipping.
- Replace local seeding with fixture loading or migration-based bootstrap.
- Add contract tests and consumer-driven compatibility tests.
- Add CI/CD, SAST, DAST, and deployment automation.
JWT_SECRETis required in production.- No secret values are hardcoded in the repository.
npm audit --omit=devis clean.- Runtime-generated local credentials are intended only for local demo use.
npm start
npm run dev
npm test
npm run test:v1
npm run test:v2
npm run test:v3
npm run test:coverageMIT