This is expected behavior.
Here's the TLDR for anyone else who comes across this question. Your API endpoint is defined in vendor/magento/module-catalog/etc/webapi.xml
. The PUT method with this endpoint calls the ProductRepositoryInterface's save
method:
<route url="/V1/products/:sku" method="PUT">
<service class="Magento\Catalog\Api\ProductRepositoryInterface" method="save" />
<resources>
<resource ref="Magento_Catalog::products" />
</resources>
</route>
This interface is implemented by \Magento\Catalog\Model\ProductRepository
, and its save
method expects a ProductInterface parameter which, critically, you have not provided, and cannot provide, in your API call:
public function save(ProductInterface $product, $saveOptions = false)
{
$assignToCategories = false;
$tierPrices = $product->getData('tier_price');
$productDataToChange = $product->getData();
// other things happen
}
So where does the $product
parameter come from? In Magento's API system, parameters provided to API service classes are created using reflection:
Because of this, Magento uses reflection to automatically create these
classes and sets data that you have submitted in JSON or HTTP array
syntax onto an instance of the expected PHP class when calling the
service method.
I don't know the deep magic of reflection well enough to point you to the place that it happens; but I expect that by providing the SKU, you tell Magento to create the $product
parameter from the existing product identified by that SKU.
By the time you hit the save
method, then, your $product
object exists with all the data you'd expect an existing product to have. The repository will treat it just like it would any other product you're saving to repo: namely, saving new data without overwriting existing data you haven't explicitly changed.