Skip to content

infocyph/JsonDispatch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 

Repository files navigation

JsonDispatch – Developer Guide

Welcome! This site hosts the JsonDispatch specification and examples.

  • What is it? A lightweight, production-ready JSON response spec.
  • Why use it? Stable envelope (success/fail/error), server-generated tracing with X-Request-Id and clear version signaling via X-Api-Version.

Contents

1. Introduction
1.2 Why Another Spec?
1.3 Core Principles

2. Media Types & Versioning
2.1 Media Type Explained (with Examples)
2.2 Versioning Strategy (Major/Minor/Patch)
2.3 Required & Recommended Headers
2.4 Version Selection & Migration
2.5 Non-JSON Responses (Reports & Exports)
2.5.1 Direct File Delivery
2.5.2 Orchestration via JsonDispatch (Recommended)
2.5.3 Streaming & Large Datasets

3. Request & Response Identification
3.1 X-Request-Id – Server-Generated Trace ID
3.2 X-Correlation-Id – Linking Related Operations
3.3 Distributed Tracing (traceparent, tracestate)

4. Response Envelope (The Outer Wrapper)
4.1 Top-Level Members at a Glance
4.2 status — Success, Fail or Error
4.3 message — Keep It Human-Friendly
4.4 data — Your Actual Payload
4.5 _references — Turning IDs Into Meaning
4.6 _properties — Describing Data Context
4.7 _links — Pagination and Beyond
4.8 Envelope Summary

5. Response Examples
5.1 A Simple Success Response
5.2 A Fail Response (Validation Issue)
5.3 An Error Response (System Failure)
5.4 Paginated Collection Response
5.5 References in Action

6. Error Handling
6.1 fail vs error — Know the Difference
6.2 Error Object Structure
6.3 Field-Level vs Request-Level Errors
6.4 Error Codes (code) — Symbolic and Actionable
6.5 Recommended HTTP Status Mapping
6.6 Key Takeaways

7. Properties & References
7.1 _properties — Describe Your Data
7.2 _references — Replace IDs with Meaning
7.3 Choosing Between Them
7.4 Example — Combined in One Response
7.5 Nested _references Example

8. Links
8.1 _links for Pagination
8.2 _links for Related Resources
8.3 _links with Metadata (Enriched Links)
8.4 Best Practices for _links
8.5 _links for Files and Downloads
8.6 _links for Inline Media (Thumbnails, Avatars, Previews)

9. Compatibility & Evolution
9.1 Core Compatibility Rules
9.2 How to Introduce Breaking Changes
9.3 Recommended Evolution Workflow

10. Best Practices
10.1 Always Log X-Request-Id
10.2 Deprecation Lifecycle (Field or Endpoint Evolution)
10.3 Response Media Types & Fallbacks
10.4 Security Headers & CORS Policy Recommendations
10.5 Use _properties and _references Generously
10.6 Operational Logging, Correlation, Monitoring & Security

11. Appendix
11.1 Reserved Headers (Response Only)
11.2 Reserved Keywords (Top-Level JSON Keys)
11.3 Middleware & Utility Patterns
11.4 Minimal JSON Schema for the Envelope (Dev Tooling)
11.5 Example cURL Requests (Version & Headers)
11.6 Developer Notes


1. Introduction

JsonDispatch is a lightweight API response specification built on top of JSON. It defines a predictable, flexible response envelope for REST APIs so clients always know where to look for the status, data and helpful metadata.

Think of it as the contract between your backend and your clients (mobile, web, services). Instead of every project reinventing its own shape, JsonDispatch gives you:

  • Consistency — The same envelope across all endpoints
  • Traceability — Every response carries a server-generated X-Request-Id
  • Clarity — Clean separation between success, fail and error
  • Flexibility — Optional _references, _properties and _links for richer responses

1.2 Why another spec?

If you've worked with APIs before, you've probably seen:

  • { "ok": true } here
  • { "status": "success", "payload": … } there
  • And somewhere else… a raw stack trace in JSON. 😬

This chaos makes it hard to build generic clients, reason about failures and correlate logs across services. JsonDispatch standardizes the response shape while staying practical and easy to adopt in real systems.

1.3 Core Principles

JsonDispatch is built around a few simple rules:

Never remove, only add

Responses evolve, but we don't break clients. Deprecate fields instead of deleting them.

Trace everything (server-generated IDs)

The server must generate and return a unique X-Request-Id on every response (clients don't send it). This makes correlation and debugging straightforward.

Clear status semantics

  • success → Everything worked
  • fail → The request was invalid (validation, preconditions, etc.)
  • error → The server or a dependency failed

Flexible metadata when you need it

  • _references → Turn IDs into human-friendly values
  • _properties → Describe the data shape, pagination and deprecations
  • _links → Make collections navigable

Versioned but predictable

  • Response carries X-Api-Version (full SemVer) — clients can log and reason about the exact server implementation.
  • Accept stays application/json — clients don't need custom accept negotiation to consume JsonDispatch.

2. Media types & versioning

As your API evolves, clients need a stable way to understand which shape they're getting and how to migrate when it changes. JsonDispatch solves this by versioning request media types and signaling the exact server version in a response header.

2.1 Media type explained (with examples)

For requests with a body, set a JsonDispatch vendor media type in Content-Type:

Content-Type: application/vnd.infocyph.jd.v1+json

Media type breakdown

  • application → Application payload (static)
  • vnd.infocyph → Your vendor namespace (configurable)
  • jd → JsonDispatch spec identifier (static for this spec)
  • v1Major version of the request format (configurable)
  • +json → JSON syntax suffix (static)

Responses can simply use Content-Type: application/json while still following the JsonDispatch envelope.

Examples

  • Project "Acme": application/vnd.acme.jd.v1+json
  • Personal/OSS (not recommended for org APIs): application/prs.yourname.jd.v1+json

2.2 Versioning strategy (major/minor/patch)

JsonDispatch follows semantic Versioning:

  • Major (v1 → v2): Breaking changes to the envelope or field types
  • Minor (v1.1 → v1.2): Backward-compatible additions
  • Patch (v1.0.0 → v1.0.1): Backward-compatible bug fixes

Key point: The request media type carries the major version: …jd.v1+json. The server's full version is in X-Api-Version (e.g., 1.3.0).

  • Do not use Accept for version negotiation; keep it application/json if you send it at all.

2.3 Required & recommended headers

Requests (with body)

  • MUST send:

    Content-Type: application/vnd.<vendor>.jd.v<MAJOR>+json

    Example:

    Content-Type: application/vnd.infocyph.jd.v1+json
  • SHOULD NOT use Accept for versioning. If present, keep it:

    Accept: application/json

Responses

  • MUST send:

    X-Api-Version: <MAJOR.MINOR.PATCH>

    Example:

    X-Api-Version: 1.4.0
  • MAY send:

    Content-Type: application/json

    Note: Servers can still set a vendor media type on responses if needed, but application/json is sufficient and preferred.

X-Request-Id, X-Correlation-Id and other tracing headers are covered in Section 3.

2.4 Version selection & migration

  • The server controls the response envelope version. Clients do not negotiate via Accept.
  • When you introduce a breaking change, bump the request major (e.g., v1 → v2) and keep returning application/json in the response with an updated X-Api-Version.

Create (client → server)

POST /articles
Content-Type: application/vnd.infocyph.jd.v1+json

{ "title": "Hello JD" }

Response (server → client)

HTTP/1.1 201 Created
Content-Type: application/json
X-Api-Version: 1.4.0
X-Request-Id: 1f1f6a2e-0c8f-4f7f-9b4b-5d2d0a3f5b99

{
  "status": "success",
  "data": { ... }
}

After a breaking change (client updates request major):

POST /articles
Content-Type: application/vnd.infocyph.jd.v2+json

{ "title": "Hello JD v2" }

Server response

HTTP/1.1 201 Created
Content-Type: application/json
X-Api-Version: 2.0.0
X-Request-Id: 6c2a3d7e-9d5a-4b61-9b05-d1d8f6a8f4a1

{
  "status": "success",
  "data": { ... }
}

Clients signal request major via Content-Type (when they send a body) and servers announce the exact implementation via X-Api-Version in the response. No Accept gymnastics and responses stay plain application/json.

2.5 Non-JSON responses (reports & exports)

JsonDispatch defines the response envelope for JSON. For binary or tabular deliverables (CSV, PDF, ZIP, images), return the native media type directly and keep JsonDispatch for orchestration endpoints (job creation, metadata, links).

2.5.1 Direct file delivery

When the endpoint returns a file stream:

Request

GET /reports/activity/download?from=2025-09-01&to=2025-09-30
Accept: text/csv

Response

HTTP/1.1 200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="activity-report-2025-09.csv"
X-Api-Version: 1.4.0
X-Request-Id: 7bfae01e-771c-41d4-b1cf-0ad52d8bce19

Use the correct Content-Type (e.g., text/csv, application/pdf, application/zip) and add Content-Disposition for downloads.

2.5.2 Orchestration via JsonDispatch (recommended)

Create the report asynchronously and return a JsonDispatch envelope with status and links:

Request

POST /reports/activity
Content-Type: application/vnd.infocyph.jd.v1+json

{ "from": "2025-09-01", "to": "2025-09-30", "format": "csv" }

Response

HTTP/1.1 202 Accepted
Content-Type: application/json
X-Api-Version: 1.4.0
X-Request-Id: 3b2c7a5a-0b2e-4b69-b1a2-1a2c3d4e5f6a

Body

{
  "status": "success",
  "message": "Report job accepted",
  "data": {
    "report_id": "rep_9KfGH2",
    "state": "queued",
    "format": "csv",
    "expires_at": "2025-10-31T23:59:59Z"
  },
  "_links": {
    "self": "https://api.example.com/reports/activity/rep_9KfGH2",
    "download": {
      "href": "https://cdn.example.com/reports/rep_9KfGH2.csv",
      "meta": { "method": "GET", "expires": "2025-10-31T23:59:59Z" }
    }
  },
  "_properties": {
    "data": { "type": "object", "name": "report" }
  }
}

2.5.3 Streaming & large datasets

For very large exports, consider streaming formats:

  • CSV/TSV stream: text/csv
  • NDJSON stream: application/x-ndjson
  • Gzip: add Content-Encoding: gzip when appropriate

Pair streaming/download endpoints with a JsonDispatch status endpoint so clients can poll readiness and discover _links.download.

Status polling

GET /reports/activity/rep_9KfGH2
Accept: application/json

Response (ready)

HTTP/1.1 200 OK
Content-Type: application/json
X-Api-Version: 1.4.0
X-Request-Id: d1c9b15f-9c1e-42d5-9a9e-8b8e5a2b1c0a

Body

{
  "status": "success",
  "data": {
    "report_id": "rep_9KfGH2",
    "state": "ready",
    "size_bytes": 9421331
  },
  "_links": {
    "download": "https://cdn.example.com/reports/rep_9KfGH2.csv",
    "retry": "https://api.example.com/reports/activity/rep_9KfGH2/retry"
  }
}

Rule of thumb: Use JsonDispatch for control, status and discovery; use native media types for the actual file bytes.


3. Request & Response Identification

In production, the hardest bugs are the ones you can’t trace. JsonDispatch enforces consistent tracing identifiers on every response so developers can connect logs, monitor latency and debug across distributed systems — automatically.

3.1 X-Request-Id – server-generated trace ID

Every response must include a globally unique request identifier generated by the server. Clients do not send this header.

Rules

  • Generated once per inbound request (UUID v4, ULID or equivalent unique token).
  • Must be a string.
  • Included in all responses, including errors.
  • Logged internally for correlation in monitoring and debugging.

Example

Client → Server

GET /articles
Accept: application/json

Server → Client

HTTP/1.1 200 OK
Content-Type: application/json
X-Api-Version: 1.4.0
X-Request-Id: 7e0e7b45-1e89-4a7f-bbd3-f7ac73fae951

👉 When a user reports an issue, the X-Request-Id from the response can be searched in logs to reconstruct the full execution path.

3.2 X-Correlation-Id – linking related operations

When multiple requests belong to the same business operation (e.g., checkout, batch processing, workflow chains), a shared correlation ID links them together.

Rules

  • Optional.
  • May be provided by a client or generated at the workflow entry point.
  • The server echoes it in the response and propagates it to any downstream service calls.
  • Must be a string, unique per logical workflow.

Example

Client → Server

POST /checkout
Content-Type: application/vnd.infocyph.jd.v1+json
X-Correlation-Id: order-2025-10-05-777

{ "cartId": "C10045" }

Server → Client

HTTP/1.1 201 Created
Content-Type: application/json
X-Api-Version: 1.4.0
X-Request-Id: 019fb440-4e83-4b1b-bef9-44a80771f181
X-Correlation-Id: order-2025-10-05-777

If the checkout flow triggers downstream services (e.g., payments, shipping), each internal call must reuse the same correlation ID.

3.3 Distributed tracing (traceparent, tracestate)

For systems instrumented with distributed-tracing tools such as OpenTelemetry, Jaeger or Zipkin, JsonDispatch is compatible with the W3C Trace Context.

These headers complement (not replace) JsonDispatch identifiers:

  • traceparent → carries trace ID and span ID.
  • tracestate → vendor-specific trace metadata.

Example

GET /profile
Accept: application/json
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
tracestate: congo=t61rcWkgMzE

Response

HTTP/1.1 200 OK
Content-Type: application/json
X-Api-Version: 1.4.0
X-Request-Id: 1b0c9d4b-eaa2-40d0-8715-fc93e6fefb99
X-Correlation-Id: session-998877
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
tracestate: congo=t61rcWkgMzE

Summary

Header Direction Purpose Required
X-Request-Id Response → Unique server-generated request trace ID ✅ Yes
X-Correlation-Id Both ↔ Link related requests in a workflow ⚪ Optional
X-Api-Version Response → Server JsonDispatch version identifier ✅ Yes
traceparent Both ↔ Distributed tracing (W3C) ⚪ Optional
tracestate Both ↔ Vendor-specific tracing metadata ⚪ Optional

4. Response Envelope (The Outer Wrapper)

Every JsonDispatch response is wrapped in a predictable, minimal envelope. This gives every API the same shape — regardless of what the data is — making client logic simpler and responses easier to debug.

The envelope helps you quickly understand:

  • what happened (status, message)
  • what’s returned (data)
  • how to interpret it (_properties)
  • how to resolve references (_references)
  • how to navigate further (_links)

4.1 Top-Level Members at a Glance

A JsonDispatch response body may contain these top-level members:

Key Type Required Purpose
status string Overall result — success, fail or error
message string Short, human-readable explanation
data mixed Main payload (object, array or scalar)
_references object ID-to-label mapping dictionary
_properties object Metadata describing structure, count or schema
_links object Navigation links (pagination, related resources)

⚪ = optional, depending on the status value and context.

4.2 status — Success, Fail or Error

The status field defines the overall outcome of the request.

  • success → The request completed successfully and data is returned.
  • fail → The client provided invalid input (validation, missing fields, etc.).
  • error → The server or an external dependency failed to process the request.

Example

{
  "status": "success",
  "data": {
    "id": 42,
    "title": "JsonDispatch in Action"
  }
}

4.3 message — Keep It Human-Friendly

message is a short sentence for humans (not parsers). Use it as a quick, meaningful summary in logs or UI alerts.

Context Example message
success "Article fetched successfully"
fail "Invalid email address"
error "Payment service unavailable"

4.4 data — Your Actual Payload

Everything your API returns lives under data. The format should remain consistent for the same (version, method and endpoint) combination.

Status Expected data type Description
success object / array / any The requested resource(s).
fail array List of validation issues.
error array List of system or dependency errors.

Example — Success Payload

"data": {
  "type": "article",
  "attributes": {
    "id": 42,
    "title": "JsonDispatch in Action",
    "category": 1
  }
}

4.5 _references — Turning IDs Into Meaning

Instead of making clients hard-code enums or category lookups, _references provides an instant dictionary for ID resolution.

Example

{
  "_references": {
    "category": {
      "1": "News",
      "2": "Tutorial",
      "3": "Opinion"
    }
  }
}

Now clients can map "category": 2 → “Tutorial” without additional API calls.

4.6 _properties — Describing Data Context

_properties gives structure-level metadata that describes your payload — useful for UI builders, pagination or deprecation notices.

Common keys include:

Key Type Purpose
type string Resource type (array, object, etc.)
name string Logical name of the resource
count int Total item count (if paginated)
page int Current page number (if applicable)
range string Item range in current response (e.g., "21–40")
template url Optional schema or structure reference
deprecation url Optional migration or deprecation notice

Example

"_properties": {
  "data": {
    "type": "array",
    "name": "articles",
    "count": 20,
    "page": 2,
    "range": "21–40",
    "deprecation": "https://api.example.com/docs/v2/articles"
  }
}

4.7 _links — Pagination and Beyond

_links makes your API navigable. It can include pagination links, related resources or documentation references.

Example — Pagination

{
  "_links": {
    "self": "https://api.example.com/articles?page=2",
    "next": "https://api.example.com/articles?page=3",
    "prev": "https://api.example.com/articles?page=1"
  }
}

Example — Related Resources

{
  "_links": {
    "self": "https://api.example.com/articles/42",
    "author": "https://api.example.com/users/99",
    "comments": "https://api.example.com/articles/42/comments"
  }
}

4.8 Envelope Summary

Section Purpose Optional
status Defines success/fail/error outcome ❌ No
message Human-readable summary ⚪ Yes
data Payload or error details ⚪ Yes
_references Lookup tables for enums or IDs ⚪ Yes
_properties Metadata about the response ⚪ Yes
_links Pagination or relational navigation ⚪ Yes

👉 Together, these create a consistent, machine-parsable yet human-friendly response pattern across all JsonDispatch APIs.


5. Response Examples

Examples are the fastest way to understand JsonDispatch. Below are common scenarios — success, fail, error and paginated responses — exactly as they should appear in production.

5.1 A Simple Success Response

Request

GET /articles/42
Accept: application/json

Response

HTTP/1.1 200 OK
Content-Type: application/json
X-Api-Version: 1.3.1
X-Request-Id: aabbccdd-1122-3344-5566-77889900aabb

Body

{
  "status": "success",
  "message": "Article fetched successfully",
  "data": {
    "type": "article",
    "attributes": {
      "id": 42,
      "title": "JsonDispatch in Action",
      "category": 2
    }
  },
  "_references": {
    "category": {
      "1": "News",
      "2": "Tutorial",
      "3": "Opinion"
    }
  }
}

5.2 A Fail Response (Validation Issue)

Request

POST /articles
Content-Type: application/vnd.infocyph.jd.v1+json
Accept: application/json

Body

{
  "title": "Hi",
  "category": 5
}

Response

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
X-Api-Version: 1.3.1
X-Request-Id: f4b44a6e-d593-11ec-9d64-0242ac120002

Body

{
  "status": "fail",
  "message": "Validation failed",
  "data": [
    {
      "status": 422,
      "source": "/data/attributes/title",
      "title": "Title too short",
      "detail": "The title must be at least 5 characters long."
    },
    {
      "status": 422,
      "source": "/data/attributes/category",
      "title": "Invalid category",
      "detail": "Category must be one of: 1, 2, 3."
    }
  ]
}

5.3 An Error Response (System Failure)

Request

GET /articles
Accept: application/json

Response

HTTP/1.1 503 Service Unavailable
Content-Type: application/json
X-Api-Version: 1.3.1
X-Request-Id: c043e23a-4b26-4a05-96c4-5c60fcc18d50

Body

{
  "status": "error",
  "message": "Temporary backend outage",
  "code": "ARTICLES_SERVICE_DOWN",
  "data": [
    {
      "status": 503,
      "source": "articles-service",
      "title": "Service unavailable",
      "detail": "The Articles microservice is currently offline."
    }
  ]
}

5.4 Paginated Collection Response

Request

GET /articles?page=2&limit=3
Accept: application/json

Response

HTTP/1.1 200 OK
Content-Type: application/json
X-Api-Version: 1.3.1
X-Request-Id: 77aa88bb-ccdd-eeff-0011-223344556677

Body

{
  "status": "success",
  "message": "Articles listed successfully",
  "data": [
    {
      "type": "article",
      "attributes": {
        "id": 4,
        "title": "Scaling JsonDispatch",
        "category": 1
      }
    },
    {
      "type": "article",
      "attributes": {
        "id": 5,
        "title": "Error Handling Patterns",
        "category": 3
      }
    },
    {
      "type": "article",
      "attributes": {
        "id": 6,
        "title": "Backward Compatibility Rules",
        "category": 2
      }
    }
  ],
  "_properties": {
    "data": {
      "type": "array",
      "name": "articles",
      "count": 3,
      "page": 2,
      "range": "4–6"
    }
  },
  "_links": {
    "self": "https://api.example.com/articles?page=2&limit=3",
    "next": "https://api.example.com/articles?page=3&limit=3",
    "prev": "https://api.example.com/articles?page=1&limit=3"
  },
  "_references": {
    "category": {
      "1": "News",
      "2": "Tutorial",
      "3": "Opinion"
    }
  }
}

5.5 References in Action

Clients no longer need to fetch category labels from another endpoint:

"attributes": {
  "id": 42,
  "title": "JsonDispatch in Action",
  "category": 2
}

Can be immediately resolved using _references:

"_references": {
  "category": {
    "1": "News",
    "2": "Tutorial",
    "3": "Opinion"
  }
}

category: "Tutorial"

Key Takeaways

  • Responses always have Content-Type: application/json.
  • X-Api-Version and X-Request-Id are generated by the server, not clients.
  • The envelope is consistent — clients only need to check status and read data.

6. Error Handling

Errors are where consistency matters most. If every service formats errors differently, debugging turns into chaos. JsonDispatch enforces a clean, uniform structure for client-side issues (fail) and server-side issues ( error) — so you always know where the problem came from.

6.1 fail vs error — Know the Difference

Type Cause Who Fixes It Typical HTTP Status Example
fail The client sent something invalid The client 400 – 422 Missing required fields, invalid format
error The server or an external dependency failed The server 500 – 504 Timeout, DB crash, network outage

Think of it like this:

  • 🧑‍💻 fail“Fix your request and try again.”
  • 🧩 error“It’s not you, it’s us.”

This split helps:

  • Clients decide whether to retry or correct their data.
  • Developers log and alert on real outages separately from validation noise.

6.2 Error Object Structure

Both fail and error responses contain an array of objects under data. Each describes one issue in a standard format:

Field Type Description
status integer HTTP status code for this error
source string Where the problem occurred — field path or subsystem name
title string Short summary of the problem
detail string Human-readable explanation for logs or UI

Example – Client Validation (fail)

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
X-Api-Version: 1.3.1
X-Request-Id: 9d2e7f6a-2f3b-45b0-9ff2-dc3d99991234
{
  "status": "fail",
  "message": "Validation failed",
  "data": [
    {
      "status": 422,
      "source": "/data/attributes/email",
      "title": "Invalid email",
      "detail": "Email must be a valid address."
    },
    {
      "status": 422,
      "source": "/data/attributes/password",
      "title": "Password too short",
      "detail": "Password must be at least 8 characters."
    }
  ]
}

Example – Server Outage (error)

HTTP/1.1 503 Service Unavailable
Content-Type: application/json
X-Api-Version: 1.3.1
X-Request-Id: e13a97b3-5a2d-46db-a3b2-f401239b0cba
{
  "status": "error",
  "message": "Database unavailable",
  "code": "DB_CONN_TIMEOUT",
  "data": [
    {
      "status": 503,
      "source": "db-service",
      "title": "Timeout",
      "detail": "No response from database after 30s."
    }
  ]
}

6.3 Field-level vs request-level errors

JsonDispatch lets you express where an issue occurred so clients can react precisely.

Two scopes:

  • Field-level — a specific input is invalid. Use a JSON Pointer–style path in source (e.g., /data/attributes/email).
  • Request-level — the whole request failed for a non-field reason (rate limit, auth, dependency outage). Use a concise string naming the subsystem or concern (e.g., auth, rate-limit, payments-gateway).

Rules

  • Prefer the most specific source you can provide.
  • You may mix field-level and request-level items in the same data array.
  • Keep title short; put human-friendly detail in detail.
  • Don’t leak internals; subsystem names should be stable, public-safe identifiers.

Examples

Field-level (fail)

{
  "status": "fail",
  "message": "Validation failed",
  "data": [
    {
      "status": 422,
      "source": "/data/attributes/email",
      "title": "Invalid email",
      "detail": "Email must be a valid address."
    },
    {
      "status": 422,
      "source": "/data/attributes/age",
      "title": "Out of range",
      "detail": "Age must be between 13 and 120."
    }
  ]
}

Request-level (error)

{
  "status": "error",
  "message": "Upstream dependency unavailable",
  "code": "PAYMENTS_GATEWAY_DOWN",
  "data": [
    {
      "status": 503,
      "source": "payments-gateway",
      "title": "Service unavailable",
      "detail": "No response from provider within 30s."
    }
  ]
}

Mixed (some fields invalid, plus a request constraint)

{
  "status": "fail",
  "message": "Request cannot be processed",
  "data": [
    {
      "status": 422,
      "source": "/data/attributes/items/0/sku",
      "title": "Unknown SKU",
      "detail": "SKU ABC-123 was not found."
    },
    {
      "status": 429,
      "source": "rate-limit",
      "title": "Too many requests",
      "detail": "Burst limit exceeded; retry after 15 seconds."
    }
  ]
}

Client guidance

  • Highlight fields with pointer paths; show inline messages near inputs.
  • Banner or dialog for request-level issues (auth, rate-limit, maintenance).
  • Consider status code for retry/backoff behavior (see the next subsections).

6.4 Error Codes (code) — Symbolic and Actionable

The optional top-level code field adds a business-level meaning beyond the HTTP status. It’s ideal for client logic, dashboards and automation.

Guidelines

  • Use uppercase UPPER_SNAKE_CASE.
  • Keep them short and descriptive.
  • Document them in your internal or public API guide.
  • Stay consistent across microservices.

Examples

Code Meaning
USER_NOT_FOUND The requested user doesn’t exist
DB_CONN_TIMEOUT Database connection timeout
PAYMENT_GATEWAY_DOWN Payment provider not reachable
ARTICLE_TITLE_TOO_SHORT Validation failure on title

6.5 Recommended HTTP Status Mapping

Scenario status HTTP Status
Read / List / Create / Update Success success 200 / 201 / 204
Validation error / bad input fail 400 / 422
Authentication required or failed fail 401
Forbidden (no permission) fail 403
Not found fail 404
Conflict (duplicate / version mismatch) fail 409
Server exception / crash error 500
Bad gateway (upstream failure) error 502
Service unavailable / maintenance error 503
Upstream timeout error 504

6.6 Key Takeaways

  • Clients never send X-Request-Id — the server generates it for traceability.
  • All error and fail responses share the same envelope shape.
  • Each issue in data[] must be explicit and readable.
  • code + status + X-Request-Id = everything you need for quick debugging.

7. Properties & References

JsonDispatch goes beyond just returning status and data. It introduces two companion sections — _properties and _references — to make responses self-descriptive and * context-aware* without extra API calls.

7.1 _properties — Describe Your Data, Not Just Send It

The _properties object carries metadata about the data field. It helps clients understand the payload’s structure, count, pagination and even its lifecycle (like deprecation or schema changes).

Field Type Purpose
type string Type of data (array, object, string, number, boolean)
name string Logical name for this data block
template string (URL) Optional link to a JSON Schema or template definition
deprecation string (URL) Optional link marking this resource as deprecated
count integer Total number of items if the data is an array
range string Range of records in paginated results (e.g., "21-40")
page integer Current page number, if paginated

Example

"_properties": {
    "data": {
        "type": "array",
        "name": "articles",
        "count": 20,
        "page": 2,
        "range": "21-40",
        "deprecation": "https://api.example.com/docs/v2/articles"
    }
}

This tells the client:

  • The data is an array named articles.
  • It contains 20 items, displaying page 2 (items 21–40).
  • The endpoint is deprecated in favor of the linked v2 spec.

Best practice: Always include at least type and name. This enables automated clients (CLI tools, SDKs, data grids) to interpret results correctly.

7.2 _references — Replace IDs with Meaning

The _references object defines lookup tables that map internal IDs or codes to human-readable labels. It eliminates the need for extra “dictionary” or “enum” endpoints.

Example

"_references": {
    "category": {
        "1": "News",
        "2": "Tutorial",
        "3": "Opinion"
    },
    "status": {
        "A": "Active",
        "I": "Inactive",
        "S": "Suspended"
    }
}

When a record includes "category": 2, the client can instantly render “Tutorial” using the mapping.

Best practice: Keep keys short and meaningful (e.g., category, status, role). These should directly correspond to the field names inside data.

7.3 Choosing Between Them

Use Case Use _properties Use _references
Describe structure, pagination or schema
Translate IDs or codes to labels
Mark field as deprecated or link to template
Enumerate possible options or states

7.4 Example — Combined in One Response

{
  "status": "success",
  "message": "Articles listed successfully",
  "data": [
    {
      "id": 1,
      "title": "Intro to JsonDispatch",
      "category": 1
    },
    {
      "id": 2,
      "title": "Error Handling Patterns",
      "category": 3
    }
  ],
  "_properties": {
    "data": {
      "type": "array",
      "name": "articles",
      "count": 2,
      "page": 1,
      "range": "1-2"
    }
  },
  "_references": {
    "category": {
      "1": "News",
      "2": "Tutorial",
      "3": "Opinion"
    }
  }
}

Clients can now:

  • Display labels directly using _references.
  • Understand that data is paginated and typed via _properties.
  • Do all this without extra round-trips or hard-coded logic.

7.5 Nested _references Example

Complex datasets often include hierarchical or multi-level relationships — e.g. categories, subcategories or status groups. JsonDispatch supports nested _references so you can express those relationships cleanly while keeping the payload compact.

This allows clients to resolve multi-level identifiers without multiple API calls.

Example — Category → Subcategory → Label Mapping

{
  "status": "success",
  "message": "Product list with hierarchical references",
  "data": [
    { "id": 1, "name": "iPhone 15", "category": 10, "subcategory": 101 },
    { "id": 2, "name": "Galaxy S24", "category": 10, "subcategory": 102 },
    { "id": 3, "name": "MacBook Air", "category": 20, "subcategory": 201 }
  ],
  "_references": {
    "category": {
      "10": {
        "label": "Mobile",
        "children": {
          "101": "Apple",
          "102": "Samsung"
        }
      },
      "20": {
        "label": "Laptop",
        "children": {
          "201": "Apple",
          "202": "Windows"
        }
      }
    }
  },
  "_properties": {
    "data": {
      "type": "array",
      "name": "products",
      "count": 3
    }
  }
}

Explanation

Field Purpose
category Maps high-level IDs (10, 20) to parent labels
children Maps subcategory IDs to their names under each parent
label A friendly label for the parent category
_references Keeps the hierarchy readable and cacheable on the client

Why it matters

  • Fewer round-trips — clients can render category and subcategory labels directly.
  • Extensible — future nesting levels (e.g., regions → countries → cities) follow the same pattern.
  • Localized references_references can hold language-specific labels if needed.

Client behavior

When parsing, clients should:

  1. Resolve subcategory first within its parent category.
  2. Fallback to top-level label if no match found.
  3. Cache _references by version to avoid redundant lookups.

Best practice: Use nested _references only when relationships are stable and bounded. For dynamic trees, prefer dedicated endpoints (/categories, /locations).


8. Links

APIs aren’t just about data — they’re about navigating between resources. JsonDispatch provides a _links object that helps clients discover where to go next without guessing or relying on hard-coded routes.

The goal is simple: ➡️ Make your API self-navigable — so clients can move through it like a website, not a maze.

8.1 _links for Pagination

Whenever your response includes a collection or list, include pagination links to guide the client.

Key Purpose
self URL of the current page
next Next page (if available)
prev Previous page (if available)
first First page in the dataset
last Last page in the dataset

Example

"_links": {
    "self": "https://api.example.com/articles?page=2&limit=10",
    "next": "https://api.example.com/articles?page=3&limit=10",
    "prev": "https://api.example.com/articles?page=1&limit=10",
    "first": "https://api.example.com/articles?page=1&limit=10",
    "last": "https://api.example.com/articles?page=50&limit=10"
}

This lets clients paginate seamlessly — no manual query-building or separate pagination logic required.

Tip: Include self in every response. It makes your payload self-documenting when viewed in isolation.

8.2 _links for Related Resources

Beyond pagination, _links can expose relationships or related resources. These hints tell the client where additional or contextual information lives.

Example

"_links": {
    "self": "https://api.example.com/articles/42",
    "author": "https://api.example.com/users/99",
    "comments": "https://api.example.com/articles/42/comments",
    "related": "https://api.example.com/tutorials/jsondispatch"
}

Now, clients can:

  • Navigate to the author or comments without extra documentation.
  • Preload related data efficiently.
  • Treat your API like a graph of connected resources.

8.3 _links with Metadata (Enriched Links)

Sometimes you need to describe how a link should be used — not just where it points. In such cases, _links entries can be full objects containing an href and a meta section.

Example

"_links": {
  "self": {
    "href": "https://api.example.com/articles/42",
    "meta": {
      "method": "GET",
      "auth": "required"
    }
  },
  "edit": {
    "href": "https://api.example.com/articles/42",
    "meta": {
      "method": "PUT",
      "auth": "editor-role"
    }
  },
  "delete": {
    "href": "https://api.example.com/articles/42",
    "meta": {
      "method": "DELETE",
      "auth": "admin-role"
    }
  }
}

This pattern makes _links expressive and safe for HATEOAS-style APIs. It tells clients both where to go and how to interact, without needing extra documentation.

8.4 Best Practices for _links

  • Always include self. It’s essential for debugging and introspection.
  • Keep URLs absolute (never relative).
  • Use consistent naming (next, prev, author, related, edit, delete, etc.).
  • Avoid embedding authentication tokens directly in URLs.
  • When possible, pair _links with _properties to describe pagination metadata (page, count, etc.).

8.5 _links for Files and Downloads

APIs frequently serve or reference files — such as reports, invoices, exports or media. JsonDispatch supports this cleanly through _links, using either direct URLs or expirable signed URLs under a dedicated file or download key.

This keeps your responses self-descriptive, avoids embedding raw file data and enables clients to access assets securely.

Example — Direct File Link (Public Resource)

{
  "status": "success",
  "message": "Activity report generated successfully",
  "data": {
    "report_id": "RPT-2025-10-06",
    "type": "activity",
    "period": "2025-09",
    "size": "2.4 MB"
  },
  "_links": {
    "self": "https://api.example.com/reports/RPT-2025-10-06",
    "file": "https://cdn.example.com/reports/RPT-2025-10-06.pdf"
  },
  "_properties": {
    "data": {
      "type": "object",
      "name": "report"
    }
  }
}

✅ Use this when files are public or long-lived (e.g., CDN-hosted assets or documentation).

Example — Signed File Link (Secure or Temporary Access)

{
  "status": "success",
  "message": "Report ready for download",
  "data": {
    "report_id": "RPT-2025-10-06",
    "type": "activity",
    "expires_in": 900
  },
  "_links": {
    "self": "https://api.example.com/reports/RPT-2025-10-06",
    "download": {
      "href": "https://api.example.com/reports/RPT-2025-10-06/download?token=eyJhbGciOiJIUzI1...",
      "meta": {
        "method": "GET",
        "auth": "required",
        "expires": "2025-10-06T12:30:00Z"
      }
    }
  }
}

✅ Use this when:

  • Files are user-specific or sensitive (exports, invoices, personal data).
  • Links must expire or require authentication.
  • You want to guide clients explicitly on how to fetch the file (via meta).

Example — Multiple File Formats

{
  "_links": {
    "pdf": "https://cdn.example.com/reports/RPT-2025-10-06.pdf",
    "csv": "https://cdn.example.com/reports/RPT-2025-10-06.csv",
    "json": "https://api.example.com/reports/RPT-2025-10-06.json"
  }
}

Clients can choose their preferred format programmatically — ideal for exports or analytics dashboards.

Best Practices

Guideline Why
Always use HTTPS links Prevents man-in-the-middle interception
Include meta when authentication or expiry applies Clients can display expiry timers or handle refresh logic
Avoid embedding file data inline Reduces payload size and memory footprint
Prefer download over generic link names Keeps semantics consistent across endpoints

✅ Summary

File links under _links make your API:

  • Predictable → consistent structure for downloads
  • Secure → signed URLs and metadata guidance
  • Portable → clients can consume them without custom conventions

Perfect — here’s the next addition, 8.6 Inline Media References (Thumbnails, Avatars, etc.), written in the same tone, format and Markdown structure as your doc. It directly complements 8.5 File Link Example, keeping _links consistent across data and media use cases.

8.6 _links for Inline Media (Thumbnails, Avatars, Previews)

Not every file link is a downloadable document — many APIs include media previews such as user avatars, product thumbnails or video stills. JsonDispatch keeps this consistent by defining them under _links.media or _links.image, so clients can handle them predictably.

Example — Simple Inline Media Links

{
  "status": "success",
  "message": "User profile fetched successfully",
  "data": {
    "id": 99,
    "name": "A. B. M. Mahmudul Hasan",
    "role": "admin"
  },
  "_links": {
    "self": "https://api.example.com/users/99",
    "avatar": "https://cdn.example.com/avatars/99-thumb.jpg"
  },
  "_properties": {
    "data": {
      "type": "object",
      "name": "user"
    }
  }
}

✅ Ideal for lightweight references such as user photos, brand icons or thumbnail images.

Example — Media with Multiple Resolutions or Types

{
  "_links": {
    "self": "https://api.example.com/products/2001",
    "image": {
      "small": "https://cdn.example.com/products/2001/small.jpg",
      "medium": "https://cdn.example.com/products/2001/medium.jpg",
      "large": "https://cdn.example.com/products/2001/large.jpg"
    }
  }
}

Clients can choose which variant to use — perfect for responsive frontends or apps that cache different image sizes.

Example — Rich Media Metadata

When returning multiple images, videos or icons, each media entry can include metadata for display and accessibility:

{
  "_links": {
    "thumbnail": {
      "href": "https://cdn.example.com/products/2001/thumb.webp",
      "meta": {
        "width": 120,
        "height": 120,
        "type": "image/webp",
        "alt": "Product preview image"
      }
    },
    "video_preview": {
      "href": "https://cdn.example.com/products/2001/preview.mp4",
      "meta": {
        "duration": 12,
        "type": "video/mp4",
        "poster": "https://cdn.example.com/products/2001/thumb.jpg"
      }
    }
  }
}

✅ This allows advanced clients (e.g. web dashboards, mobile apps) to render previews, use proper MIME types and preload efficiently.

Best Practices

Guideline Reason
Use separate keys for image vs. video (e.g. avatar, thumbnail, video_preview) Keeps structure clear and predictable
Include meta.type for MIME hints (image/png, video/mp4) Helps browsers and SDKs preload correctly
Prefer WebP or AVIF for image efficiency Saves bandwidth for clients
Use _links — not _references — for any URL-based assets Keeps semantics clean (navigation vs lookup)

✅ Summary

Inline media links under _links let APIs describe:

  • Where assets are located (href)
  • What they are (meta.type, meta.alt)
  • How to use them (variants, resolutions, roles)

They make your API visual-friendly, cache-efficient and self-documenting — no guesswork or extra endpoints needed.


9. Compatibility & Evolution

JsonDispatch is designed for long-lived APIs that evolve gracefully without breaking existing clients. The guiding principle is simple:

⚙️ Evolve forward, never break back.

9.1 Core Compatibility Rules

When making changes to your API responses:

  • Never remove a field. Old clients may still depend on it.

  • Never change the type of an existing field. A string should never become an object and an object should never become an array.

  • Only add new fields (preferably optional ones with sensible defaults).

  • Deprecate before removing. Mark old fields with _properties.deprecation and provide documentation for migration.

Example

{
  "_properties": {
    "legacyTitle": {
      "type": "string",
      "name": "legacy-title",
      "deprecation": "https://api.example.com/docs/v2/articles#title"
    }
  }
}

This approach ensures:

  • Older clients keep working as expected.
  • Newer clients can progressively adopt new structures.

9.2 How to Introduce Breaking Changes

When a breaking change becomes necessary:

  1. Increment the major version in the response’s Content-Type.

    Content-Type: application/vnd.infocyph.jd.v2+json
    X-Api-Version: 2.0.0
  2. Maintain the old major version (v1) in production for a transition period. Deprecate it gradually using communication and version headers.

  3. Publish updated documentation for each major version side-by-side.

  4. Avoid “soft breaks” (changing existing semantics without version bumps). Always be explicit.

9.3 Recommended Evolution Workflow

Step Action Example
1 Add field Add _properties.template
2 Mark old field deprecated _properties.oldField.deprecation
3 Announce upcoming version Changelog + docs
4 Introduce new major version v2 media type
5 Sunset old version Remove after clients migrate

10. Best Practices

JsonDispatch provides structure — but your team’s discipline keeps it reliable. These best practices ensure consistency, observability and developer happiness.

10.1 Always log X-Request-Id

  • The server generates a unique X-Request-Id for each response.
  • Include it in all logs, traces and monitoring dashboards.
  • When an issue occurs, that single ID traces the request end-to-end.

✅ Treat it as your primary debugging handle.

10.2 Deprecation Lifecycle (Field or Endpoint Evolution)

Deprecation in JsonDispatch isn’t just about marking things as “old.” It’s about communicating intent clearly — to humans and machines — so clients can migrate smoothly without breaking.

Below is the recommended lifecycle for any field, structure or endpoint change.

Phase Description Duration / Expectation Implementation Pattern Example
1. Active (Default) Field is stable and supported. Ongoing Regular use; documented and visible. "title": "Hello World"
2. Announce Deprecation You’ve introduced a replacement field or version. 1 release cycle minimum before enforcement Mark in _properties.deprecation with URL + replacement reference. "legacyTitle": { "deprecation": "https://api.example.com/docs/v2/articles#title" }
3. Dual Support Phase Both old and new fields coexist; clients update gradually. 1–2 release cycles Continue returning both values; prefer new one in docs and examples. Old → legacyTitle, New → title
4. Soft Removal (Warn Only) Old field still exists but returns a notice or null. 1 cycle max Include _properties.legacyTitle.deprecation + log warnings in responses. "legacyTitle": null + metadata link
5. Hard Removal Field is no longer returned; major version bump required. Next major release Remove from payload; update JSON Schema and docs. Removed in v2

Example — Deprecation Metadata in Action

{
  "status": "success",
  "message": "Article listed with deprecated field notice",
  "data": {
    "id": 42,
    "legacyTitle": "Hello JD (legacy)",
    "title": "Hello JsonDispatch"
  },
  "_properties": {
    "legacyTitle": {
      "type": "string",
      "deprecation": "https://api.example.com/docs/v2/articles#title"
    },
    "title": {
      "type": "string",
      "name": "title"
    }
  }
}

✅ The _properties.legacyTitle.deprecation URL gives developers a clear migration path — and automated tools can detect deprecation without guessing.

Quick Rules of Thumb

Rule Why
Never remove without prior deprecation notice Prevents client crashes
Always provide documentation link Enables auto-migration and transparency
Keep dual support phase predictable Lets clients plan migration windows
Announce removals in release notes Keeps API consumers informed
Bundle hard removals with major version bumps Aligns with Semantic Versioning

10.3 Response Media Types & Fallbacks

Clients are not required to send vendor-specific Accept headers. Your server defines the media type in responses:

Header Example Description
Content-Type application/vnd.infocyph.jd.v1+json Defines the JsonDispatch version in use
X-Api-Version 1.3.2 Full semantic version of implementation

If a client requests plain JSON (Accept: application/json), return the default stable major version — but still include the correct headers for transparency.

Example

HTTP/1.1 200 OK
Content-Type: application/vnd.infocyph.jd.v1+json
X-Api-Version: 1.3.2
X-Request-Id: b3e9e7c4-9b7b-44c3-a8f3-8c39e612d882

10.4 Security Headers & CORS Policy Recommendations

Even the most elegant API format is useless if it leaks data or opens up attack surfaces. JsonDispatch defines how you format responses — but your platform must enforce how they’re delivered securely.

Below are recommended security headers, CORS patterns and exposure rules that align with JsonDispatch’s design.

10.4.1 Required Security Headers

Header Example Purpose
Content-Security-Policy default-src 'none'; frame-ancestors 'none'; Prevents browsers from embedding or executing API responses in iframes or cross-site contexts.
Strict-Transport-Security max-age=31536000; includeSubDomains; preload Enforces HTTPS and prevents downgrade attacks.
X-Content-Type-Options nosniff Blocks MIME-type sniffing, ensuring application/json stays JSON.
X-Frame-Options DENY Prevents clickjacking or UI redress attacks.
Referrer-Policy no-referrer Avoids leaking private API URLs in browser referrers.
Cache-Control no-store, no-cache, must-revalidate Prevents sensitive responses (e.g., tokens, user info) from being cached.
Permissions-Policy geolocation=(), microphone=(), camera=() Locks down API-origin capabilities when served via browsers.

Tip: You can centralize these headers at reverse proxy level (e.g., Nginx, Caddy or API Gateway) — they don’t need to live inside your application code.

10.4.2 CORS (Cross-Origin Resource Sharing)

If your API is accessed from browsers, define explicit and minimal CORS policies.

Recommended Example

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Request-Id, X-Correlation-Id, Authorization
Access-Control-Expose-Headers: X-Request-Id, X-Api-Version, X-Correlation-Id
Access-Control-Max-Age: 600

✅ Key points:

  • Always whitelist origins, never use * for authenticated APIs.
  • Expose X-Request-Id, X-Api-Version and X-Correlation-Id so browser-based clients can log and correlate them.
  • Cache preflight (OPTIONS) responses to reduce latency.

10.4.3 Authentication & Error Safety

  • Never echo back raw credentials, tokens or stack traces in error responses. Use safe code and message fields instead.

  • Return consistent HTTP status codes (401, 403) for unauthorized access — don’t over-share.

  • When using JWT or HMAC signatures, ensure timestamps and expirations are validated server-side.

  • Log X-Request-Id with auth context, but never include sensitive tokens in the same line — to prevent log correlation attacks.

10.4.4 Example Safe Error Response (Auth Context)

{
  "status": "fail",
  "message": "Authentication required",
  "data": [
    {
      "status": 401,
      "source": "auth-service",
      "title": "Invalid or missing token",
      "detail": "Please provide a valid Authorization header."
    }
  ]
}

This tells the user exactly what’s wrong — without exposing internals.

10.4.5 Summary: Security Sanity Checklist

✅ Task Why it matters
HTTPS enforced (Strict-Transport-Security) Prevents MITM attacks
No open Access-Control-Allow-Origin: * Blocks cross-site token leakage
nosniff and DENY headers applied Stops MIME confusion & framing
Only expose safe headers (X-*) Prevents internal header leakage
Minimal, consistent error structure Avoids sensitive info exposure

10.5 Use _properties and _references Generously

They’re not fluff — they make your responses self-describing.

  • _properties → guides clients about structure and pagination.
  • _references → eliminates enum lookups or duplicate API calls.

Example:

{
  "_references": {
    "status": {
      "A": "Active",
      "I": "Inactive"
    }
  },
  "_properties": {
    "data": {
      "type": "array",
      "name": "users",
      "count": 50,
      "page": 1
    }
  }
}

10.6 Operational Logging, Correlation, Monitoring & Security

JsonDispatch isn’t just a response format — it’s the foundation of your API observability contract. When used consistently, it becomes the single source of truth for debugging, monitoring, auditing and compliance.

10.6.1 Unified Structured Logging

Every service should emit structured logs with consistent keys — machine-parseable and human-readable.

Field Source Purpose
timestamp system When the event occurred
level system Severity (INFO, WARN, ERROR)
service config Service name (checkout-api, risk-worker)
route request HTTP method + path
status response HTTP status code
duration_ms response Request duration
x_request_id header Per-request trace ID
x_correlation_id header Workflow-level trace ID
user_id context Acting user or system ID
remote_ip request Client IP (sanitized if needed)

Example log line

[2025-10-06T10:22:51Z] INFO  service=checkout-api
  route=POST /checkout duration=284ms status=201
  request_id=019fb440-4e83-4b1b-bef9-44a80771f181
  correlation_id=order-2025-10-05-777 user_id=U9912

Tip: Always start each log entry with request_id for fast filtering in log pipelines.

10.6.2 Cross-Service Correlation Flow

Each inbound call generates a unique X-Request-Id, while X-Correlation-Id persists across the entire workflow.

Service X-Correlation-Id X-Request-Id Role
checkout-api order-2025-10-05-777 019f… Entry point
payment-api Propagated 020a… Downstream call
shipping-worker Propagated 021b… Background task
order-2025-10-05-777
├── [checkout-api] 019f…
├── [payment-api]  020a…
└── [shipping-job] 021b…

Search by correlation_id to see the entire transaction chain.

10.6.3 Integration with APM & Trace Systems

Attach JsonDispatch IDs to your tracing spans for full observability.

Example span attributes

{
  "trace_id": "00f067aa0ba902b7",
  "request_id": "019fb440-4e83-4b1b-bef9-44a80771f181",
  "correlation_id": "order-2025-10-05-777",
  "service.name": "checkout-api",
  "http.status_code": 201,
  "duration_ms": 284
}

Best Practice: Mirror these IDs in logs, traces and metrics — enabling one-click navigation from error to trace to log line.

10.6.4 Health & Readiness Endpoints

Expose /health and /ready endpoints using the JsonDispatch envelope. This ensures monitoring tools receive a consistent, parsable format.

Example

GET /health
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
X-Api-Version: 1.4.0
X-Request-Id: 44f0d7e2-c9b2-4a61-9b2a-1cf41b922021
{
  "status": "success",
  "message": "Service healthy",
  "data": {
    "uptime": "4d 06h 22m",
    "load": 0.21,
    "dependencies": {
      "database": "ok",
      "redis": "ok",
      "queue": "delayed(1)"
    }
  },
  "_properties": {
    "data": { "type": "object", "name": "health" }
  }
}

Return status:error with 503 if any dependency fails.

10.6.5 Metrics & Monitoring Snapshots

Expose lightweight /metrics or /stats endpoints for quantitative insights.

{
  "status": "success",
  "message": "Metrics snapshot",
  "data": {
    "requests_per_minute": 1240,
    "average_latency_ms": 182,
    "active_users": 341,
    "error_rate_percent": 0.6
  },
  "_properties": {
    "data": {
      "type": "object",
      "name": "metrics",
      "template": "https://spec.infocyph.com/jsondispatch/metrics.schema.json"
    }
  }
}

This allows Grafana, Prometheus exporters or custom dashboards to consume metrics in the same JSON format as all other responses.

10.6.6 Security & Audit Hooks

JsonDispatch headers and IDs also power audit trails and forensic analysis. Integrate them into your audit subsystem.

Audit Log Entry Example

{
  "timestamp": "2025-10-06T11:44:10Z",
  "action": "USER_DELETE",
  "actor_id": "admin-42",
  "target_id": "user-983",
  "result": "success",
  "request_id": "bafc98e0-33a1-41e9-90e4-0234cf19a311",
  "correlation_id": "session-2384",
  "ip": "203.0.113.12"
}

Security Best Practices

  • 🔒 Mask sensitive fields (PII, credentials, tokens) before logging.
  • 🧩 Validate _links URLs to prevent malicious injection.
  • 🧮 Use UUIDs or hashes instead of numeric IDs in responses.
  • 🕵️ Correlate admin actions via X-Request-Id in audit reports.
  • 🧱 Rotate and retain logs per compliance policy (GDPR, PCI-DSS, ISO 27001).
  • 📈 Trigger alerts when error rates exceed thresholds, grouped by service and correlation_id.

10.6.7 Operational Governance Checklist

Category Key Practice Why It Matters
Tracing Generate X-Request-Id for every response Root-cause visibility
Correlation Reuse X-Correlation-Id across related calls End-to-end transaction tracing
Logging Emit structured JSON logs Machine-readable monitoring
Security Mask sensitive info before logging Data protection & compliance
Monitoring Return JsonDispatch envelopes for /health & /metrics Uniform automation
Audit Store IDs with every admin or financial action Forensic traceability
Alerts Integrate with APM / log aggregator Real-time anomaly detection

Key Takeaway

JsonDispatch is not just a response contract — it’s the observability spine of your platform. When tracing, metrics, logs and audits all share the same IDs and envelope style, your API ecosystem becomes self-diagnosing, self-auditing and self-healing.

11. Appendix

The Appendix provides reference materials, reserved conventions and developer tools for teams implementing or integrating JsonDispatch.

It’s meant as a quick lookup section — not something you memorize, but something you check when building middleware, validation tools or test clients.

11.1 Reserved Headers (Response Only)

These headers are core to JsonDispatch and reserved for server responses. They should never be redefined for other purposes.

Header Direction Required Description
Content-Type Response Defines the JsonDispatch response format (e.g. application/vnd.infocyph.jd.v1+json)
X-Api-Version Response Full semantic version of the server’s JsonDispatch implementation
X-Request-Id Response Unique identifier generated by the server for this specific request/response
X-Correlation-Id Response Optional; groups multiple related requests under one workflow
traceparent / tracestate Response Optional; W3C Trace Context headers if distributed tracing is enabled

⚠️ Clients should not send X-Request-Id or X-Api-Version — these are server-assigned identifiers for traceability and audit purposes.

Example (Response Headers)

Content-Type: application/vnd.infocyph.jd.v1+json
X-Api-Version: 1.3.1
X-Request-Id: aabbccdd-1122-3344-5566-77889900aabb
X-Correlation-Id: order-2025-09-30-777

If you also use W3C Trace Context:

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
tracestate: infocyph=api-2025

11.2 Reserved Keywords (Top-Level JSON Keys)

JsonDispatch reserves certain top-level fields in the response body. Avoid reusing them for other meanings.

Reserved Key Purpose
status Overall outcome (success, fail, error)
message Human-readable message
data Primary content (object, array or list of errors)
code Business-level error code (only in error responses)
_references Lookup tables for IDs → labels
_properties Metadata describing structure or pagination
_links Navigational or relational links

If you need more top-level fields, group them under a meta object or use prefixed names (e.g. app_status).

11.3 Middleware & Utility Patterns

JsonDispatch is language-agnostic. Here’s what a typical implementation might include:

Middleware responsibilities

  • Attach Content-Type and X-Api-Version.
  • Generate X-Request-Id for each request.
  • Optionally include X-Correlation-Id if workflow-aware.
  • Enrich logs and tracing context automatically.

Response builders

  • Provide helper methods like:

    • JsonDispatch::success($data, $message)
    • JsonDispatch::fail($errors, $message)
    • JsonDispatch::error($code, $errors, $message)
  • Automatically append _links, _properties and _references if provided.

Logging integration

  • Every log entry should carry X-Request-Id.
  • Distributed logs can also use X-Correlation-Id for multi-service correlation.

11.4 Minimal JSON Schema for the Envelope (Dev Tooling)

A lightweight JSON Schema to validate response envelopes. This helps test suites and monitoring agents verify that your API always returns valid JsonDispatch shapes.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://spec.infocyph.com/jsondispatch/v1/envelope.schema.json",
  "title": "JsonDispatch v1 Envelope",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "status": {
      "type": "string",
      "enum": [
        "success",
        "fail",
        "error"
      ]
    },
    "message": {
      "type": "string"
    },
    "code": {
      "type": "string"
    },
    "data": {},
    "_references": {
      "type": "object"
    },
    "_properties": {
      "type": "object"
    },
    "_links": {
      "type": "object"
    }
  },
  "required": [
    "status"
  ]
}

This schema validates:

  • status must always exist.
  • Reserved fields must use correct types.
  • No unexpected top-level keys.

11.5 Example cURL Requests (Version & Headers)

Basic request (client → server):

curl -H 'Accept: application/json' \
  https://api.example.com/articles/42

Server response (JsonDispatch-compliant):

HTTP/1.1 200 OK
Content-Type: application/vnd.infocyph.jd.v1+json
X-Api-Version: 1.3.1
X-Request-Id: 60c1bbca-b1c8-49d0-b3ea-fe41d23290bd

Body:

{
  "status": "success",
  "message": "Article fetched successfully",
  "data": {
    "id": 42,
    "title": "JsonDispatch in Action"
  }
}

Request with correlation (for multi-step workflows):

curl -H 'Accept: application/json' \
  -H 'X-Correlation-Id: order-2025-10-05-xyz' \
  https://api.example.com/checkout

Server response:

HTTP/1.1 201 Created
Content-Type: application/vnd.infocyph.jd.v1+json
X-Api-Version: 1.3.1
X-Request-Id: 8d4e2a1b-c821-4b97-8430-44c7b9651d79
X-Correlation-Id: order-2025-10-05-xyz

Body:

{
  "status": "success",
  "message": "Checkout initiated successfully",
  "data": {
    "order_id": "ORD-2391A",
    "state": "processing"
  }
}

11.6 Developer Notes

  • The server is the only authority for JsonDispatch headers. Clients may provide X-Correlation-Id (optional), but never X-Request-Id.

  • Content-Type defines the envelope version (application/vnd.infocyph.jd.v1+json).

  • Always include X-Api-Version in responses — even for errors.

  • JsonDispatch responses remain valid JSON even for plain application/json clients.

About

A specification for building APIs in JSON based format for application-level communication.

Topics

Resources

Stars

Watchers

Forks