static async apiSingleSearch (req, res, next) {
    if (!ArkimeUtil.isString(req.body.query)) {
      return res.send({ purpose: 'error', text: 'Missing query' });
    }

    const itype = req.params.itype;
    const query = ArkimeUtil.sanitizeStr(req.body.query.trim());
    const indicator = { itype, query };

    const integration = Integration.#integrationsByName[req.params.integration];

    if (integration === undefined || integration.itypes[itype] === undefined) {
      return res.send({ purpose: 'error', text: `integration ${itype} ${req.params.integration} not found` });
    }

    const keys = req.user.getCont3xtKeys();
    const disabled = keys?.[integration.name]?.disabled;
    if (disabled === true || disabled === 'true') {
      return res.send({ purpose: 'error', text: `integration ${itype} ${req.params.integration} disabled` });
    }

    if (integration.viewRoles && !req.user.hasRole(integration.viewRoles)) {
      return res.send({ purpose: 'error', text: `integration ${itype} ${req.params.integration} not allowed` });
    }

    const stats = integration.stats;
    if (itypeStats[itype] === undefined) {
      makeITypeStats(itype);
    }
    const istats = itypeStats[itype];
    stats.total++;
    istats.total++;

    stats.directLookup++;
    istats.directLookup++;
    const dStartTime = Date.now();
    integration[integration.itypes[itype]](req.user, query)
      .then(response => {
        updateTime(stats, istats, Date.now() - dStartTime, 'direct');
        stats.directFound++;
        istats.directFound++;
        if (response === Integration.NoResult) {
          res.send({ purpose: 'data', indicator, name: integration.name, data: { _cont3xt: { createTime: Date.now() } } });
        } else if (response) {
          stats.directGood++;
          istats.directGood++;
          if (!response._cont3xt) { response._cont3xt = {}; }
          response._cont3xt.createTime = Date.now();
          res.send({ purpose: 'data', indicator, name: integration.name, data: response });
          if (Integration.#cache && integration.cacheable) {
            const cacheKey = `${integration.sharedCache ? 'shared' : req.user.userId}-${integration.name}-${itype}-${query}`;
            Integration.#cache.set(cacheKey, response);
          }
        }
      })
      .catch(err => {
        console.log(integration.name, itype, query, err);
        stats.directError++;
        istats.directError++;
        res.status(500).send({ purpose: 'fail', indicator, name: integration.name });
      });
  }
POST - /api/integration/:itype/:integration/search

Fetches integration data about a single itype/integration
@name /integration/:itype/:integration/search
@param {string} query - The string to query the integration
@returns {IntegrationChunk} - The chunk with either: purpose:data, purpose:fail, or purpose:error