# Use of Product endpoints

### Creating a product&#x20;

{% tabs %}
{% tab title="HTTP" %}
**POST** /v1/products
{% endtab %}

{% tab title="Request body (json)" %}

```json
[
  {
    "ProductStructureUid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "VariationDefinitionUid": "3fa85f64-5717-4562-b3fc-2c963f66afa5",
    "Classifications": [
      {
        "CategoryId": 0,
        "IsPrimary": true,
        "OwnerReference": "string",
        "SortOrder": 0
      }
    ],
    "WorkflowStateUid": "3fa85f64-5717-4562-b3fc-2c963f66afa4",
    "BusinessUnits": [
      {
        "AccessPolicy": "string",
        "BusinessUnitUid": "3fa85f64-5717-4562-b3fc-2c963f66afa3"
      }
    ],
    "Values": {
      "additionalProp1": "string",
      "additionalProp2": "string",
      "additionalProp3": "string"
    }
  }
]
```

{% endtab %}
{% endtabs %}

When creating new products, we can add more information in regards to their product structure, variation definition, classifications, workflow state and business units. You are not required to include all of these in the product setup. However, in this example we will set everything up so that you can get an idea of how to do your specific task.

#### Fetching the product structure and variation definition

{% code title="C#" overflow="wrap" %}

```csharp
ProductStructure clothingProductStructure = _apiClient.ProductStructures.GetProductStructures().Single(x => x.Alias == "Clothing");
```

{% endcode %}

The `GetProductStructures` method sends an HTTP request to the [/v1/productstructures](https://docs.struct.com/api-reference/endpoints/productstructures) endpoint. It returns a list of `ProductStructure`. We use `Single` to select the only product structure with the alias "Clothing".

Alternatively, you can use the [/v1/productstructures/{uid}](https://app.gitbook.com/o/oxJ2eg1cPA7Tpa74FHpT/s/uUonpFWM7AJ0xVVXV1tr/~/changes/194/api-reference/endpoints/productstructures#get-v1-productstructures-uid) endpoint if you know the specific UID of the product structure you would like to use.

Within the `ProductStructure` instance, you can now get the `VariationDefinition`.

{% code title="C#" overflow="wrap" %}

```csharp
VariationDefinition clothingVariation = clothingProductStructure.VariationDefinitions.Single(x => x.Name == "Clothing");

```

{% endcode %}

We are now able to set the product structure and variation definition Uid on our product model.

<pre class="language-csharp" data-title="C#"><code class="lang-csharp">CreateProductModel&#x3C;ProductModel> productModelToBeCreated = new()
{
   ProductStructureUid = clothingProductStructure.Uid,
<strong>   VariationDefinitionUid = clothingVariation.Uid,
</strong>};
</code></pre>

#### Adding classifications

After defining the product structure and its variations, you can improve it by adding classifications.

Classifications help organize products into groups, making it easier to manage and find product information. Each product can have multiple classifications, but only one can be the primary. This primary classification highlights the most important category for the product.

{% code title="C#" overflow="wrap" %}

```csharp
CreateProductModel<ClothingProductModel> productModelToBeCreated = new()
{
    ProductStructureUid = clothingProductStructure.Uid,
    VariationDefinitionUid = clothingVariation.Uid,

    Classifications = new List<SetClassificationModel>
    {
        new SetClassificationModel()
        {
            CategoryId = 242,
            IsPrimary = true,
            OwnerReference = "made by demo api",
            SortOrder = 0
        },
        new SetClassificationModel()
        {
            CategoryId = 240,
            IsPrimary = false,
            OwnerReference = "made by demo api",
            SortOrder = 0
        },
        new SetClassificationModel()
        {
            CategoryId = 241,
            IsPrimary = false,
            OwnerReference = "made by demo api",
            SortOrder = 0
        }
    },
```

{% endcode %}

#### Adding values

After setting up the clasiffications you now only need to set the values the product should be created with. \
\
Using the [Struct Pim Model generator](https://docs.struct.com/api-reference/introduction#autogenerate-models), we have generated some C# classes in order to have strongly typed models that matches the models in  Struct PIM.

With those we can now specify what type of values we want. In this case we are working with clothing as seen in the code above so we would also want the values to be of type `ClothingProductModel`.

<pre class="language-csharp" data-title="C#" data-overflow="wrap"><code class="lang-csharp">CreateProductModel&#x3C;ClothingProductModel> productModelToBeCreated = new()
{
    ProductStructureUid = clothingProductStructure.Uid,
    VariationDefinitionUid = clothingVariation.Uid,

    Classifications = new List&#x3C;SetClassificationModel>
    {
        new SetClassificationModel()
        {
            CategoryId = 242,
            IsPrimary = true,
            OwnerReference = "made by demo api",
            SortOrder = 0
        },
        new SetClassificationModel()
        {
            CategoryId = 240,
            IsPrimary = false,
            OwnerReference = "made by demo api",
            SortOrder = 0
        },
        new SetClassificationModel()
        {
            CategoryId = 241,
            IsPrimary = false,
            OwnerReference = "made by demo api",
            SortOrder = 0
        }
    },

    Values = new ClothingProductModel
    {
        Name = new List&#x3C;LocalizedData&#x3C;string>>
        {
<strong>            new LocalizedData&#x3C;string> { CultureCode = "en-GB", Data = "New Awesome         Gadget" },
</strong>            new LocalizedData&#x3C;string> { CultureCode = "da-DK", Data = "Ny Fantastisk Gadget" }
        },
        
    }
};
</code></pre>

You can incorporate various attributes under values, such as `Name`, to identify the product. The `Name` attribute is of type `LocalizedData<string>`, allowing the name to vary by language in the PIM. This is done by specifying the `CultureCode` and `Data` for the `Name` attribute.

Now we are mostly done. The remaining information that can be defined besides different values are businessunits that the product has relation to, and the workflow it is assigned to.

{% code title="C#" overflow="wrap" %}

```csharp
 CreateProductModel<ClothingProductModel> productModelToBeCreated = new()
 {
     ProductStructureUid = clothingProductStructure.Uid,
     VariationDefinitionUid = clothingVariation.Uid,
     
     WorkflowStateUid = null,
```

{% endcode %}

In the example above we set the `WorkflowStateUid` as null, since we do not have a workflow for.&#x20;

When adding business units to the product we must first retrieve the business unit. We do this through the [/v1/businessunits](https://docs.struct.com/api-reference/endpoints/businessunits#get-v1-businessunits) endpoint. Just like previously with product we select the business unit through its alias "ClothingUnit".

{% code title="C#" overflow="wrap" %}

```csharp
 BusinessUnitModel clothingBusinessUnit = _apiClient.BusinessUnits.GetBusinessUnits().Single(x => x.Alias == "ClothingUnit");
```

{% endcode %}

Once we have the business unit we can proceed to add it to the product being created.

{% code title="C#" overflow="wrap" %}

```csharp
CreateProductModel<ClothingProductModel> productModelToBeCreated = new()
{
    ProductStructureUid = clothingProductStructure.Uid,
    VariationDefinitionUid = clothingVariation.Uid,
    
    WorkflowStateUid = null,

    BusinessUnits = new List<BusinessUnitRelationModel>
    {
        new BusinessUnitRelationModel
        {
            BusinessUnitUid = clothingBusinessUnit.Uid,
        },
    },
```

{% endcode %}

With everything now set up we can conclude the example by adding the product to the PIM throught the use of the [/v1/products](https://docs.struct.com/api-reference/endpoints/products#post-v1-products) enpoint.

{% code title="C#" overflow="wrap" %}

```csharp
_apiClient.Products.CreateProduct(productModelToBeCreated);
```

{% endcode %}

### Using the /search endpoint

{% tabs %}
{% tab title="HTTP" %}
**POST** /v1/products/search
{% endtab %}

{% tab title="Request body (json) " %}

```json
{
  "IncludeArchived": true,
  "QueryModel": {
    "BooleanOperator": 0
  }
}
```

{% endtab %}

{% tab title="Request body (json) example" %}

```json
{
  "IncludeArchived": false,
  "QueryModel": {
    "SubQueries": [
      {
        "Filters": [
          {
            "FieldUid": "ReleasedInCountries_NA_NA",
            "QueryOperator": 0,
            "FilterValue": "DK"
          }
        ],
        "BooleanOperator": 0,
        "QueryModelType": "SimpleQueryModel"
      },
      {
        "Filters": [
          {
            "FieldUid": "Color.BaseColor.Name_en-GB_NA",
            "QueryOperator": 0,
            "FilterValue": "red"
          },
          {
            "FieldUid": "Color.BaseColor.Name_en-GB_NA",
            "QueryOperator": 0,
            "FilterValue": "blue"
          }
        ],
        "BooleanOperator": 1,
        "QueryModelType": "SimpleQueryModel"
      }
    ],
    "BooleanOperator": 0,
    "QueryModelType": "BooleanQueryModel"
  }
}
```

{% endtab %}
{% endtabs %}

When using the search endpoint to find product IDs, the process can seem complex initially, especially when multiple conditions are involved, as shown in the example above.&#x20;

In the following example we will demystify the request body and set an example to give a better idea on how to perform this specific task.

{% code title="C#" overflow="wrap" %}

```csharp
SearchModel search = new SearchModel();
                    
```

{% endcode %}

Before we can use the search endpoint we need to first understand how to use the `SearchModel` and set up conditions.

We start by instantiating the `SearchModel` publicating it with information. We begin with the `IncludeArchived` property which is a boolean we can set to true or false dependent on if you want to include archived items in result.

{% code title="C#" overflow="wrap" %}

```csharp
SearchModel search = new SearchModel()
{                    
    IncludeArchived = false,
    QueryModel = new BooleanQueryModel
    {
                    
```

{% endcode %}

Once this is done we begin setting up the abstract `QueryModel` which can either be of type `SimpleQueryModel` or  `BooleanQueryModel`.&#x20;

* SimpleQueryModel: Simple query model used for querying specific fields. Used for specifying fields to filter search by.
* BooleanQueryModel: Query wrapper for sub queries where the BooleanOperator operates between the sub queries. Allows for nested queries.

In the example above we want to set up multiple search conditions. For that we would need `SubQueries` which only BooleanQueryModel can contain. However, before adding them we need to specify with a `BooleanOperator` if at least one or all conditions in the `SubQueries` must match by asigning the boolean the value 1 or 0. By selecting the `BooleanOperator.And` (0), we have choosen that all conditions must match for the search to pick up the product id.

{% code title="C#" overflow="wrap" %}

```csharp
SearchModel search = new SearchModel()
{                    
    IncludeArchived = false,
    QueryModel = new BooleanQueryModel
    {
        BooleanOperator = BooleanOperator.And,
        SubQueries = new List<QueryModel>
        {
            new SimpleQueryModel
            {
                Filters = new List<FieldFilterModel>
                {
                    new FieldFilterModel { }
                    
```

{% endcode %}

The `SubQueries` contain a list of `SimpleQueryModels` that each can contain a list of `FieldFilterModels` where the conditions for the search are written. In the scenario where a `SimpleQueryModel` contains multiple `FieldFilterModels`, it is adviced to add a `BooleanOperator` in order to specify if all or only one condition must match.

{% code title="C#" overflow="wrap" %}

```csharp
SearchModel search = new SearchModel()
{                    
    IncludeArchived = false,
    QueryModel = new BooleanQueryModel
    {
        BooleanOperator = BooleanOperator.And,
        SubQueries = new List<QueryModel>
        {
            new SimpleQueryModel
            {
                Filters = new List<FieldFilterModel>
                {
                    new FieldFilterModel
                    {
                        FieldUid = "",
                        QueryOperator = QueryOperator.Equals,
                        FilterValue = ""
                    }
                    
```

{% endcode %}

The `FieldFilterModel` contains three properties, as seen in the example above.

* `FieldUid`: Uid of field to query.
* `QueryOperator`: Can be any of:
  * `Equals` / 0 (Value must be exactly equal to FilterValue(not considering casing))
  * `WildcardEquals` / 1 (Value must start with FilterValue)
  * `SmallerThan` / 2 (Value must be smaller than FilterValue)
  * `LargerThan` / 3 (Value must be larger than FilterValue)
  * `IsEmpty` / 4 (Value must be empty)
  * `IsNotEmpty` / 5 (Value must not be empty)
  * `Contains` / 6 (Value must contain FilterValue)
  * `NotContains` / 7 (Value must not contain FilterValue)
  * `NotEquals` / 8 (Value must not be exactly equal to FilterValue (not considering casing))
  * `NotWildcardEquals` / 9 (Value must not start with FilterValue)
  * `InList` / 10 (Item field value must be part of the provided values in FilterList)
  * `SmallerThanOrEqualTo` / 11 (Value must be smaller than or equal to FilterValue)
  * `InList` / 12 (Value must be larger than or equal to FilterValue)
  * `NotInList` / 13 (Item field value must not be part of the provided values in FilterList)
* `FilterValue`: Value to filter for using the QueryOperator. When QueryOperator is "InList", FilterValue must be an array of values to query for.'

A good way to get all queryable fields from the PIM is through the endpoint [/v1/products/queryablefields](https://docs.struct.com/api-reference/endpoints/products#get-v1-products-queryablefields).&#x20;

With this you can set up simple or complex `SearchModels` using the[ /v1/products/search](https://docs.struct.com/api-reference/endpoints/products#post-v1-products-search) endpoint.

### Example of searching for products

The following example demonstrate a query that looks for products with "Adidas" as the brand, "Portugal" as the country of origin, and having at least 15 variants.

{% code title="C#" overflow="wrap" lineNumbers="true" %}

```csharp
SearchModel searchModel = new SearchModel()
{
    IncludeArchived = false,
    QueryModel = new BooleanQueryModel()
    {
        BooleanOperator = BooleanOperator.And,
        SubQueries = new()
        {
            new SimpleQueryModel()
            {
                BooleanOperator = BooleanOperator.And,
                Filters = new List<FieldFilterModel>()
                {
                    // Country of origin
                    new FieldFilterModel()
                    {
                        FieldUid = "e2342c65-3def-4f57-9fe7-3fe9d3f093ed_en-GB_NA",
                        QueryOperator = QueryOperator.Equals,
                        FilterValue = "Portugal"
                    },

                    // Brand
                    new FieldFilterModel()
                    {
                        FieldUid = "f886acd6-1397-4004-aba0-a3b2d6180151_NA_NA",
                        QueryOperator = QueryOperator.Equals,
                        FilterValue = "Adidas"
                    }
                }
            },

            new SimpleQueryModel()
            {
                Filters = new()
                {
                    // Number of variants
                    new FieldFilterModel()
                    {
                        FieldUid = "PIM_VariantsCount",
                        QueryOperator = QueryOperator.LargerThan,
                        FilterValue = "14"
                    }
                }
            }
        }
    }
};

List<int> queryResult = _apiClient.Products.Search(searchModel);
```

{% endcode %}

{% hint style="info" %}
A common mistake when using the search endpoint is to use AttributeUids instead of FieldUids.\
FieldUids consist of AttributeUids with a culture code and segment included separated by underscores. \
\
The syntax for a FieldUid is: \[AttributeUid]\_\[CultureCode]\_\[Segment]. \
If an attribute is neither localized or dimensioned the FieldUid will be: \[AttributeUid]\_NA\_NA.\
\
All fieldUids can also be found by using the queryablefields endpoint for entities, e.g. [/v1/products/queryablefields](https://docs.struct.com/api-reference/endpoints/products#get-v1-products-queryablefields) for products.
{% endhint %}
