Skip to content

Managing your content with Gally

Romain Ruaud edited this page Jan 18, 2023 · 29 revisions

Managing E-Commerce Content

Gally is tailored for E-Commerce and is able to deal out-of-the-box with the most commonly used concepts in the E-Commerce world : products and categories.

Authentication

First of all, all the write operations will require you to be authenticated.

You should have created an admin user during the setup of your project, that's the account you can use to operate with the API.

To authenticate your API calls, you have to use the authentication_token API :

REST
URL /authentication_token
Method POST
Body
{
  "email": "[email protected]",
  "password": "apassword"
}
Response The auth token
GraphQl

This auth token has then to be injected as a Bearer:AUTH_TOKEN in the "Authorization" header in all your subsequent API calls.

Define your catalogs

In Gally, a Catalog is the representation of a scope of your E-Commerce website.

If you're a retailer that is running several brands, like www.shoes-shop.com and www.glasses-shop.com, you'll want to create two different catalogs :

  • Shoes Shop
  • Glasses Shop

To create your catalog(s), you have to use the Catalog API. The catalog creation is required only once (or if later, you add a new catalog to your webshop).

REST
URL /catalogs
Method POST
Body
{
  "code": "shoes_com",
  "name": "Shoes Shop",
}
Response The created catalog, with IRI for later use
GraphQl

Define your localized catalogs

In Gally, a Localized Catalog is the combination of a Catalog and a locale. Under the hood, this will allow to have one Elasticsearch index per catalog and locale, to be able to deal with different languages.

So if your previously seen Shoes Shop and Glasses Shop are available both in english and french, you'll have two localized catalogs for each of them.

The resulting structure will then be :

  • Shoes Shop (Catalog) :
    • Shoes Shop french (Localized Catalog)
    • Shoes Shop english (Localized Catalog)
  • Glasses Shop (Catalog) :
    • Glasses Shop french (Localized Catalog)
    • Glasses Shop english (Localized Catalog)

To create your localized catalog(s), you have to use the LocalizedCatalog API. The localized catalog(s) creation is required only once (or if later, you add a new locale to your webshop).

REST
URL /localizedcatalogs
Method POST
Body
{
  "name": "Shoes Shop french",
  "code": "shoes_com_fr",
  "locale": "fr_FR",
  "currency": "EUR",
  "isDefault": true,
  "catalog": "shoes_com"
}
Response The created localized catalog, with IRI for later use
GraphQl

That's as simple as that.

Define your source fields and their options

Now that you have your catalogs and localized catalogs, it's time to teach Gally how your catalog structure looks like.

That's where source fields appears. In Gally, each source field is the representation of a field of your entities.

Eg : If your products do have a name, a price and a brand, you need to tell Gally that you have those 3 source fields for the product entity type.

This step will help Gally to define properly the underlying mapping of the Elasticsearch indices that will be used for indexing and searching in content.

The good news is, you don't have to bother with Elasticsearch complicated field types or to understand how they work, Gally's logic is wrapping this inside a more comprehensible manner to define field types.

Default source field types

Type Details Example
text Text fields Product Name, description, etc...
keyword Non-analyzed text fields String identifiers, etc...
select Fields that contains a closed list of values Brand, color, etc...
int Integer fields Unique identifiers, numerical values etc...
boolean True/false fields "Eco label", "Suitable for childrens", etc...
float Floating numbers Not "price" (see below), but rather "width", "length", etc...
object Complex objects containing several sub-fields Structured content (tree, persons with name and surname, etc...)
date Date field

Advanced source field types

Type Details Example
price Price field Product prices for different customer groups, including potential discount
stock Stock field Product stock field, including stock status and quantity
category Category/Product relation field Contains the list of categories a product belongs to
reference Unique identifier field SKU
image Image field URLs of the product images

Create source fields

First, you have to create all your source fields. Source fields creation is required only once, or if the data type of your source field has changed in your ECommerce application.

To create source fields, you have to use the SourceFields API :

REST
URL /sourcefields
Method POST
Body
{
  "code": "name",
  "defaultLabel": "Product Name",
  "type": "text",
  "isFilterable": true,   // Not mandatory
  "isSearchable": true,   // Not mandatory
  "isSortable": true,     // Not mandatory
  "isUsedForRules": true, // Not mandatory
  "weight": 1,            // Not mandatory
  "isSpellchecked": true, // Not mandatory
  "metadata": "product"
}
Response The created source field, with IRI for later use
GraphQl

Here are the details of all the source fields parameters :

Parameter Name Detail
code* The code of the source field. Unique identifier.
defaultLabel* The label of the source field. Untranslated.
type* The type of the source field. As explained before.
metadata* The entity type this fields relates to ("product", "category", or something else.
isFilterable If this field is used for filtering. Can be changed in the back-office later.
isSearchable If this field is used for searching. Can be changed in the back-office later.
isSortable If this field is used for sorting. Can be changed in the back-office later.
isUsedForRules If this field is used for rules (virtual categories, boosts, etc...). Can be changed in the back-office later.
weight  Weight of this field for searching. Can be changed in the back-office later.
isSpellchecked If this field is spellchecked. Can be changed in the back-office later

Create source fields labels (when using several locales)

If you are having several locales (Eg. fr_FR and en_US), you'll have to tell Gally how a source field label should be translated for a given catalog.

Eg : "Material" should be "Matière" when browsing a french localized catalog.

You have to do so with the SourceFieldLabel API.

REST
URL /source_field_labels
Method POST
Body
{
  "sourceField": "/source_fields/4",  // The IRI of the "material" source field
  "localizedCatalog": "shoes_com_fr", // The localized catalog to target
  "label": "Matière"                  // The translated label
}
Response The created source field label, with IRI for later use
GraphQl

Create source fields options (for "select" source fields)

For your source fields that are of type "select", it means they are option-based. You then need to inform Gally what are the options of each field.

Eg : "Material" could have the following options : "Cotton","Wool","Leather"...

You have to do so with the SourceFieldOption API.

REST
URL /source_field_options
Method POST
Body
{
  "code": "material_cotton",          // Unique identifier of the option
  "sourceField": "/source_fields/4",  // The IRI of the "material" source field
  "position": 0,                      // The position of this option within all the options
  "defaultLabel": "Cotton"            // The default label of this option
}
Response The created option, with IRI for later use
GraphQl

Create source fields options labels (for "select" source fields, when using several locales)

If you are having several locales (Eg. fr_FR and en_US), you'll have to tell Gally how a source field option label should be translated for a given catalog.

Eg : "Leather" value of the "Material" Source Field should be "Cuir" when browsing a french localized catalog.

You have to do so with the SourceFieldOptionLabel API.

REST
URL /source_field_options_labels
Method POST
Body
{
  "sourceFieldOption": "/source_field_options/4", // IRI of the option created previously
  "localizedCatalog": "localized_catalogs/1",     // IRI of the localized catalog the option belongs to
  "label": "Cuir"                                 // The translated label
}
Response The created option label, with IRI for later use
GraphQl

Sync your catalog data

Once your catalogs, localized catalogs, and source fields have been defined, you can send your data to Gally to get them indexed into Elasticsearch.

Creating your index

To do so, you first have to ask for creating a new index :

REST
URL /indices
Method POST
Body
{
  "entityType": "string",
  "localizedCatalog": "string"
}
GraphQl

This method will give you the newly created index identifier.

Bulk your data

Then, bulk your data into this newly created index :

REST
URL /index_documents
Method POST
Body
{
  "indexName": "string",
  "documents": [
    "string"
  ]
}
GraphQl

The bulk Api is intended to be used with batches of items. You'll probably be willing to call it in a loop that is parsing your whole catalog and call it as much time as needed.

Bulk format

The Bulk API accepts jsonified version of the data you want to index. Your data has to be accurate with your source field types.

Here is an example table of how your data should be structured per each type :

Source Field Type Data
text
name:"Nike red Shoes"
keyword
my_identifier:"075d8b8"
select
"fashion_size": [
    {
        "value": 33,
        "label": "XL"
    }, {
        "value": 37,
        "label": "XS"
    }, {
        "value": 36,
        "label": "S"
    }, {
        "value": 35,
        "label": "M"
    }, {
        "value": 34,
        "label": "L"
    }
]
int
"width":12
boolean
"has_video": {
        "value": true,
        "label": "Has Video"
    },
float
"length":127.04
object
"actor": {
        "firstname": "Hugh",
        "lastname": "Jackman"
    },
date
"created_at": "2022-09-07 14:57:19"
price
"price": [
    {
        "price": 88,
        "original_price": 88,
        "group_id": 0,
        "is_discounted": false
    }, {
        "price": 75,
        "original_price": 88,
        "group_id": 1,
        "is_discounted": true
    }, {
        "price": 88,
        "original_price": 88,
        "group_id": 2,
        "is_discounted": false
    }
],
stock
"stock": {
    "qty": 0,
    "status": true
},
category
"category": [
    {
        "category_uid": "Mg==",
        "id": "cat_2"
    }, {
        "name": "Tops",
        "category_uid": "OA==",
        "id": "cat_8"
    }, {
        "is_parent": true,
        "name": "Blouses & Shirts",
        "category_uid": "OQ==",
        "id": "cat_9"
    }
]
reference
"sku": "VT04"
image
"image": "\/v\/t\/vt04-mt_main.jpg"
Example of a full document being sent through a bulk
{
	"entity_id": "1104",
	"attribute_set_id": "11",
	"type_id": "configurable",
	"sku": "VT04",
	"has_options": false,
	"required_options": false,
	"created_at": "2022-09-07 14:57:19",
	"updated_at": "2022-09-07 14:57:19",
	"visibility": {
		"value": "4",
		"label": "Catalog, Search"
	},
	"price": [{
		"price": 88,
		"original_price": 88,
		"group_id": 0,
		"is_discounted": false
	}, {
		"price": 88,
		"original_price": 88,
		"group_id": 1,
		"is_discounted": false
	}, {
		"price": 88,
		"original_price": 88,
		"group_id": 2,
		"is_discounted": false
	}, {
		"price": 88,
		"original_price": 88,
		"group_id": 3,
		"is_discounted": false
	}],
	"indexed_attributes": ["price", "name", "url_key", "description", "fashion_material", "fashion_style", "status", "tax_class_id", "fashion_color", "fashion_size", "has_video"],
	"category": [{
		"is_virtual": "false",
		"category_uid": "Mg==",
		"id": "cat_2"
	}, {
		"is_virtual": "false",
		"name": "Tops",
		"category_uid": "OA==",
		"id": "cat_8"
	}, {
		"is_parent": true,
		"is_virtual": "false",
		"name": "Blouses & Shirts",
		"category_uid": "OQ==",
		"id": "cat_9"
	}],
	"name": ["Anna Draped Top"],
	"url_key": ["anna-draped-top"],
	"description": ["<p>The Anna Draped Top hangs beautifully in the all the right places. The soft, sheer material offers graceful lines and seamless movement. Back lace detail and tie at the neckline complete the look.  <\/p><p>Features:<\/p><ul><li>Draped neckline<\/li><li>Capped sleeves<\/li><li>Hits at the hips<\/li><li>Lace detail back &amp; tie neckline<\/li><li>Hand wash, line dry<\/li><\/ul>"],
	"fashion_material": [{
		"value": "47",
		"label": "Cotton"
	}, {
		"value": "56",
		"label": "Viscose"
	}],
	"fashion_style": [{
		"value": "62",
		"label": "Short Sleeve"
	}, {
		"value": "72",
		"label": "Crew"
	}],
	"status": [{
		"value": 1,
		"label": "Enabled"
	}],
	"tax_class_id": [{
		"value": 2,
		"label": "Taxable Goods"
	}],
	"fashion_color": [{
		"value": 5,
		"label": "Gold"
	}, {
		"value": 25,
		"label": "Rain"
	}, {
		"value": 26,
		"label": "Mint"
	}, {
		"value": 24,
		"label": "Lilac"
	}, {
		"value": 28,
		"label": "Latte"
	}],
	"fashion_size": [{
		"value": 33,
		"label": "XL"
	}, {
		"value": 37,
		"label": "XS"
	}, {
		"value": 36,
		"label": "S"
	}, {
		"value": 35,
		"label": "M"
	}, {
		"value": 34,
		"label": "L"
	}],
	"has_video": [{
		"value": true,
		"label": "Has Video"
	}],
	"children_ids": [144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159],
	"children_attributes": ["indexed_attributes", "url_key", "description", "fashion_material", "fashion_style", "fashion_color", "fashion_size", "has_video"],
	"configurable_attributes": ["fashion_color", "fashion_size"],
	"children.indexed_attributes": ["name", "url_key", "description", "fashion_material", "fashion_style", "status", "tax_class_id", "fashion_color", "fashion_size", "has_video"],
	"children.url_key": ["anna-draped-top"],
	"children.description": ["<p>The Anna Draped Top hangs beautifully in the all the right places. The soft, sheer material offers graceful lines and seamless movement. Back lace detail and tie at the neckline complete the look.  <\/p><p>Features:<\/p><ul><li>Draped neckline<\/li><li>Capped sleeves<\/li><li>Hits at the hips<\/li><li>Lace detail back &amp; tie neckline<\/li><li>Hand wash, line dry<\/li><\/ul>"],
	"children.sku": ["VT04-RN-XS", "VT04-RN-S", "VT04-RN-M", "VT04-RN-L", "VT04-MT-XS", "VT04-MT-S", "VT04-MT-M", "VT04-MT-L", "VT04-LL-XS", "VT04-LL-S", "VT04-LL-M", "VT04-LL-L", "VT04-LA-XS", "VT04-LA-S", "VT04-LA-M", "VT04-LA-L"],
	"id": 1104,
	"stock": {
		"qty": 0,
		"status": true
	},
	"image": "\/v\/t\/vt04-mt_main.jpg"
}

Install the index

When you are done with bulks, you can finish the installation of your index :

REST
URL /indices/install/{name}
Method PUT
GraphQl

And then, refresh it :

REST
URL /indices/refresh/{name}
Method PUT
GraphQl

Differential indexing

You may not want to re-create a new index and process all your content when something has changed by your side. That's where differential indexing will help you.

If you have some data that has changed recently (Eg : a product has been edited), here's how you want to proceed :

Get the current "live" index

You can get the current live index by calling the indices API :

REST
URL /indices
Method GET
Response
  "hydra:member": [
    {
      "@id": "/indices/gally_en_fr_product_20230112_152027",
      "@type": "Index",
      "name": "gally_en_fr_product_20230112_152027",
      "aliases": [
        ".catalog_11",
        ".entity_product",
        "gally_en_fr_product"
      ],
      "docsCount": 0,
      "size": "226b",
      "entityType": "product",
      "localizedCatalog": "/localized_catalogs/11",
      "status": "live"
    },
    {
      "@id": "/indices/gally_fr_fr_product_20230112_152026",
      "@type": "Index",
      "name": "gally_fr_fr_product_20230112_152026",
      "aliases": [
        ".catalog_9",
        ".entity_product",
        "gally_fr_fr_product"
      ],
      "docsCount": 1703,
      "size": "1mb",
      "entityType": "product",
      "localizedCatalog": "/localized_catalogs/9",
      "status": "live"
    },.... 
GraphQl

The index (or indices) that has status:live and entityType:product are the ones that you want to index your modified data into.

Bulk your updated data

Just call the bulk API to those indices with the updated data.

Using the API to search for products

Managing additional content

But Gally is more clever than just products and categories. You can also add any other content type (pages, blog posts, etc...) to the engine easily, and to be able to search on those contents.

Create Metadata

Index content

Search for additional content