JSONPath QUERY Request Body Support

Categories: Change Log, API Testing, HTTP Methods

API Challenges now supports JSONPath expressions in QUERY request bodies.

This means our API QUERY endpoints advertise and accept:

Content-Type: application/jsonpath

The original QUERY support used form-encoded content:

Content-Type: application/x-www-form-urlencoded`

The payload would use normal form encoding like:

type=book

Form-encoded content still works. JSONPath adds another way to describe read-only selection criteria in the body of a QUERY request.

One of the key advantages for QUERY is the support for multiple content types supporting different query styles and filtering representations. And when the API is properly written, the API itself will use the accept-query header to tell the client what formats are supported:

accept-query: application/x-www-form-urlencoded, application/jsonpath

What is JSONPath?

JSONPath is a query syntax for JSON documents. It lets us select values from a JSON structure in a similar spirit to how XPath selects values from XML.

The standard is RFC 9535, published in February 2024. The RFC defines JSONPath as a syntax for selecting and extracting JSON values from a JSON value.

A JSONPath expression usually starts with $, which means the root of the JSON document.

For a response like this:

{
  "items": [
    {
      "id": 1,
      "type": "book",
      "price": 9.99,
      "numberinstock": 3,
      "isbn13": "123-4-56-789012-3"
    }
  ]
}

The expression:

$.items[?(@.type == 'book')]

selects every item where the type field is book.

Why Use JSONPath?

JSONPath is useful when the query is more structured than a simple field/value filter.

A URL query string works well for simple examples:

/simpleapi/items?type=book

But a request body can be easier to read when the query has multiple conditions or when you want a syntax that already describes JSON data.

For example:

$.items[?(@.type == 'book' && @.numberinstock > 0)]

That expression reads as "from the items collection, return books where the number in stock is greater than zero."

Examples Using Simple API

The Simple API has an /simpleapi/items collection with fields such as type, price, numberinstock, and isbn13.

To return only books:

QUERY /simpleapi/items HTTP/1.1
Content-Type: application/jsonpath
Accept: application/json

$.items[?(@.type == 'book')]

To return CDs:

$.items[?(@.type == 'cd')]

To return out-of-stock items:

$.items[?(@.numberinstock == 0)]

To return books that have stock:

$.items[?(@.type == 'book' && @.numberinstock > 0)]

To return all items:

$.items

For API Challenges todos, the equivalent completed-todo query is:

QUERY /todos HTTP/1.1
Content-Type: application/jsonpath
Accept: application/json

$.todos[?(@.doneStatus == true)]

Why Use JSONPath With QUERY?

QUERY is intended for safe read requests where the query content belongs in the request body rather than the URL.

JSONPath pairs well with QUERY because:

  • the HTTP method still communicates "this is a read";
  • the URL can stay focused on the collection resource;
  • the request body can contain a structured query expression;
  • the Content-Type header documents the query language;
  • clients can discover support through the Accept-Query response header.

This gives testers another useful behavior to explore. Does your REST client support custom methods? Does it allow a request body with QUERY? Does it preserve Content-Type: application/jsonpath? Does generated OpenAPI documentation show the content type clearly?

Try the New Challenge

There is now an API Challenge for JSONPath query bodies:

And the reference material has been expanded:

Try the Simple API examples first, then use the challenge to prove that your request is doing what you think it is doing.