# Attributes

## Structure

The attribute field is an array of JSON elements. Each attribute must declare the following fields.

| Name           | Type           | Mandatory                           | Description                                                                                                                                                                                               |
| -------------- | -------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type           | type as string | yes                                 | See available types below                                                                                                                                                                                 |
| localizedNames | list           | no                                  | <p>List of objects providing available translations per locale:</p><p><code>{</code><br><code>"locale": "\<langcode\_countrycode>",</code><br><code>"name": "\<translation>"</code><br><code>}</code></p> |
| isRequired     | Boolean        | no                                  | The attribute is required or not on item creation                                                                                                                                                         |
| isReturned     | Boolean        | no                                  | XO configuration                                                                                                                                                                                          |
| isIndexed      | Boolean        | no                                  | XO configuration                                                                                                                                                                                          |
| isExported     | Boolean        | no                                  | XO configuration                                                                                                                                                                                          |
| attributes     | list           | yes if type is Object or ObjectList | type of elements in object                                                                                                                                                                                |
| listSubType    | Boolean        | yes if type is List                 | type of elements in list                                                                                                                                                                                  |
| isFhrValue     | Boolean        | no                                  | Define if the attribute is related to the FHR Value attribute                                                                                                                                             |
| isFhrValueId   | Boolean        | no                                  | Define if the attribute is related to FHR Value Id attribute                                                                                                                                              |

Attributes name can be freely defined \_\*\*\_but [certain attributes are reserved for use](https://crownpeak.gitbook.io/product-discovery/sending-and-managing-product-data/what-is-the-items-api/working-with-items/item-schema/list-of-reserved-attributes).

### Available types

| **Name**      | **Description**                                                                                   |
| ------------- | ------------------------------------------------------------------------------------------------- |
| BOOLEAN       | true/false                                                                                        |
| FLOAT         | Floating numbers                                                                                  |
| INTEGER       | Integer numbers                                                                                   |
| TEXT          | String                                                                                            |
| TIMESTAMP     | Must be in [RFC 3339 timestamp format](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) |
| LIST          | List of values, each value with the same type                                                     |
| OBJECT        | Key value object, where each value as its own schema.                                             |
| OBJECTLIST    | List of objects (only object of the same schema are allowed)                                      |
| LOCALIZEDTEXT | Key value object (see below)                                                                      |

### Localized Text

The **LOCALIZEDTEXT** type allows you to add translations to the given field defined in the attributes. It's a key-value object where:

* key is based on the Java locale format *\<languagecode>\_*\<countrycode>
  * *languagecode* is based on the [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
  * *countrycode* is defined by [ISO 3166-1](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes)
* values are strings

Let's say that the `title` field of your item has a French and German translation:

```javascript
// LocalizedText attribute definition in itemSchema
{
    "name": "title",
    "type": "LOCALIZEDTEXT"
},‌

// final attribute
{
    "title": {
        "fr_FR": "mon titre",
        "en_GB": "my title",
        "de_DE": "mein Titel"
    }
}
```

LOCALIZEDTEXT can be used where text fields are available (as is, in a LIST, in an OBJECT or OBJECTLIST)

XO features (recommendation, product tagging) need a default locale to work.\
This default locale must be set in [this api](https://crownpeak.gitbook.io/product-discovery/sending-and-managing-product-data/what-is-the-items-api/working-with-items/item-schema/defaultlocale-api).

### Type decision tree

<figure><img src="https://3916646904-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfLO8j00CcKdYax4GPUyE%2Fuploads%2FEX4Y1KjnGQNBf8Qj217k%2Ftype-decision-tree.png?alt=media&#x26;token=bc07d928-1af1-4f84-b0e2-ec6837308aaa" alt=""><figcaption></figcaption></figure>

### FHR data modeling

To make use of FHR specific features refer to below table on how to model item's attributesype

{% tabs %}
{% tab title="Types" %}

| Type          | Usage                                                                                                                                                              | Notes                                                                                                                                                                                                                                                                                     |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| BOOLEAN       | Flag out of stock or on sale items.                                                                                                                                | Implicitly converted to ***INTEGER**, False - 0, True - 1*                                                                                                                                                                                                                                |
| INTEGER       | For (bracketed) facets and sorting on e.g. stock amounts, ratings, etc.                                                                                            | **Only positive** integer values are allowed.                                                                                                                                                                                                                                             |
| FLOAT         | Typically used for bracketed facets and sorting on prices, margin, discounts etc.                                                                                  | **Only positive** float values are allowed. Negative values will be considered as undefined.                                                                                                                                                                                              |
| TEXT          | Not multi lingual but possible to navigate on. It is typically used for product codes that are locale independent and need to be displayed or free text searchable | Data type **without locale specific values**, i.e. its value is the same across all locales.                                                                                                                                                                                              |
| TIMESTAMP     | Same as text                                                                                                                                                       | Implicitly converted to ***datetime.***                                                                                                                                                                                                                                                   |
| LOCALIZEDTEXT | Meant for free text search and display purposes. Typical examples of this are product descriptions or image references.                                            | An asset value does not have a locale independent identifier. It is **not possible to create facets or sort on assets**                                                                                                                                                                   |
| LIST          | Used exclusively for providing product item's categorization (*categories* attribute) as list of leaf category ids the item belongs to.                            | Not multi lingual, any other attribute of the type is implicitly converted to ***OBJECTLIST*** where each value is made available for all catalog localizations.                                                                                                                          |
| OBJECT        | Typically used for facets. One value per item.                                                                                                                     | Represents fixed list of **multi-lingual, locale dependent display values (*****values*** property) sharing the same **locale independent value identifier** (**value\_id** property). Identifiers should be unique to the attribute and can contain **only characters a-z0-9 and "\_"**. |
| OBJECTLIST    | Typically used for facets. Multiple values per item.                                                                                                               | The type specifics are identical to OBJECT.                                                                                                                                                                                                                                               |
| {% endtab %}  |                                                                                                                                                                    |                                                                                                                                                                                                                                                                                           |

{% tab title="Example schema" %}

```javascript
{
    "name": "product",
    "tenant": "demo",
    "environment": "live1",
    "attributes": [
        {
            "name": "_imageurl",
            "type": "TEXT"
        },
        {
            "name": "from_date",
            "type": "TIMESTAMP"
        },
        {
            "name": "name",
            "type": "LOCALIZEDTEXT"
        },
        {
            "name": "categories",
            "type": "LIST"
        },
        {
            "name": "gender",
            "type": "OBJECT",
            "attributes": [
                {
                    "name": "value_id",
                    "type": "TEXT"
                },
                {
                    "name": "value",
                    "type": "LOCALIZEDTEXT"
                }
            ]
        },
        {
            "name": "colour",
            "type": "OBJECTLIST",
            "attributes": [
                {
                    "name": "value_id",
                    "type": "TEXT"
                },
                {
                    "name": "value",
                    "type": "LOCALIZEDTEXT"
                }
            ],
            "localizedNames": [
            {
                "locale": "en_GB",
                "name": "Colour"
            },
            {
                "locale": "fr_FR",
                "name": "Couleur"
            }
        }
    ],
    "nestedItemSchemas": [
        "slug": "variant",
        "attributes": [
            {
                "name": "in_stock",
                "type": "BOOLEAN"
            },
            {
                "name": "stock",
                "type": "INTEGER"
            },
            {
                "name": "price",
                "type": "FLOAT"
            }
        ]
    ]
}
```

{% endtab %}

{% tab title="Example item attribute" %}
**Product item**

```javascript
{
    "id": "p1",
    "type": "product",
    "attributes": {
        "_imageurl": "https://example.com/img.png",
        "from_date": "2012-04-23T18:25:43.511Z",
        "name": {
            "en_GB": "World Cup Boots",
            "fr_FR": "Chaussures World Cup"
        },
        "categories": [
            "shoes_1234",
            "sale_6789"
        ],
        "gender": {
            "value_id": "unisex",
            "value": {
                "en_GB": "Unisex",
                "fr_FR": "Unisexe"
            }
        },
        "colour": [
            {
                "value_id": "red",
                "value": {
                    "en_GB": "Red",
                    "fr_FR": "Rouge"
                }
            },
            {
                "value_id": "blue",
                "value": {
                    "en_GB": "Blue",
                    "fr_FR": "Bleu"
                }
            }
        ]
    }
}
```

**Variant item**

```javascript
{
    "id": "v1",
    "type": "variant",
    "attributes": {
        "in_stock": true,
        "stock": 12,
        "price": 33.3
    },
    "parentId": "p1"
}
```

{% endtab %}
{% endtabs %}

### FHR functionality matrix

The following table provides an overview of some FHR functionalities and how each types can be used for that:

| Type          | Create facet/filter | Create ranking | Include in ranking cocktail | Translatable | Searchable | Multiple values per item |
| ------------- | ------------------- | -------------- | --------------------------- | ------------ | ---------- | ------------------------ |
| BOOLEAN       | ✔                   | ✔              | ✔                           | ✘            | ✘          | ✘                        |
| INTEGER       | ✔                   | ✔              | ✔                           | ✘            | ✘          | ✘                        |
| FLOAT         | ✔                   | ✔              | ✔                           | ✘            | ✘          | ✘                        |
| TEXT          | ✔                   | ✔              | ✘                           | ✘            | ✔          | ✘                        |
| TIMESTAMP     | ✔                   | ✔              | ✘                           | ✘            | ✔          | ✘                        |
| LOCALIZEDTEXT | ✘                   | ✘              | ✘                           | ✔            | ✔          | ✘                        |
| LIST          | ✔                   | ✔\*            | ✘                           | ✔            | ✔          | ✔                        |
| OBJECT        | ✔                   | ✔              | ✘                           | ✔            | ✔          | ✘                        |
| OBJECTLIST    | ✔                   | ✘              | ✘                           | ✔            | ✔          | ✔                        |

\* Not applicable for ***categories*** attribute.

### FHR Object Type

To work with attribute type "Object" with FHR, the object's attribute must have one attribute with the `isFhrValue` flag and one with the `isFhrValueId` flag.

The flags are automatically set if your schema is following this structure:

```json
[
    {
        "name": {attribute_name},
        "type": "OBJECT",
        "attributes": [
            { "name": "value", "type": "TEXT" | "LOCALIZEDTEXT"},
            { "name": "valueId", "type": "TEXT"}
        ]
    }
]
```

## Examples

Here is an example of item schema with one field of each type:

```javascript
[
    // boolean attribute
    {
        "name": "in_stock",
        "type": "BOOLEAN"
    },

    // float attribute
    {
        "name": "customer_rating",
        "type": "FLOAT"
    },

    // integer attribute
    {
        "name": "price",
        "type": "INTEGER"
    },

    // text attribute
    {
        "name": "title",
        "type": "TEXT"
    },

    // LocalizedText attribute with translation
    {
        "name": "title",
        "type": "LOCALIZEDTEXT"
        "localizedNames": [
            {
                "locale": "en_GB",
                "name": "Title"
            },
            {
                "locale": "fr_FR",
                "name": "Titre"
            }
        ]
    },

    // timestamp attribute
    {
        "name": "start_date",
        "type": "TIMESTAMP"
    },

    // list attribute
    {
        "name": "categories",
        "type": "LIST",
        "listSubType": "TEXT"
    },

    // object attribute
    // must have a nested schema in "attributes" which
    // corresponds to the schema of the object
    {
        "name": "film",
        "type": "OBJECT",
        "attributes": [
            {
                "name": "film_title"
                "type": "TEXT"
            },
            {
                "name": "film_description"
                "type": "TEXT"
            }
        ]
    },

    // FHR object attribute 
    // must have a nested schema in "attributes" which
    // corresponds to the schema of the object
    {
        "name": "brand",
        "type": "OBJECT",
        "attributes": [
            {
                "name": "value_id"
                "type": "TEXT"
            },
            {
                "name": "value"
                "type": "LOCALIZEDTEXT"
            }
        ]
    },

    // objectList attribute
    // must have a nested schema in "attributes" which
    // corresponds to the schema of the objects
    {
        "name": "film"
        "type": "OBJECTLIST",
        "attributes": [
            {
                "name": "film_title",
                "type": "TEXT"
            },
            {
                "name": "film_description",
                "type": "TEXT"
            }
        ]
    },

    // FHR objectList attribute
    // must have a nested schema in "attributes" which
    // corresponds to the schema of the objects
    {
        "name": "color"
        "type": "OBJECTLIST",
        "localizedNames": [
            {
                "locale": "en_GB",
                "name": "Colour"
            },
            {
                "locale": "fr_FR",
                "name": "Couleur"
            }
        ],
        "attributes": [
            {
                "name": "value_id",
                "type": "TEXT"
            },
            {
                "name": "value",
                "type": "LOCALIZEDTEXT"
            }
        ]
    }
]
```

OBJECT and OBJECTLIST types allow recursive typing:

```javascript
[
    // object attribute with nested object
    {
        "name": "film"
        "type": "OBJECT"
        "attributes": [
            {
                "name": "film_title",
                "type": "TEXT"
            },
            {
                "name": "film_description",
                "type": "OBJECT",
                "attributes": [
                    {
                        "name": "scenario",
                        "type": "TEXT"
                    }
                    {
                        "name": "actors",
                        "type": "LIST",
                        "listSubType": "TEXT"
                    }
                ]
            }
        ]
    }
```

## Validation

Additional validation:

* each attribute (and attributes of inner schemas) should have unique attribute names
* the following attributes name are reserved and cannot be used : "secondid", "universe", "countries", "itemid", "match\_rate", "categories"

## FHR data model validation

The query parameter fhrValidation=true can be added to enforces Fredhopper specific validation to the schema API. This includes the following additional checks to the schema:

* Attribute name (aka attribute\_ids) are lowercased with only \[a-z0-9\_]+ i.e. lowercase Latin letters: `a-z`, digits: `0-9`, and underscores: `_`
* Value (type TEXT) and value\_id (type TEXT or LOCALIZEDTEXT) are mandatory for attributes of type OBJECT and OBJECTLIST
* Attribute name (aka attribute\_ids) cannot start with a number
* FHR valid types for attributes are : “boolean”, “text”, “integer”, “float”, “list”, “localizedText”, “Object”, “ObjectList”, “timestamp”
