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/vnd.infocyph.jd.v1+json
  X-Api-Version: 1.4.0

Server → Client
~~~~~~~~~~~~~~~

**Response**

.. code-block:: http

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

.. tip::

   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
  X-Api-Version: 1.4.0
  Accept: application/vnd.infocyph.jd.v1+json
  Content-Type: application/json; charset=utf-8
  X-Correlation-Id: order-2025-10-05-777

  { "cartId": "C10045" }

Server → Client
~~~~~~~~~~~~~~~

**Response**

.. code-block:: http

   HTTP/1.1 201 Created
   Content-Type: application/json; charset=utf-8
   X-Api-Version-Selected: 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 <https://www.w3.org/TR/trace-context/>`_.

These headers complement (not replace) JsonDispatch identifiers:

- **``traceparent``** — carries trace ID and span ID.
- **``tracestate``** — vendor-specific trace metadata.

**Example**

**Request**

.. code-block:: http

   GET /profile
   Accept: application/vnd.infocyph.jd.v1+json
   X-Api-Version: 1.4.0
   traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
   tracestate: congo=t61rcWkgMzE

Response
~~~~~~~~

**Response**

.. code-block:: http

   HTTP/1.1 200 OK
   Content-Type: application/json; charset=utf-8
   X-Api-Version-Selected: 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**

.. list-table::
   :header-rows: 1
   :widths: 18 12 50 10

   * - 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``
     - Request →
     - Requested JsonDispatch API version
     - ✅ Yes
   * - ``X-Api-Version-Selected``
     - Response →
     - Server JsonDispatch version identifier
     - ✅ Yes
   * - ``traceparent``
     - Both ↔
     - Distributed tracing (W3C)
     - ⚪ Optional
   * - ``tracestate``
     - Both ↔
     - Vendor-specific tracing metadata
     - ⚪ Optional


3.4 Rate limiting
-----------------

To protect API resources and ensure fair usage, JsonDispatch recommends standard rate limiting headers that inform
clients about their current usage and limits.

3.4.1 Rate limit headers
^^^^^^^^^^^^^^^^^^^^^^^^

Include these headers in **all successful responses** (and optionally in error responses).

**Standard approach (X-prefixed headers)**

.. list-table::
   :header-rows: 1
   :widths: 28 44 28

   * - Header
     - Description
     - Example
   * - ``X-RateLimit-Limit``
     - Maximum requests allowed in the current window
     - ``1000``
   * - ``X-RateLimit-Remaining``
     - Requests remaining in the current window
     - ``987``
   * - ``X-RateLimit-Reset``
     - Unix timestamp when the rate limit resets
     - ``1698249600``
   * - ``X-RateLimit-Window`` (optional)
     - Duration of the rate limit window
     - ``3600`` (1h)

**Example response with rate limit headers**

**Response**

.. code-block:: http

   HTTP/1.1 200 OK
   Content-Type: application/json; charset=utf-8
   X-Api-Version-Selected: 1.4.0
   X-Request-Id: 9b7f3c2a-4e1d-4f8c-a3b2-1e5d6c8f9a0b
   X-RateLimit-Limit: 1000
   X-RateLimit-Remaining: 987
   X-RateLimit-Reset: 1698249600

**IETF Draft Standard (optional alternative)**

JsonDispatch also supports the `IETF RateLimit Header Fields draft
<https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers>`_ which uses non-prefixed headers:

.. list-table::
   :header-rows: 1
   :widths: 28 44 28

   * - Header
     - Description
     - Example
   * - ``RateLimit-Limit``
     - Maximum requests allowed in the current window
     - ``1000``
   * - ``RateLimit-Remaining``
     - Requests remaining in the current window
     - ``987``
   * - ``RateLimit-Reset``
     - Seconds until the rate limit resets
     - ``3600``
   * - ``RateLimit-Policy``
     - Rate limit policy definition
     - ``1000;w=3600``

**Example response with IETF Draft headers**

**Response**

.. code-block:: http

   HTTP/1.1 200 OK
   Content-Type: application/json; charset=utf-8
   X-Api-Version-Selected: 1.4.0
   X-Request-Id: 9b7f3c2a-4e1d-4f8c-a3b2-1e5d6c8f9a0b
   RateLimit-Limit: 1000
   RateLimit-Remaining: 987
   RateLimit-Reset: 3600
   RateLimit-Policy: 1000;w=3600

.. note::

   The main difference is that ``RateLimit-Reset`` uses seconds (delta) while ``X-RateLimit-Reset`` uses a Unix timestamp.
   Choose one approach consistently across your API.

**Policy format**

- ``1000;w=3600`` = 1000 requests per 3600 seconds (1 hour)
- ``100;w=60`` = 100 requests per 60 seconds (1 minute)
- ``10000;w=86400`` = 10000 requests per 86400 seconds (24 hours)

**Combined approach (maximum compatibility)**

For maximum compatibility, you may send both header styles:

**Response**

.. code-block:: http

   HTTP/1.1 200 OK
   Content-Type: application/json; charset=utf-8
   X-Api-Version-Selected: 1.4.0
   X-Request-Id: 9b7f3c2a-4e1d-4f8c-a3b2-1e5d6c8f9a0b
   X-RateLimit-Limit: 1000
   X-RateLimit-Remaining: 987
   X-RateLimit-Reset: 1698249600
   RateLimit-Limit: 1000
   RateLimit-Remaining: 987
   RateLimit-Reset: 3600
   RateLimit-Policy: 1000;w=3600

.. tip::

   If you’re building a new API, prefer the IETF Draft headers as they are likely to become a standard.
   For existing APIs, continue with X-prefixed headers for backward compatibility.


3.4.2 Rate limit exceeded response
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

When a client exceeds their rate limit, return **``429 Too Many Requests``** with a ``fail`` status:

**Response**

.. code-block:: http

   HTTP/1.1 429 Too Many Requests
   Content-Type: application/json; charset=utf-8
   X-Api-Version-Selected: 1.4.0
   X-Request-Id: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
   X-RateLimit-Limit: 1000
   X-RateLimit-Remaining: 0
   X-RateLimit-Reset: 1698249600
   Retry-After: 3600

.. code-block:: json

   {
     "status": "fail",
     "message": "Rate limit exceeded",
     "data": {
       "errors": [
         {
           "code": "RATE_LIMIT_EXCEEDED",
           "message": "You have exceeded the rate limit of 1000 requests per hour"
         }
       ]
     },
     "_properties": {
       "rate_limit": {
         "limit": 1000,
         "remaining": 0,
         "reset_at": "2025-10-22T16:00:00Z",
         "retry_after_seconds": 3600
       }
     },
     "_links": {
       "upgrade": "https://example.com/pricing",
       "docs": "https://docs.example.com/rate-limits"
     }
   }

.. note::

   Include the ``Retry-After`` header (in seconds) to tell clients when they can retry.


3.4.3 Rate limiting strategies
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

JsonDispatch supports various rate limiting strategies:

**Per-user rate limiting**

Rate limits tied to authenticated user accounts::

  X-RateLimit-Limit: 5000
  X-RateLimit-Remaining: 4872
  X-RateLimit-Reset: 1698253200

**Per-API-key rate limiting**

Different limits for different API keys or service tiers::

  X-RateLimit-Limit: 100000
  X-RateLimit-Remaining: 99234
  X-RateLimit-Reset: 1698253200

**Per-endpoint rate limiting**

Some endpoints may have stricter limits than others. Use ``_properties`` to communicate this:

.. code-block:: json

   {
     "status": "success",
     "data": { "...": "..." },
     "_properties": {
       "rate_limit": {
         "endpoint_limit": 100,
         "endpoint_remaining": 87,
         "endpoint_window": "60s"
       }
     }
   }

.. tip::

   Always log rate limit violations with ``X-Request-Id`` to identify abusive patterns and help legitimate users understand their usage.
