12

How do we get the url to thumbnail image of of a product through rest API.

/V1/products/{sku}/media would get us the relative url such as "/m/b/mb01-blue-0.jpg"

and the image url would be baseurl/catalog/product/m/b/mb01-blue-0.jpg

This works fine. But how do we get the thumbnail which usually resides in the cache folder.

  • There is no such functionality out of the box. You'll have to write custom API. – Sinisa Nedeljkovic Feb 28 '17 at 20:19
10

If you need the complete path of the thumbnail image with Magento 2 cache system through API, you can create your custom API based on the native ProductRepository class.

Create a new module. (explained in other posts)

Create a etc/webapi.xml file :

<?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
    <route url="/V1/custom/products/{sku}" method="GET">
        <service class="Vendor\ModuleName\Api\ProductRepositoryInterface" method="get"/>
        <resources>
            <resource ref="Magento_Catalog::products"/>
        </resources>
    </route>
</routes>

Create a etc/di.xml file :

<?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Vendor\ModuleName\Api\ProductRepositoryInterface" type="Vendor\ModuleName\Model\ProductRepository" />
</config>

Create your interface Api\ProductRepositoryInterface.php :

namespace Vendor\ModuleName\Api;

/**
 * @api
 */
interface ProductRepositoryInterface
{
    /**
     * Get info about product by product SKU
     *
     * @param string $sku
     * @param bool $editMode
     * @param int|null $storeId
     * @param bool $forceReload
     * @return \Magento\Catalog\Api\Data\ProductInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function get($sku, $editMode = false, $storeId = null, $forceReload = false);
}

Create your model Model\ProductRepository.php :

namespace Vendor\ModuleName\Model;


class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterface
{
    /**
     * @var \Magento\Catalog\Model\ProductFactory
     */
    protected $productFactory;

    /**
     * @var Product[]
     */
    protected $instances = [];

    /**
     * @var \Magento\Catalog\Model\ResourceModel\Product
     */
    protected $resourceModel;

    /**
     * @var \Magento\Store\Model\StoreManagerInterface
     */
    protected $storeManager;

    /**
     * @var \Magento\Catalog\Helper\ImageFactory
     */
    protected $helperFactory;

    /**
     * @var \Magento\Store\Model\App\Emulation
     */
    protected $appEmulation;

    /**
     * ProductRepository constructor.
     * @param \Magento\Catalog\Model\ProductFactory $productFactory
     * @param \Magento\Catalog\Model\ResourceModel\Product $resourceModel
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     */
    public function __construct(
        \Magento\Catalog\Model\ProductFactory $productFactory,
        \Magento\Catalog\Model\ResourceModel\Product $resourceModel,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Store\Model\App\Emulation $appEmulation,
        \Magento\Catalog\Helper\ImageFactory $helperFactory
    ) {
        $this->productFactory = $productFactory;
        $this->storeManager = $storeManager;
        $this->resourceModel = $resourceModel;
        $this->helperFactory = $helperFactory;
        $this->appEmulation = $appEmulation;
    }


    /**
     * {@inheritdoc}
     */
    public function get($sku, $editMode = false, $storeId = null, $forceReload = false)
    {
        $cacheKey = $this->getCacheKey([$editMode, $storeId]);
        if (!isset($this->instances[$sku][$cacheKey]) || $forceReload) {
            $product = $this->productFactory->create();

            $productId = $this->resourceModel->getIdBySku($sku);
            if (!$productId) {
                throw new NoSuchEntityException(__('Requested product doesn\'t exist'));
            }
            if ($editMode) {
                $product->setData('_edit_mode', true);
            }
            if ($storeId !== null) {
                $product->setData('store_id', $storeId);
            } else {
                // Start Custom code here

                $storeId = $this->storeManager->getStore()->getId();
            }
            $product->load($productId);

            $this->appEmulation->startEnvironmentEmulation($storeId, \Magento\Framework\App\Area::AREA_FRONTEND, true);

            $imageUrl = $this->getImage($product, 'product_thumbnail_image')->getUrl();

            $customAttribute = $product->setCustomAttribute('thumbnail', $imageUrl);

            $this->appEmulation->stopEnvironmentEmulation();

            // End Custom code here

            $this->instances[$sku][$cacheKey] = $product;
            $this->instancesById[$product->getId()][$cacheKey] = $product;
        }
        return $this->instances[$sku][$cacheKey];
    }

    /**
     * Retrieve product image
     *
     * @param \Magento\Catalog\Model\Product $product
     * @param string $imageId
     * @param array $attributes
     * @return \Magento\Catalog\Block\Product\Image
     */
    public function getImage($product, $imageId, $attributes = [])
    {
        $image = $this->helperFactory->create()->init($product, $imageId)
            ->constrainOnly(true)
            ->keepAspectRatio(true)
            ->keepTransparency(true)
            ->keepFrame(false)
            ->resize(75, 75);

        return $image;
    }

}

Access

Go to /rest/V1/custom/products/{sku}

You should retrieve the thumbnail image with the image frontend URL cached :

<custom_attributes>
    <item>
        <attribute_code>thumbnail</attribute_code>
        <value>http://{domain}/media/catalog/product/cache/1/thumbnail/75x75/e9c3970ab036de70892d86c6d221abfe/s/r/{imageName}.jpg</value>
    </item>
</custom_attributes>

Comments :

The third parameter of the function startEnvironmentEmulation is used to force the use of frontend area if you are already on the same storeId. (usefull for API area)

I do not test this custom API, you may adapt the code but the logic is correct but I already tested the part to retrieve the image URL in other custom API.

This workaround avoid you to have this kind of errors :

http://XXXX.com/pub/static/webapi_rest/_view/en_US/Magento_Catalog/images/product/placeholder/.jpg

Uncaught Magento\Framework\View\Asset\File\NotFoundException: Unable to resolve the source file for 'adminhtml/_view/en_US/Magento_Catalog/images/product/placeh‌​older/.jpg'
  • I think this might work better with the \Magento\Catalog\Api\ProductRepositoryInterfaceFactory instead of \Magento\Catalog\Model\ProductFactory, since you can call get() on the productRepositry object with the SKU directly. At least, that's what I'm using now. – thaddeusmt Mar 16 '17 at 20:47
  • We don't encourage to provide own ProductRepositoryInterface , because there is one provided by Catalog module. And we suppose that you will customize existing one if needed. Because ideally all the clients which dependent on Catalog's ProductRepositoryInterface should not be affected with your change. There are two possible solution for currect issue: 1. Add URL as a part of ProductInterface as extension attribute 2. Introuce dedicated URL resolver service. The first solution doesn't fit current architecture of Service contract, because this attribute should be read-only. – Igor Minyaylo Apr 24 '17 at 10:46
  • Indeed, this answer is to put in evidence a possible workaround of this issue. The best solution is to add a dedicated URL resolver service and to based on the native catalog API. – Franck Garnier Apr 24 '17 at 11:38
  • hi @franck Garnier i am getting an error as shown in this screenshot prntscr.com/g5q4ak how to solve please suggest me thanks? – Nagaraju K Aug 8 '17 at 5:40
  • You error is explicit, the function do not exist. I just give you a code example, but you need to adapt it with your needs. For example implement the getCacheKey function such as like here : vendor/magento/module-catalog/Model/ProductRepository.php:258 – Franck Garnier Aug 8 '17 at 8:35
2

The reasons why Magento doesn't provide this functionality out of the box are next:

  • To return image thumbnail URL as a part of Product with attribute or extension attribute that will mean to introduce support of Read-Only (non-modifiable) attributes in Data Objects. Because URL is a representation of some data. Data taken from different sources, as domain name belongs to system configuration, but path belongs to Catalog module.
  • For now Magento doesn't support read-only attributes or service for Query API.

As a long term solution – Query APIs should address this question, as they will provide an ability for read-only and computed fields. As a solution we could provide for community nearest time – we could implement/introduce dedicated URL resolver service which will return URL for specific entity types (like Product, Category, Image etc.)

For the same reason we don't provide Product URL as a part of ProductInterface

Here is my response devoted to this issue (Product URL): https://community.magento.com/t5/Programming-Questions/Retrieving-the-product-URL-for-the-current-store-from-a/m-p/55387/highlight/true#M1400

  • 1
    When does a such URL resolver service will be available out of the box ? – Franck Garnier Nov 2 '17 at 15:34
  • The answer is from 2017. Has this been added in Magenta 2.1.x 2.2.x or 2.3.x since then? – Marcus Wolschon Sep 13 '18 at 5:52
1

It should be possible with the following url: /rest/V1/products/{sku}

This will return the product and there should be a node for custom_attributes which contains a thumbnail link

<custom_attributes>
    <item>
        <attribute_code>thumbnail</attribute_code>
        <value>/m/b/mb01-blue-0.jpg</value>
    </item>
</custom_attributes>
  • cache/1/thumbnail/88x110/beff4985b56e3afdbeabfc89641a4582/m/b/mb02-blue-0.jpg this is the thumbnail location. is there a way to get this? – Mohammed Shameem Jul 23 '16 at 16:20
  • /V1/products/{sku}/media and /rest/V1/products/{sku} gives the same result the former gives the media alone and the later gives all the other information as well. – Mohammed Shameem Jul 23 '16 at 16:27
  • @MohammedShameem have you find any working solution? – torayeff Aug 1 '16 at 17:22
  • @torayeff not yet. I guess will have to write one. Do you have any suggessions? – Mohammed Shameem Aug 3 '16 at 9:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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