Как использовать значение параметра, заданное пользователем в веб-приложении, в запросе Optic API в Marklogic? - PullRequest
0 голосов
/ 23 февраля 2019

Blockquote

У меня есть веб-приложение (написанное в js), где пользователь может ввести имя (наряду с другими критериями), выполнить поиск по базе данных ML и выполнитьвозвращается табличное представление некоторых данных, связанных с этим именем (или другими критериями поиска).На первых этапах разработки я писал оптические api-запросы со значением для имени, жестко закодированным в операторе where запроса.Я сделал это, чтобы проверить, что API REST правильно вызывал запрос и т. Д. Что все работает, и я вижу правильные результаты для этого жестко закодированного имени, возвращаемого в веб-приложении.Теперь я хочу передать введенное пользователем значение для имени в запрос API Optic (EntityInformation_Optic_API_Query.json), чтобы заменить жестко закодированное значение в выражении where.Как мне это сделать?Заранее спасибо.


владелец редактировать

Приложение написано на PHP, и я скопировал код ниже.В этом вы можете увидеть, где вызывается оптический API-запрос и где строятся параметры.

<?php
if (!defined('RSS_BASE_URL')) exit;

use MarkLogic\MLPHP as MLPHP;

function rss_api_call($json, $params = array(), $resource = 'rows', $verb = 'POST')
{
    $json = __DIR__ . '/json/' . $json;

    if (!file_exists($json)) return false;

    $request = new MLPHP\RESTRequest('POST', 'rows', $params, file_get_contents($json), array('Content-type' => 'application/json'));
    $response = rss_get_client()->send($request);

    return json_decode($response->getBody());
}

function rss_api_entities()
{
    $params = array();

    return rss_api_call('EntityInformation_Optic_API_Query.json', $params);
    //return (empty($params)) ? '' : rss_api_call('EntityInformation_Optic_API_Query.json', $params);
}

function rss_api_search()
{
    $params = array();

    if (isset($_POST['companyname']) && !empty($_POST['companyname']))
    {
        $params['CompanyName'] = htmlspecialchars($_POST['companyname']);
    }

    if (isset($_POST['EIN']) && !empty($_POST['ein']))
    {
        $params['EIN'] = htmlspecialchars($_POST['ein']);
    }

    if (isset($_POST['city']) && !empty($_POST['city']))
    {
        $params['EntityCity'] = htmlspecialchars($_POST['city']);
    }

    if (isset($_POST['state']) && !empty($_POST['state']))
    {
        $params['EntityState'] = htmlspecialchars($_POST['state']);
    }

    if (isset($_POST['zip']) && !empty($_POST['zip']))
    {
        $params['EntityZip'] = htmlspecialchars($_POST['zip']);
    }

    return rss_api_call('SearchResults_Optic_API_Query.json', $params);
    //return (empty($params)) ? '' : rss_api_call('SearchResults_Optic_API_Query.json', $params);
}

function rss_asset_path($path, $file_name)
{
    global $rss_manifest;

    if (empty($rss_manifest))
    {
        ob_start();

        include(__DIR__ . '/../manifest.json');

        $rss_manifest = json_decode(ob_get_clean(), true);
    }

    if (isset($rss_manifest[$file_name]))
    {
        $file_name = $rss_manifest[$file_name];
    }

    return RSS_ASSET_PATH . $path . '/' . $file_name;
}

function rss_box($title, $content)
{
    echo '<div class="rss-box">' .
        '<div class="rss-box-title">' . $title . '</div>' .
        '<div class="rss-box-content">' . $content . '</div>' .
        '</div>';
}

function rss_get_client()
{
    $mlphp = new MLPHP\MLPHP(array
    (
        'host' => RSS_API_HOST,
        'port' => RSS_API_PORT,
        'version' => RSS_API_VERSION,
        'username' => RSS_API_USERNAME,
        'password' => RSS_API_PASSWORD
    ));

    return $mlphp->getClient();
}

function rss_hidden_search_fields()
{
    echo '<div class="rss-hidden">';

    $fields = array('debug', 'companyname', 'ein', 'city', 'state', 'zip');

    foreach ($fields as $field)
    {
        echo (isset($_POST[$field])) ? '<input name="' . $field . '" type="hidden" value="' . htmlspecialchars($_POST[$field]) . '" />' : '';
    }

    if (!empty($_POST['social']))
    {
        $social = (is_array($_POST['social'])) ? $_POST['social'] : array($_POST['social']);

        foreach ($social as $social_network)
        {
            echo '<input name="social[]" type="hidden" value="' . htmlspecialchars($social_network) . '" />';
        }
    }

    echo (empty($_POST['social-select-all'])) ? '' : '<input name="social-select-all" type="hidden" value="1" />';
    echo '</div>';
}



Part of the EntityInformation_Optic_API_Query.json is below
-----

edit (information from a comment below):

The request will be a POST to /v1/rows. Does the following payload look correct? 

```javascript
{
    "$optic": {
        "ns": "op",
        "fn": "operators",
        "args": [
            {
                "ns": "op",
                "fn": "from-view",
                "args": [ "TestSchema", "SUT", null, null ]
            },
            {
                "ns": "op",
                "fn": "where",
                "args": [
                    {
                        "ns": "op",
                        "fn": "eq",
                        "args": [
                            {
                                "ns": "op",
                                "fn": "col",
                                "args": [ "CompanyName" ]
                            },
                            "${req.params.CompanyName}"
                        ]
                    }
                ]
            }

Ответы [ 3 ]

0 голосов
/ 26 февраля 2019

Для веб-приложения на Java или Node.js наилучшим подходом может быть написание функции, которая принимает значение, создает и возвращает запрос Optic.

В других средах, используя представление JSON и вставкузначение будет самым безопасным.

Сборка JSON-сериализации запроса Optic в виде строки возможна с экранированием, хотя иногда трудно отладить.В коде MarkLogic JSON анализируется как JSON, а не оценивается, поэтому нет риска инъекционных атак, но возможны сбои синтаксического анализа.

Надеюсь, что поможет,

0 голосов
/ 28 февраля 2019

Я считаю, что вам нужно использовать параметры "связывания".Таким образом, ваш план будет выглядеть следующим образом:

{
  "$optic": {
    "ns": "op",
    "fn": "operators",
    "args": [
      {
        "ns": "op",
        "fn": "from-view",
        "args": [
          "TestSchema",
          "SUT",
          null,
          null
        ]
      },
      {
        "ns": "op",
        "fn": "where",
        "args": [
          {
            "ns": "op",
            "fn": "eq",
            "args": [
              {
                "ns": "op",
                "fn": "col",
                "args": [
                  "CompanyName"
                ]
              },
              {
                "ns": "op",
                "fn": "param",
                "args": [
                  "companyName"
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

И затем, когда вы публикуете это в / v1 / row, вам нужно установить параметр и тип привязки companyName.Итак, добавьте следующие параметры к вашему POST:

bind:companyName=${req.params.CompanyName}
bind:companyName:type=xs:string

Предполагая, что ${req.params.CompanyName} содержит значение названия компании, переданное пользователем.

В качестве примечания, касающегося сериализованных планов OpticРука может быть жесткой.Я бы порекомендовал вам оставить это за расширением REST и просто передать параметры.Если вы действительно хотите сохранить планы Optic на своем среднем уровне, вы всегда можете использовать консоль запросов MarkLogic для генерации плана с соответствующими вызовами op.param(), для которых вы хотите иметь параметризованные значения.IE что-то вроде:

const op = require('/MarkLogic/optic');
const plan = op
  .fromView("TestSchema", "SUT")
  .where(
    op.eq(
      op.col("CompanyName"), op.param("companyName")
    )
  )

plan.export()
0 голосов
/ 25 февраля 2019

Это зависит от того, как вы настраиваете приложение.

REST API

Если ваш код будет расширением REST API, функция, которую вы напишете, будет иметь параметр params.Для JavaScript это будет объект.См. Интерфейс расширения ресурсов JavaScript .Из этой части документов:

Если запрос PUT /v1/resource/my-ext?rs:p=1&rs:p=2, то значение params.p равно ["1", "2"].

Основной модуль

Если клиент получит доступ к вашему коду через обычный (не REST) ​​основной модуль, используйте xdmp.getRequestField.


Редактировать: я обновил ваш вопрос с дополнительной информацией из вашего комментария.Мне кажется, что у вас есть средний уровень, который принимает параметры от клиента (браузера) и использует их для построения запроса для передачи /v1/rows.Похоже, что "${req.params.CompanyName}" предназначен для интерполяции, так что ваш средний уровень получает значение req.params.CompanyName, которое затем помещается в строку, которая отправляется в MarkLogic.

Возможно ли, что "${req.params.CompanyName}" был добавлен в строку с неповрежденными кавычками, чтобы средний уровень не мог выполнить интерполяцию?Если вы можете предоставить больше информации о том, как создается полезная нагрузка для /v1/rows, мы можем предложить дополнительную помощь.

...