1. Overview
In this tutorial, we’ll learn how to work with JSON objects as query parameters using OpenAPI.
2. Query Parameters in OpenAPI 2
OpenAPI 2 doesn’t support objects as query parameters; only primitive values and arrays of primitives are supported.
Because of that, we’ll instead want to define our JSON parameter as a string.
To see this in action, let’s define a parameter called params as a string, even though we’ll parse it as JSON in our backend:
swagger: "2.0"
...
paths:
/tickets:
get:
tags:
- "tickets"
summary: "Send an JSON Object as a query param"
parameters:
- name: "params"
in: "path"
description: "{\"type\":\"foo\",\"color\":\"green\"}"
required: true
type: "string"
Thus, instead of:
GET http://localhost:8080/api/tickets?type=foo&color=green
we’ll do:
GET http://localhost:8080/api/tickets?params={"type":"foo","color":"green"}
3. Query Params in OpenAPI 3
OpenAPI 3 introduces support for objects as query parameters.
To specify a JSON parameter, we need to add a content section to our definition that includes the MIME type and schema:
openapi: 3.0.1
...
paths:
/tickets:
get:
tags:
- tickets
summary: Send an JSON Object as a query param
parameters:
- name: params
in: query
description: '{"type":"foo","color":"green"}'
required: true
schema:
type: object
properties:
type:
type: "string"
color:
type: "string"
Our request can now look like:
GET http://localhost:8080/api/tickets?params[type]=foo¶ms[color]=green
And, actually, it can still look like:
GET http://localhost:8080/api/tickets?params={"type":"foo","color":"green"}
The first option allows us to use parameter validations, which will let us know if something is wrong before the request is made.
With the second option, we trade that for greater control on the backend as well as OpenAPI 2 compatibility.
4. URL Encoding
It’s important to note that, in making this decision to transport request parameters as a JSON object, we’ll want to URL-encode the parameter to ensure safe transport.
So, to send the following URL:
GET /tickets?params={"type":"foo","color":"green"}
We’d actually do:
GET /tickets?params=%7B%22type%22%3A%22foo%22%2C%22color%22%3A%22green%22%7D
5. Limitations
Also, let’s keep in mind the limitations of passing a JSON object as a set of query parameters:
- reduced security
- limited length of the parameters
For example, the more data we place in a query parameter, the more appears in server logs and the higher the potential for sensitive data exposure.
Also, a single query parameter can be no longer than 2048 characters. Certainly, we can all imagine scenarios where our JSON objects are larger than that. Practically speaking, a URL encoding of our JSON string will actually limit us to about 1000 characters for our payload.
One workaround is to send larger JSON Objects in the body. In this way, we fix both the security issue and the JSON length limitation.
Actually, GET or POST both support this. One reason to send a body over GET is to maintain the RESTful semantics of our API.
Of course, it’s a bit unusual and not universally supported. For instance, some JavaScript HTTP libraries don’t allow GET requests to have a request body.
In short, this choice is a trade-off between semantics and universal compatibility.
6. Conclusion
To sum up, in this article we learned how to specify JSON objects as query parameters using OpenAPI. Then, we observed some of the implications on the backend.
The complete OpenAPI definitions for these examples are available over on GitHub.