In my case Magento2 delivers to another CMS-System Product Informations via REST API. The CMS-System caches an downsized image in another caching system. This works, but if there are to many images after clearing cache, the system comes to it's limits.
Is there a way to get directly the cached thumbnail image from the catalog view from an API call?
e.g. /pub/media/catalog/product/cache/f073062f50e48eb0f0998593e568d857/9/7/9783532624999.png
Is this only possible with a new module extending the API? But how?
Thank for your help,
Martin
$requestUrl=$restbase.'/rest/V1/products/'.$sku;
[media_gallery_entries] => Array ( [0] => stdClass Object ( [id] => 321 [media_type] => image [label] => [position] => [disabled] => [types] => Array ( ) [file] => /9/7/9783532624999.png ) [1] => stdClass Object ( [id] => 739 [media_type] => image [label] => [position] => [disabled] => [types] => Array ( ) [file] => /9/7/9783532624999.jpg ) [2] => stdClass Object ( [id] => 740 [media_type] => image [label] => [position] => [disabled] => [types] => Array ( ) [file] => /9/7/9783532624999_1.jpg ) [3] => stdClass Object ( [id] => 974 [media_type] => image [label] => [position] => [disabled] => [types] => Array ( ) [file] => /9/7/9783532624999_1.png ) )
Hello typotraum
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 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); }
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/placeholder/.jpg'
hope it will help you, if works then mark as solution.
Thank you prakash for your fast answer!
Is it right, that the class ProductRepository has to implement the ProductRepositoryInterface previously declared instead of the \Magento\Catalog\Api\ProductRepositoryInterface?
class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterface
should be
class ProductRepository implements \Vendorname\TheNewModule\Api\ProductRepositoryInterface
? Right?
When I call the new webapi route, the response is
Request does not match any route.
Probably there are other reasons for that error. I will research.
MyVendorName └── ThumbnailApi ├── Api │ └── ProductRepositoryInterface.php ├── etc │ ├── di.xml │ ├── module.xml │ └── webapi.xml ├── Model │ └── ProductRepository.php └── registration.php