= JSON Request API
:solr-root-path: ../../
:example-source-dir: {solr-root-path}solrj/src/test/org/apache/solr/client/ref_guide_examples/
:page-children: json-query-dsl
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

Solr supports an alternate request API which accepts requests composed in part or entirely of JSON objects.
This alternate API can be preferable in some situations, where its increased readability and flexibility make it easier to use than the entirely query-parameter driven alternative.
There is also some functionality which can only be accessed through this JSON request API, such as much of the analytics capabilities of <<json-facet-api.adoc#facet-analytics-module,JSON Faceting>>

== Building JSON Requests
The core of the JSON Request API is its ability to specify request parameters as JSON in the request body, as shown by the example below:
[.dynamic-tabs]
--
[example.tab-pane#curl-simple-json-query]
====
[.tab-label]*curl*
[source,bash]
----
curl http://localhost:8983/solr/techproducts/query -d '
{
  "query" : "memory",
  "filter" : "inStock:true"
}'
----
====
[example.tab-pane#solrj-simple-json-query]
====
[.tab-label]*SolrJ*
[source,java,indent=0]
----
include::{example-source-dir}JsonRequestApiTest.java[tag=solrj-json-query-simple]
----
====
--

JSON objects are typically sent in the request body, but they can also be sent as values for `json`-prefixed query parameters.  This can be used to override or supplement values specified in the request body.  For example the query parameter `json.limit=5` will override any `limit` value provided in the JSON request body.  You can also specify the entire JSON body in a single `json` query parameter, as shown in the example below:
[source,bash]
curl http://localhost:8983/solr/techproducts/query -d 'json={"query":"memory"}'

=== JSON Parameter Merging
If multiple `json` parameters are provided in a single request, Solr attempts to merge the parameter values together before processing the request.

The JSON Request API has several properties (`filter`, `fields`, etc) which accept multiple values.  During the merging process, all values for these "multivalued" properties are retained.  Many properties though (`query`, `limit`, etc.) can have only a single value.  When multiple parameter values conflict with one another a single value is chosen based on the following precedence rules:

* Traditional query parameters (`q`, `rows`, etc.) take first precedence and are used over any other specified values.
* `json`-prefixed query parameters are considered next.
* Values specified in the JSON request body have the lowest precedence and are only used if specified nowhere else.

This layered merging gives the best of both worlds.  Requests can be specified using readable, structured JSON.  But users also have the flexibility to separate out parts of the request that change often.  This can be seen at work in the following example, which combines `json.`-style parameters to override and supplement values found in the main JSON body.

[.dynamic-tabs]
--
[example.tab-pane#curl-json-query-param-overrides]
====
[.tab-label]*curl*
[source,bash]
----
curl 'http://localhost:8983/solr/techproducts/query?json.limit=5&json.filter="cat:electronics"' -d '
{
  query: "memory",
  limit: 10,
  filter: "inStock:true"
}'
----
====
[example.tab-pane#solrj-json-query-param-overrides]
====
[.tab-label]*SolrJ*
[source,java,indent=0]
----
include::{example-source-dir}JsonRequestApiTest.java[tag=solrj-json-query-param-overrides]
----
====
--

This is equivalent to:

[.dynamic-tabs]
--
[example.tab-pane#curl-json-query-param-overrides-equivalent]
====
[.tab-label]*curl*
[source,bash]
----
curl http://localhost:8983/solr/techproducts/query -d '
{
  "query": "memory",
  "limit": 5,     // this single-valued parameter was overwritten.
  "filter": ["inStock:true","cat:electronics"]    // this multi-valued parameter was appended to.
}'
----
====
[example.tab-pane#solrj-json-query-param-overrides-equivalent]
====
[.tab-label]*SolrJ*
[source,java,indent=0]
----
include::{example-source-dir}JsonRequestApiTest.java[tag=solrj-json-query-param-overrides-equivalent]
----
====
--


Similarly, smart merging can be used to create JSON API requests which have no proper request body at all, such as the example below:
[.dynamic-tabs]
--
[example.tab-pane#curl-json-facet-all-query-params]
====
[.tab-label]*curl*
[source,bash]
----
curl http://localhost:8983/solr/techproducts/query -d 'q=*:*&rows=1&
  json.facet.avg_price="avg(price)"&
  json.facet.top_cats={type:terms,field:"cat",limit:3}'
----
====
[example.tab-pane#solrj-json-facet-all-query-params]
====
[.tab-label]*SolrJ*
[source,java,indent=0]
----
include::{example-source-dir}JsonRequestApiTest.java[tag=solrj-json-facet-all-query-params]
----
====
--

That is equivalent to the following request:
[.dynamic-tabs]
--
[example.tab-pane#curl-json-facet-all-query-params-equivalent]
====
[.tab-label]*curl*
[source,bash]
----
curl http://localhost:8983/solr/techproducts/query -d '
{
  "query": "*:*",
  "limit": 1,
  "facet": {
    "avg_price": "avg(price)",
    "top_cats": {
      "type": "terms",
      "field": "cat",
      "limit": 5
    }
  }
}
'
----
====
[example.tab-pane#solrj-json-facet-all-query-params-equivalent]
====
[.tab-label]*SolrJ*
[source,java,indent=0]
----
include::{example-source-dir}JsonRequestApiTest.java[tag=solrj-json-facet-all-query-params-equivalent]
----
====
--

See the <<json-facet-api.adoc#facet-analytics-module,JSON Facet API>> for more on faceting and analytics commands.

== Supported Properties and Syntax

Right now, only some of Solr's traditional query parameters have first class JSON equivalents.  Those that do are shown in the table below:

.Standard query parameters to JSON field
|===
|Query parameters |JSON field equivalent

|`q`
|`query`

|`fq`
|`filter`

|`start`
|`offset`

|`rows`
|`limit`

|`fl`
|`fields`

|`sort`
|`sort`

|`json.facet`
|`facet`

|`json.<param_name>`
|`<param_name>`

|`json.queries.<query_name>`
|`queries`
|===

Parameters not specified in the table above can still be used in the main body of JSON API requests, but they must be put within a `params` block as shown in the example below.

[.dynamic-tabs]
--
[example.tab-pane#curl-json-query-params-block]
====
[.tab-label]*curl*
[source,bash]
----
curl "http://localhost:8983/solr/techproducts/query?fl=name,price"-d '
{
  params: {
    q: "memory",
    rows: 1
  }
}'
----
====

[example.tab-pane#solrj-json-query-params-block]
====
[.tab-label]*SolrJ*

[source,java,indent=0]
----
include::{example-source-dir}JsonRequestApiTest.java[tag=solrj-json-query-params-block]
----
====
--

Parameters placed in a `params` block act as if they were added verbatim to the query-parameters of the request.  The request above is equivalent to:

[source,bash]
----
curl "http://localhost:8983/solr/techproducts/query?fl=name,price&q=memory&rows=1"
----

Usage of `queries` key is described in <<json-query-dsl.adoc#additional-queries,Query DSL>>.


=== Parameter Substitution / Macro Expansion
Of course request templating via parameter substitution works fully with JSON request bodies or parameters as well.
For example:

[.dynamic-tabs]
--
[example.tab-pane#curl-json-query-macro-expansion]
====
[.tab-label]*curl*
[source,bash]
----
curl "http://localhost:8983/solr/techproducts/query?FIELD=text&TERM=memory" -d '
{
  query:"${FIELD}:${TERM}",
}'
----
====

[example.tab-pane#solrj-json-query-macro-expansion]
====
[.tab-label]*SolrJ*

[source,java,indent=0]
----
include::{example-source-dir}JsonRequestApiTest.java[tag=solrj-json-query-macro-expansion]
----
====
--

=== JSON Extensions

Solr uses the *Noggit* JSON parser in its request API.  Noggit is capable of more relaxed JSON parsing, and allows a number of deviations from the JSON standard:

* bare words can be left unquoted
* single line comments can be inserted using either `//` or `#`
* Multi-line ("C style") comments can be inserted using `/\*` and `*/`
* strings can be single-quoted
* special characters can be backslash-escaped
* trailing (extra) commas are silently ignored (e.g., `[9,4,3,]`)
* nbsp (non-break space, \u00a0) is treated as whitespace.

== Debugging

If you want to see what your merged/parsed JSON looks like, you can turn on debugging (`debug=timing`), and it will come back under the "json" key along with the other debugging information.
Note that `debug=true` and `debugQuery=true` can often have significant performance implications, and should be reserved for debugging.  Also note that `debug=query` has no effect on JSON facets in SolrCloud.
