6

I want to send a JSON string via API, and then parse the JSON in code. I don't want Magento to try to convert my JSON parameter to a PHP object.

I'm trying to add this to the stock registry API. Here's the code that I've added.

webapi.xml

<route url="/V1/products/stockItems/update/" method="POST">
    <service class="Magento\CatalogInventory\Api\StockRegistryInterface" method="updateStockItems"/>
    <resources>
        <resource ref="Magento_CatalogInventory::cataloginventory"/>
    </resources>
</route>

StockRegistryInterface.php

public function updateStockItems($stockItems);

StockRegistry.php

public function updateStockItems($stockItems)
{
   // do stuff
}

I'm posting to http://magento.test/rest/V1/products/stockItems/update using Postman.

Here is my request address and headers.

enter image description here

enter image description here

Here's my JSON body

{
   "stockItems": [
      {
        "item_id": 1,
        "product_id": 1,
        "stock_id": 1,
        "qty": 15
      },
      {
        "item_id": 2,
        "product_id": 2,
        "stock_id": 2,
        "qty": 15
      }
   ]
}

I'm getting the error

[2019-03-06 18:22:44] main.CRITICAL: Report ID: webapi-5c800ff4b4623;
Message: Class  does not exist {"exception":"[object] (Exception(code: -1):
Report ID: webapi-5c800ff4b4623; Message: Class  does not exist at 
/var/www/magento2/lib/internal/Magento/Framework/Webapi/
ErrorProcessor.php:205, ReflectionException(code: -1): 
Class  does not exist at /var/www/magento2/lib/internal/Magento/Framework/
Webapi/ServiceInputProcessor.php:162)"} []

How do I get Magento to let me pass my JSON into updateStockItems without trying to convert it to a Magento object?

Update

I can get it to work by passing my JSON as a string and then parsing that string into JSON in the PHP code. If I use the following as the body of my request, it works. But that seems like a dirty workaround. Is there a better way of doing it?

{ "stockItems": "[ {\"sku\": \"SKU-1234\", \"quantity\": 1234}, {\"sku\": \"SKU-5678\", \"quantity\": 5678} ]" }

And here's my PHP code (getStockItemBySku is an existing Magento function within StockRegistry.php)

public function updateStockItems($stockItems)
{
    $json = json_decode($stockItems, true);
    $updatedItemCount = 0;
    foreach ($json as $productJson)
    {            
        $sku = $productJson['sku'];
        $quantity = $productJson['quantity'];
        if ($sku !== NULL && $quantity != NULL)
        {
            $stockItem = $this->getStockItemBySku($sku);
            if ($stockItem !== NULL)
            {
                $stockItem->setQty($quantity);
                $this->stockItemRepository->save($stockItem);
                $updatedItemCount++;
            }
        }
    }
    return $updatedItemCount;
}
11
  • it should be rest not test
    – fmsthird
    Commented Mar 6, 2019 at 21:14
  • Sorry, typo. I updated it. It's rest in my actual code.
    – Ben Rubin
    Commented Mar 6, 2019 at 21:14
  • you should include in your header the Content-type of your request, it should be Content-Type: application/json
    – fmsthird
    Commented Mar 6, 2019 at 21:28
  • I've got that in my header. I'm using Postman to send requests, and I've got Content-Type: application/json as one of my headers in the request.
    – Ben Rubin
    Commented Mar 6, 2019 at 21:40
  • I updated my question to show the request headers.
    – Ben Rubin
    Commented Mar 6, 2019 at 21:42

2 Answers 2

4

I hope you don't have the intention to "hack" Magento core files. I recommend to create your own classes / interfaces for that!

Anyway if you are implementing a custom method updateStockItems for a webapi which updates more stockitems with a single request you should take care of the right method signature: You are expecting an array of stock items, therefore your input parameter should be of that type.

Your interface:

/**
 * 
 * @param \Magento\CatalogInventory\Api\Data\StockItemInterface[] $stockItems
 * @return int
 * @throws \Magento\Framework\Exception\NoSuchEntityException
 */
public function updateStockItems(\Magento\CatalogInventory\Api\Data\StockItemInterface[] $stockItems);

Your method implementation:

/**
 * 
 * @param \Magento\CatalogInventory\Api\Data\StockItemInterface[] $stockItems
 * @return int
 * @throws \Magento\Framework\Exception\NoSuchEntityException
 */
public function updateStockItems(\Magento\CatalogInventory\Api\Data\StockItemInterface[] $stockItems)
{
    foreach ($stockItems as $stockItem){
        //do whatever with your stock item
    }
};

Please take care to use only parameter in your JSON objects which match the used interfaces, in this example \Magento\CatalogInventory\Api\Data\StockItemInterface. So putting there some key sku doesn't make sense and should either be ignored by Magento or give you an error in the API call.

Here is the documentation about the usage of custom webservices.

https://devdocs.magento.com/guides/v2.3/extension-dev-guide/service-contracts/service-to-web-service.html

1
  • Well I did have the intention to hack one of the core files, but since I've been called out now, I guess I'll do it the right way and make a module.
    – Ben Rubin
    Commented Mar 7, 2019 at 13:50
1

The rest API address you are using seems not correct. Have a look at this page, under the cataloginventory section:

https://devdocs.magento.com/guides/v2.3/rest/list.html#cataloginventory

As you can see the available URLs are different from the one you are using.

The correct one you should be using is this one:

PUT    /V1/products/:productSku/stockItems/:itemId

And you can update one stock at a time, so you need to call the API for each product you want to update.

3
  • 1
    The API address I'm using is one I created (see my webapi.xml). I'll ultimately be updating hundreds or thousands of items, so I'm trying to do it as a single request, rather than issuing a thousand requests, to cut down on overhead.
    – Ben Rubin
    Commented Mar 6, 2019 at 21:06
  • Please check the webapi.xml in this example, it is a little different from yours: inchoo.net/magento-2/magento-2-custom-api. The same is here: thirdandgrove.com/creating-custom-rest-api-magento2 Commented Mar 6, 2019 at 21:12
  • Do you mean the <?xml> and <routes> tags? I have those in my actual webapi file. That part in my question is just an excerpt. I think my webapi file is OK because I can change the type of the parameter in my updateStockItems method and I get different errors, so Magento is finding the route correctly.
    – Ben Rubin
    Commented Mar 6, 2019 at 21:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.