Tutorials

Postman & Makaira-API


Creating signed requests with Postman

Task: Check communication between Makaira API and store.

Solution
With Postman it is possible to check the requests signed with the shared secret between the store and Makaira API.
This is done by sending a POST request to the endpoint provided by the store, e.g. <shopurl>?cl=makaira_connect_endpoint in the Oxid Shop.
It is recommended to create an environment configuration with the following variables.

nonce:123456
secret:<shared secret>
requestHash:someValueThatWillBeOverridden

The following headers are required:

Content-Type:application/json
X-Makaira-Nonce:{{nonce}}
X-Makaira-Hash:{{requestHash}}

With a pre-request script, the hash is generated based on the current request body.

var nonce = postman.getEnvironmentVariable("nonce");
var secret = postman.getEnvironmentVariable("secret");

var hashString = nonce + ':' + request.data;
var hash = CryptoJS.HmacSHA256(hashString, secret);

postman.setEnvironmentVariable("requestHash", hash);

Example: Body for checking the update data

POST <shopurl>?cl=makaira_connect_endpoint
{"action":"getUpdates","since":0,"count":10,"language":"de"}

Signing of API requests in the store

Task: Send requests directly to the Makaira API without using the Connect module.

Solution
Communication with the API is secured via signed requests. The signature is formed as a hash over the request body and a randomly generated nonce using a shared secret. The X-Makaira-Nonce and X-Makaira-Hash headers must be transmitted with the request.

PHP example for generating the headers:

<?php

/**
 * Execute a HTTP request to the remote server
 *
 * @param mixed  $body         request body
 * @param string $sharedSecret secret shared between client and application
 *
 * @return array
 */
public function generateSignatureHeaders($body = null, $sharedSecret)
{
    $nonce = bin2hex(random_bytes(16));
    $hash = hash_hmac('sha256', $nonce . ':' . $body, $sharedSecret);
    $headers[] = 'X-Makaira-Nonce: ' . $nonce;
    $headers[] = 'X-Makaira-Hash: ' . $hash;

    return $headers;
}

Control of ES indices via the Makaira API

Task: Change or delete ElasticSearch indexes via the Makaira API.

Solution
Makaira allows manipulating ElasticSearch indexes via the provided API.

The <makaira-url>/indices route is provided as the endpoint.

The requests to interact with the API require a Basic-Auth header from the login credentials for the Makaira instance for verification.

To identify the relevant index, its alias - found in Makaira under "Index Configuration" - can be used, e.g. stage_passive_en

  • Delete an index
    Note: When deleting, only passive indexes should be deleted. The importer ensures that these are automatically created again.
curl -X DELETE \
  https://<CUSTOMER>.makaira.io/indices/stage_passive_de \
  -H 'Authorization: Basic <BASIC-AUTH> \
  -H 'Content-Type: application/json'
  • Activate a passive index
    Note: Activating a passive index always switches the currently active index of the selected language to inactive.
curl -X PUT \
  https://<CUSTOMER>.makaira.io/indices/stage_passive_de/active \
  -H 'Authorization: Basic <BASIC-AUTH> \
  -H 'Content-Type: application/json'
  • Status (revision) of an index
    The request to query the index status has basically the same structure as the previous examples. However, since each instance can have multiple active and passive indexes, an additional header must be sent to specify the desired instance. In the response, the openChanges field indicates the revisions are still to be processed. If this value is 0, the respective index is up to date.
curl -X PUT \
  https://<CUSTOMER>.makaira.io/importer/status \
  -H 'Authorization: Basic <BASIC-AUTH> \
  -H 'Content-Type: application/json' \
  -H 'X-Makaira-Instance: <INSTANCE>'

Customize API request


Set additional product filters

Task: You want to manipulate the item list with additional filters.

Solution
With the help of an OXID eShop module you can extend the API request:

First, create a module directory (here specified with <module_root>) and a metadata.php that looks like this:

<?php
/* <module_root>/metadata.php */

$sMetadataVersion = '1.1';

$aModule = array(
    'id'     => 'makaira/extension',
    'title'  => 'Makaira :: Extension',
    'extend' => array(
        'makaira_connect_request_handler' => '<module_root>/makaira_extension_request_handler'
    ),
    'files'    => array(),
    'blocks'   => array(),
    'settings' => array(),
);

Next comes the override of the makaira_connect_request_handler::modifyRequest() method. This allows easy manipulation of the API request and setting additional filters.

<?php
/* <module_root>/makaira_extension_request_handler.php */

class makaira_extension_request_handler extends makaira_extension_request_handler_parent
{
    protected function modifyRequest(Query $query)
    {
        /*
        $query->customFilter = [
            "product" => [
                "and" => [
                    [
                        "field"    => "OXSTOCK",
                        "operator" => "gt",
                        "value"    => 2
                    ],
                    [
                        "attribute" => "d2eb444e35c0a71f0a85df8194acb5b6",
                        "operator"  => "eq",
                        "value"     => ["blau", "schwarz"]
                    ],
                    [
                        "attribute" => "9438ac75bac3e344628b14bf7ed82c15",
                        "dataType"  => "integer",
                        "operator"  => "gte",
                        "value"     => 10
                    ],
                ],
                "or"  => [],
                "not" => []
            ]
        ];
        */

        return parent::modifyRequest($query);
    }
}

Information
The customFilter property accepts filters for product fields and attributes that are linked using and, or, or not. These can also be nested within each other. As of Makaira-Connect version 2018.11.0, attributes can be imported specifically as numeric attributes. If such an attribute is to be accessed via the customFilter, dataType must be set (integer or float).

The customFilter can be applied only to product attributes, only to variant attributes, or both. So instead of product, makaira-product (variants only) or makaira-productgroup (products only) can be used:

makaira-product filters only by variant attributes

makaira-productgroup filters only by product attributes

product filters on both levels simultaneously: by product and variant attributes

If multiple customFilters with different types are used, they are linked with and.


Provide additional data for autosuggest

Task: You want to display additional fields in Autosuggest, for example, the manufacturer of an item.

Solution
The returned fields of the autosuggest are provided by the following function:

<?php

protected function getFieldsForResults()
{
    $fields = ['OXID', 'OXTITLE', 'OXVARSELECT'];

    return $fields;
}

The function can be found in the Connect module at src/oxid/core/makaira_connect_autosuggester.php.

By extending the class makaira_connect_autosuggester the function can be overridden and more fields can be added.

<?php

class makaira_project_autosuggester extends makaira_project_autosuggester_parent
{
    /**
     * Getter method for resulting fields
     *
     * @return array
     */
    protected function getFieldsForResults()
    {
        $fields   = parent::getFieldsForResults();
        $fields[] = 'MANUFACTURERTITLE';

        return $fields;
    }

    /**
     * data preparation hook
     *
     * @param object $doc
     * @param \oxArticle $product
     *
     * @return array
     */
    protected function prepareProductItem(&$doc, &$product)
    {
        $aItem = parent::prepareProductItem($doc, $product);
        // add additional field
        $aItem['manufacturer'] = $doc->fields['manufacturertitle']

        return $aItem;
    }
}

Information
Calling the parent method ensures that the default autosuggest fields will continue to be used.

When preparing the data for autosuggest, an instance of the item is created. To avoid the associated database request, the loadProductItem method can be overridden instead of the prepareProductItem method.

<?php

class makaira_project_autosuggester extends makaira_project_autosuggester_parent
{
    /**
     * Prepare the data
     *
     * @param object $doc
     *
     * @return array
     */
    protected function loadProductItem($doc)
    {
        if (empty($doc->fields['oxtitle'])) {
            return [];
        }

        $title = $doc->fields['oxtitle'];
        if (!empty($doc->fields['oxvarselect'])) {
            $title .= ' | ' . $doc->fields['oxvarselect'];
        }

        $aItem = [];
        $aItem['label'] = $title;
        $aItem['value'] = $title;
        $aItem['link']  = $doc->fields['url']
        $aItem['type']  = 'product';

        return $aItem;
    }
}

Improve search results with synonym, antonym, and association

Creating synonyms, antonyms and mapping is generally not the best solution to improve search in a store, because unexpected behavior can occur quickly and features like fuzzy search do not work with synonyms. For example, if I have 10 similar products in my store, but they are all named differently, it is possible to create a temporary solution with 10 synonyms, but it would be better to edit the description of the articles or at least to store the most important terms in the Searchkeys field uniformly for each product. Furthermore, it does not make sense to import all synonyms for a term across the board from a synonym dictionary, as this quickly leads to a very fuzzy search. In general, it can be said that concentrating on a few frequently used words is better than trying to cover all conceivable cases.

A good starting point is the evaluation of the search queries (monitoring). If it becomes apparent here that certain search terms frequently do not deliver any results or are linked to a poor conversion rate, these cases should first be checked manually. If it now appears that only a few or no relevant results can be found under this search term, it must be checked whether another search term delivers better results. If the new search really fits better to the customer's intention, synonyms, antonym,s and mapping can be used to improve the search.

Task
Create synonyms and still maintain the search accuracy. The whole thing will be demonstrated on the basis of various cases.

  • In the store about half of the products have black as color description and the other half black .
  • Customers often search for snapsack but all items in my store that match are called backpack or satchel.
  • Customers often search for roomy backpack, they are available in the store, but the word roomy does not appear in any description.

Solution
Under Search->How to search->the following synonyms are created:
black, schwarz
schnappsack=> rucksack, ranzen
geraumiger rucksack=> rucksack