> ## Documentation Index
> Fetch the complete documentation index at: https://doc.lucidworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# REST Query

> Index pipeline stage configuration specifications

export const schema = {
  "type": "object",
  "title": "REST Query",
  "description": "Add results of an REST (RPC) call to the document.",
  "required": ["params"],
  "properties": {
    "skip": {
      "type": "boolean",
      "title": "Skip This Stage",
      "description": "Set to true to skip this stage.",
      "default": false,
      "hints": ["advanced"]
    },
    "label": {
      "type": "string",
      "title": "Label",
      "description": "A unique label for this stage.",
      "hints": ["advanced"],
      "maxLength": 255
    },
    "condition": {
      "type": "string",
      "title": "Condition",
      "description": "Define a conditional script that must result in true or false. This can be used to determine if the stage should process or not.",
      "hints": ["code", "code/javascript", "advanced"]
    },
    "params": {
      "type": "object",
      "title": "Call Parameters",
      "required": ["uri", "method"],
      "properties": {
        "uri": {
          "type": "string",
          "title": "Endpoint URI"
        },
        "method": {
          "type": "string",
          "title": "Call method",
          "description": "One of GET, POST, PUT, or DELETE",
          "enum": ["get", "put", "post", "delete"]
        },
        "queryParams": {
          "type": "object",
          "title": "Query parameters",
          "properties": {},
          "additionalProperties": {
            "type": "string"
          }
        },
        "headers": {
          "type": "object",
          "title": "Request protocol headers",
          "properties": {},
          "additionalProperties": {
            "type": "string"
          }
        },
        "entity": {
          "type": "string",
          "title": "Request entity (as string)",
          "hints": ["code", "lengthy"]
        }
      }
    },
    "debug": {
      "type": "boolean",
      "title": "Add Debugging Information",
      "description": "Setting to true will add a number of properties to either the context (in the Query case) or the document (in the indexing case)",
      "default": false
    },
    "hasNoSideEffects": {
      "type": "boolean",
      "title": "Run in simulation mode",
      "description": "To run this stage in simulation mode, set to 'true'.",
      "default": false
    },
    "mappingRules": {
      "type": "array",
      "title": "Mapping of Returned Values (as XPath Expressions) to Document Fields",
      "items": {
        "type": "object",
        "required": ["path", "target"],
        "properties": {
          "path": {
            "type": "string",
            "title": "XPath expression"
          },
          "target": {
            "type": "string",
            "title": "Target field"
          },
          "append": {
            "type": "boolean",
            "title": "Append to Existing Values in Target Field",
            "default": false
          },
          "xml": {
            "type": "boolean",
            "title": "Add as an XML Fragment",
            "default": false
          }
        }
      }
    }
  },
  "category": "Document Filtering and Enrichment",
  "categoryPriority": 8,
  "unsafe": true
};

export const SchemaParamFields = ({schema}) => {
  const sanitize = str => {
    if (typeof str !== "string") return str;
    return str.replace(/^"(.*)"$/s, "$1").replace(/\\/g, "").replace(/"/g, "'");
  };
  const formatDescription = str => {
    const s = sanitize(str);
    return (/[.!?]\)*$/).test(s) ? s : `${s}.`;
  };
  const {description, properties = {}, required: requiredProps = []} = schema;
  const visibleProps = useMemo(() => Object.entries(properties).filter(([, prop]) => !prop.hints?.includes("hidden")), [properties]);
  return <div>
      {description && <p>{formatDescription(description)}</p>}

      {visibleProps.map(([name, prop]) => {
    const isRequired = requiredProps.includes(name);
    const hasDefault = prop.default !== undefined;
    const rawDefault = prop.default;
    const isComplexDefault = hasDefault && (typeof rawDefault === "object" || typeof rawDefault === "string" && (rawDefault.length > 20 || rawDefault.includes('"')));
    const fieldProps = {
      key: name,
      body: prop.title || name,
      type: prop.type,
      ...prop.title && ({
        post: [<><span className="text-stone-400 dark:text-stone-500">API property: </span>{name}</>]
      }),
      ...isRequired && ({
        required: true
      }),
      ...!isComplexDefault && hasDefault ? {
        default: sanitize(String(rawDefault))
      } : {}
    };
    const isObject = prop.type === "object" && prop.properties;
    const isArrayOfObjects = prop.type === "array" && prop.items?.type === "object" && prop.items.properties;
    return <ParamField {...fieldProps}>
            {prop.description && <p>{formatDescription(prop.description)}</p>}

            {isComplexDefault && <div className="flex">
                <p>
                  <strong>Default:</strong>
                </p>
                <pre className="!my-0">
                  <code>
                    {JSON.stringify(rawDefault, null, 2)}
                  </code>
                </pre>
              </div>}

            {isArrayOfObjects && <div className="flex">
              <p>
                <strong>Object attributes:</strong>
              </p>
              <pre className="!my-0">
                <code>
                  {'{\n'}
                  {Object.entries(prop.items.properties).map(([iname, iprop]) => <>
                      {`  ${iname}`}
                      {prop.items?.required?.includes(iname) && <span style={{
      color: 'red'
    }}> required</span>}
                      {`: {\n    display name: ${sanitize(iprop.title || '')}\n    type: ${iprop.type}\n  }\n`}
                    </>)}
                  {'}'}
                </code>
              </pre>
              </div>}

            {isObject && <Expandable title="properties">
                <SchemaParamFields schema={{
      properties: prop.properties,
      required: prop.required
    }} />
              </Expandable>}
          </ParamField>;
  })}
    </div>;
};

export const LwTemplate = ({title = "Key questions to get you started", icon = "sparkles", cta = "Powered by Agent Studio", linkHref = "https://lucidworks.com/demo/?utm_source=docs&utm_medium=referral&utm_campaign=docs_cta_ai"}) => {
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => {
    const timer = setTimeout(() => {
      setIsLoaded(true);
    }, 500);
    return () => clearTimeout(timer);
  }, []);
  return <div className="lw-template-container">
      <Card title={title} icon={icon}>
        {isLoaded && <span dangerouslySetInnerHTML={{
    __html: `<lw-template id="a029c1a9-28be-427e-b0e1-5d918920246a"></lw-template
            >`
  }} />}
        <Link href={linkHref} className="agent-studio-link text-left text-gray-600 gap-2 dark:text-gray-400 text-sm font-medium flex flex-row items-center hover:text-primary dark:hover:text-primary-light group-hover:text-primary group-hover:dark:text-primary-light">Powered by Lucidworks Agent Studio</Link>
      </Card>
    </div>;
};

[localhost link]: http://localhost:3000/docs/lucidworks-search/09-developer-documentation/config-specs/index-pipeline-stages/rest-query

[mintlify link]: https://doc.lucidworks.com/docs/lucidworks-search/09-developer-documentation/config-specs/index-pipeline-stages/rest-query

[old doc.lw link]: https://doc.lucidworks.com/managed-fusion/5.9/a20hmu

The REST Query index stage performs remote procedure calls to external services, merges the response from that service with a document being processed by the pipeline, and makes calls to the external system for each document.

This stage can call external systems in any of the following ways:

* any HTTP or HTTPS request: `<http-protocol>://<path>`
* a Solr request: `solr://COLLECTION_NAME/…​`
* a Lucidworks Search service request: `extservice://SERVICE_NAME/<path>`

The call syntax allows the use of document field variables. For example, variable `${docField}` will be replaced with the value of the field named `docField` for the document being processed.

Several types of responses are also supported:

* POJOs
* JSON
* XML

<LwTemplate />

## Call Parameters

In the Lucidworks Search UI, select **include** to display the fields for the call parameters (`params` in the REST API). Parameters are specified as key-value pairs:

|                                           |                                                                                                                                                                                                                                                                                                                |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Endpoint URI** / `uri`                  | A fully-qualified service URI. This can be an HTTP call, a Solr request, or a Lucidworks Search service call  <br />●any HTTP or HTTPS request: `<http-protocol>://<path>`  <br />●a Solr request: `solr://COLLECTION_NAME/…​`  <br />●a Lucidworks Search service request: `extservice://SERVICE_NAME/<path>` |
| **Call Method** / `method`                | The method to use for the RPC call. Supported methods are `GET`, `POST`, `PUT`, and `DELETE`.                                                                                                                                                                                                                  |
| **Query parameters** / `queryParams`      | Query parameters to be passed with the request.                                                                                                                                                                                                                                                                |
| **Request protocol headers** / `headers`  | Request protocol headers, such as `"Content-Type" : "application/json"`.                                                                                                                                                                                                                                       |
| **Request entity (as string)** / `entity` | The request body. The request body; [see the examples below](#examples).                                                                                                                                                                                                                                       |

The `params` can also take variable substitution expressions. Variables are expressed as `${fieldName}`, where `fieldName` is a name of the current document’s field (or `id` for the document’s id). Only the first value of a multi-valued field is used for substitution, and this value is treated as a string.

For example, a `queryParams` could be constructed as follows:

```json wrap  theme={"dark"}
"params" : {
  "uri" : "solr://collection1/select",
  "method" : "GET",
  "queryParams" : {
    "q" : "{!field f=a_txt v=$prodName}",
    "prodName" : "${prodName}"
  }
}
```

In this example, the variable `${prodName}` will be replaced with the string value of the 'prodName' field in the current document being processed. If the current document contains "iPhone 6" as the value of 'prodName', the resulting query in this example will be a fielded search `q=a_txt:iPhone 6`.

## Mapping Rules

The **mappingRules** property takes the following, specified as key-value pairs:

* path. an [XPath expression](http://www.w3schools.com/xml/xpath_syntax.asp). It is assumed that this expression always returns a node list, and each returned node is processed separately and its converted value is added to a multi-valued field.
* target. the name of the target field in the current document where the value(s) will be stored.
* append. if true, values extracted from the RPC response will be appended to the target multi-valued field. When this is false, the default, existing values in the target field will be discarded and replaced with the values from the RPC response.
* xml. if true, the extracted DOM nodes will be separately serialized to XML and the resulting XML-formatted text will be added to the target field. When this is false, the default, the extracted DOM nodes will be flattened and converted to a list of fields. Field names in this case will correspond to XML element names, dot-separated, and element attributes will be represented as fields with @attributeName suffix.

## Examples

**Create a REST Query stage to merge results from another Solr system:**

```json wrap  theme={"dark"}
{
  "type" : "indexing-rpc",
  "id" : "BasicSolrCall",
  "mappingRules" : [ {
    "path" : "//result/doc[1]/str[@name='foo_s']/text()",
    "target" : "foo_s",
    "append" : true,
    "xml" : false
  }, {
    "path" : "//result/doc/arr[@name='a_txt']/*",
    "target" : "doc_txt",
    "append" : true,
    "xml" : false
  } ],
  "debug" : true,
  "params" : {
    "uri" : "solr://collection1/select",
    "method" : "GET",
    "queryParams" : {
      "q" : "a_txt:${doc_value}"
    },
    "headers" : { }
  },
  "skip" : false,
  "label" : "indexing-rpc"
}
```

**Upload a stopword list:**

```json wrap  theme={"dark"}
{
 "type" : "indexing-rpc",
 "id" : "demo",
 "debug" : true,
 "params" : {
   "uri" : "http://EXAMPLE_COMPANY.lucidworks.cloud/api/stopwords/movies",
   "method" : "PUT",
   "headers" : { "Content-Type" : "application/json" },
   "entity" : "New stopword list"
 },
 "skip" : false,
 "label" : "Indexing RPC Demo",
 "type" : "indexing-rpc"
}
```

<Note>
  Replace `EXAMPLE_COMPANY` with the name provided by your Lucidworks representative.
</Note>

## Configuration

<Tip>
  When entering configuration values in the UI, use *unescaped* characters, such as `\t` for the tab character. When entering configuration values in the API, use *escaped* characters, such as `\\t` for the tab character.
</Tip>

<SchemaParamFields schema={schema} />
