Magento 2 REST API – Products Not Saved Correctly

catalogmagento2productrestsave

I create products through the REST API (catalogProductRepositoryV1) using a POST request.

For some reason there is something different about these products. Just after creating them everything seems to work fine, but after a while (I haven't been able to figure when or why) they seem to break and any change to product attributes stops working.

If I for example change the name of a product it appears to work and saves correctly while on the edit page of the product. However the changes do not take effect and the name stays unchanged in the product list and in the shop. I obviously need to be able to update and change product.

I use the following body in the POST request:

{
    "saveOptions": true,
    "product": {
        "attribute_set_id": 10,
        "visibility": 4,
        "price": 125,
        "type_id": "virtual",
        "name": "CreatedThroughRest",
        "options": [
            {
                "product_sku": "test123",
                "title": "This is a gift",
                "type": "checkbox",
                "sort_order": 1,
                "is_require": false,
                "values": [
                    {
                        "title": "Yes",
                        "price": 0,
                        "price_type": "fixed",
                        "sku": "gift"
                    }
                ],
                "extension_attributes": {}
            }
        ],
        "extension_attributes": {
            "stock_item": {
                "manage_stock": false,
                "is_in_stock": true,
                "use_config_manage_stock": false
            }
        },
        "sku": "test123",
        "status": 2,
        "custom_attributes": [
            {
                "value": "1970-01-01 01:00:00",
                "attribute_code": "available_from_date"
            },
            {
                "value": "2032-02-26 11:04:02",
                "attribute_code": "available_to_date"
            }
        ]
    }
}

I also have a cron job for enabling/disabling product, where the exact same thing happens after the products break. I use addFieldToFilter('status', \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED) to look for disabled products and after changing the status, it is no longer found by the product collection even though the status in the product list says disabled.

Image 1: List shows status "Disabled"
enter image description here

Image 2: Product edit page shows status "Enabled"
enter image description here

Best Answer

Edit: There was a recent documentation update for the Magento REST API. It seems by changing the API path from <root domain>/rest/default/<api endpoint> to <root domain>/rest/all/<api endpoint> you will affect the global/default data instead of the store-specific data. However, this only works for POST or PUT requests for products, categories, etc. (Data types which use store values.)


I believe this may have to do with an issue that's already been brought up in the Magento 2 issue list. When you save a product through the API, it automatically selects the store based on the URL. Since API endpoints are always forwarded to the store front-end, this means its going to select the ID of that storefront and NOT the global ID of 0 (the default settings).

What this means is that the API will save the attributes for that store's overrides. If you select the "Store View" of the frontend store when viewing the product within the admin, you will likely find that the updated attributes have been saved to this store scope. If you make changes to the 'default' data at this point, it will not reflect on the frontend.

On the store I manage, we've created a plugin for the API method which forces it to use the 'admin' scope when saving attributes with the API.

/**
 * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
 * @param \Magento\Catalog\Api\Data\ProductInterface $product
 * @param bool $saveOptions
 * @return array
 * @throws \Magento\Framework\Exception\InputException
 * @throws \Magento\Framework\Exception\StateException
 * @throws \Magento\Framework\Exception\CouldNotSaveException
 */
public function beforeSave($productRepository, \Magento\Catalog\Api\Data\ProductInterface $product, $saveOptions = false)
{
    $product->setSku(urldecode($product->getSku()));
    $this->storeManager->setCurrentStore('admin');
}

Note that you'll also have to remove and/or incorporate the frontend overrides back into your default dataset.

Related Topic