skip to content

In a validation error response, how do you identify the offending value when it sits deep inside the payload - say the quantity of the fourth element of an items array? What does an RFC 6901 JSON Pointer give you, and where does it fall short?

level: seniorimportance: should knowfreq 38%

answer

  1. /items/3/quantity - slash tokens, zero-based indexes
  2. empty string = whole document
  3. ~1 = /, ~0 = ~, decode ~1 first
  4. body only - no query, headers or path
  5. must resolve against the wire names the client sent

basics

~20 s

Use a JSON Pointer into the request document: /items/3/quantity. It is a slash-separated path of member names and zero-based array indexes, empty string for the whole document, with ~1 escaping a literal slash and ~0 a literal tilde. It cannot address query parameters or headers.

solid answer

~50 s

I emit an RFC 6901 JSON Pointer that resolves against the exact request body the client sent: /items/3/quantity. Pointers are unambiguous, machine-evaluable by an off-the-shelf library, and handle arrays and nesting without inventing a syntax. The empty string points at the document root, which is where whole-body rules land. The rules people forget: it must start with a slash unless it is empty, array indexes are numeric and zero-based, and inside a token ~ is escaped as ~0 and / as ~1 - and when unescaping you must replace ~1 before ~0. The shortfalls: it only addresses the body, so query, path and header problems need a name-plus-location form instead; it must use the wire property names, not internal field names, which matters when a serializer renames things; and after any server-side normalisation the indexes must still match what the client sent.

code

json · 8 lines
json
{
  "errors": [
    { "location": "body", "target": "/items/3/quantity", "code": "range.min" },
    { "location": "body", "target": "", "code": "rule.date-order" },
    { "location": "body", "target": "/meta/a~1b", "code": "required" },
    { "location": "query", "name": "page", "code": "type.integer" }
  ]
}

go deeper

for a junior

Know the shape /items/3/quantity and that indexes are zero-based; escaping details are not expected.

for a middle

Add the empty-pointer root case, the ~0/~1 escapes, and why a pointer beats a dotted path.

for a senior

Discuss wire-name translation, index drift after normalisation, the body-only limitation, and a test that evaluates every emitted pointer against the request.

for a principal

Standardise the target and location fields across services so one client library binds validation errors for the whole platform, and require pointer-resolves tests in the contract suite.

## What a JSON Pointer is RFC 6901 defines a tiny syntax for addressing one value inside a JSON document. A pointer is a sequence of reference tokens, each preceded by /. Evaluation starts at the whole document and applies tokens left to right: on an object the token is a member name, on an array it is a zero-based index (or - for the position past the end, which is a JSON Patch concept and not useful in errors). - "" - the entire document - "/email" - the email member of the root object - "/items/3/quantity" - the quantity member of the fourth element of items - "/a~1b" - the member literally named a/b - "/m~0n" - the member literally named m~n Escaping is the classic trap: ~ becomes ~0 and / becomes ~1, and when decoding you must replace ~1 before ~0 or the sequence ~01 decodes wrongly. ## Why it beats a hand-rolled path Dotted paths (items[3].quantity) look friendlier and break as soon as a property name contains a dot or a bracket - which JSON permits. Pointers have exactly one escaping rule, a published spec, and libraries in every language, so a client can evaluate the pointer against the body it just sent and physically retrieve the bad value. That is what lets a generic form binder highlight the right control without endpoint-specific code. ## The wire-name obligation The pointer must resolve against the JSON the client sent. If your server maps camelCase JSON onto snake_case entities, aliases properties, or unwraps a wrapper object, the target has to be translated back to the client's representation. Emitting an internal field name is a common and infuriating bug: the client receives a pointer that resolves to nothing. The same applies to indexes. If the server sorts, filters, or de-duplicates the incoming array before validating, index 3 in your working copy may be index 7 in the request. Validate against the original ordering, or carry the original index alongside. ## Where pointers cannot go A JSON Pointer addresses a JSON document. It cannot address a query parameter, a path segment, a header, a multipart part name, or a form field, and there is no legal encoding that makes /query/page meaningful - it would resolve to a member named query in the body. For those, use a different discriminator: a location field (body, query, path, header, cookie) plus a name. Many APIs carry both fields and populate whichever applies. If the payload is not JSON at all - form-encoded or XML - pointers do not apply and a name or XPath-style expression is the alternative. ## Pointer, and then what A pointer identifies the target; it says nothing about the rule. Pair it with the stable code and the human message, and keep the pointer key name consistent across the whole API so a client's binder works everywhere. If a violation genuinely has no single target - a cross-field rule - point at the smallest containing object rather than picking one of the two fields arbitrarily, or use the empty pointer for a document-level rule. ## Testing it The cheap regression test is mechanical: for every violation your API can emit, evaluate the pointer against the request body in the test and assert it resolves. That catches renamed properties, missing leading slashes, unescaped characters, and index drift in one assertion.

  • How do you report a violation of a rule spanning two fields, like endDate must be after startDate?
    Point at the smallest object that contains both fields - the empty pointer if they sit at the root - and use a code that names the rule rather than a field constraint. Arbitrarily blaming one of the two fields misleads the client, though some APIs additionally attach the same violation to both fields so a form can highlight them; if you do that, keep it a documented convention.

saying these in an interview costs you the question

  • Emitting internal Java or database field names in the pointer instead of the JSON property names
  • Forgetting the leading slash, or using items[3].quantity and calling it a JSON Pointer
  • Ignoring ~0/~1 escaping for property names containing tilde or slash
  • Trying to address a query parameter or header with a JSON Pointer

context