Search code examples
jsonpathjson-path-expression

How to retrieve responses that are an array in JSON Path


I have the following API specification in JSON format. I want to retrieve, using JSON path, those responses (200, 401, etc.) that return directly an array as a response. That is, [{}, {}, ...] instead of {result: [{}, {}, ...]}.

What I have been trying is:

  • $.paths.[*].[*].responses.[*].content.[?(@.type === 'array')]

But the main problem is that I get two results, nonetheless, it should return onle one (there's only one response being an array). It's a returning a more nested object inside the schema, that is also an array.

So my question is, how can I build a json path filter to fit my use case? I have tried more combinations but I cannot make it work.

Current output

If you go to a json path resolver and input my current expression, you will get these two results:

[
  {
    "type": "array",
    "items": {
      "type": "object",
      "properties": {
        "place_id": {
          "type": "string",
          "example": "ChIJ37HL3ry3t4kRv3YLbdhpWXE"
        },
        "name": {
          "type": "string",
          "example": "The White House"
        },
        "type": {
          "type": "string",
          "example": "tourist_attraction"
        },
        "formatted_address": {
          "type": "string",
          "example": "1600 Pennsylvania Avenue NW, Washington, DC 20500, United States"
        },
        "location": {
          "type": "object",
          "properties": {
            "latitude": {
              "type": "number",
              "format": "float",
              "example": 38.8976763,
              "minimum": -90,
              "maximum": 90
            },
            "longitude": {
              "type": "number",
              "format": "float",
              "minimum": -180,
              "maximum": 180,
              "example": -77.0365298
            }
          }
        }
      }
    }
  },
  {
    "type": "array",
    "minItems": 7,
    "maxItems": 7,
    "items": {
      "type": "object",
      "properties": {
        "week_day": {
          "type": "number",
          "format": "int",
          "minimum": 1,
          "maximum": 7,
          "example": 1
        },
        "zone_id": {
          "type": "string",
          "example": "Africa/Abidjan"
        },
        "start": {
          "type": "string",
          "pattern": "^\\d{4}$",
          "example": "0100"
        },
        "end": {
          "type": "string",
          "pattern": "^\\d{4}$",
          "example": "1630"
        }
      }
    }
  }
]

If you take a look, the first result is the only one I want, because is the schema of a response. The second one is just a nested structure in another part of the json, that also has a type property set to array.

Expected output

So, the only valid result should be:

[
  {
    "type": "array",
    "items": {
      "type": "object",
      "properties": {
        "place_id": {
          "type": "string",
          "example": "ChIJ37HL3ry3t4kRv3YLbdhpWXE"
        },
        "name": {
          "type": "string",
          "example": "The White House"
        },
        "type": {
          "type": "string",
          "example": "tourist_attraction"
        },
        "formatted_address": {
          "type": "string",
          "example": "1600 Pennsylvania Avenue NW, Washington, DC 20500, United States"
        },
        "location": {
          "type": "object",
          "properties": {
            "latitude": {
              "type": "number",
              "format": "float",
              "example": 38.8976763,
              "minimum": -90,
              "maximum": 90
            },
            "longitude": {
              "type": "number",
              "format": "float",
              "minimum": -180,
              "maximum": 180,
              "example": -77.0365298
            }
          }
        }
      }
    }
  }
]

Additional information

Not relevant to the question I think, but this is to create a custom rule in spectral for valdiating my API specs.


Solution

  • I'm not sure what the implementation you're using is doing, but having a . before your bracketed segments is invalid and should be rejected.

    Using this path

    $.paths.*.*.responses.*.content.*[?(@.type == 'array')]
    

    gets you what you're after.

    (I also replaced the === with == because === isn't defined in JSON Path.)


    $.foo[*] is equivalent to $.foo.* and returns every child under a foo property. $.foo.[*] (note the second .) should be invalid.

    Similarly, $.foo.[?(@.bar == 'value')] is invalid. You need to drop that second . to get $.foo[?(@.bar == 'value')].