Magento 2 : How to create custom API?

how to create customer API in Magento 2
Today we are going to focus on creating custom web API in Magento 2 using our simple step by step guide. These web APIs allows third party systems like ERP, CRM, POS etc to integrate and pull data directly from Magento 2 as it gives the output in well known formats like REST and SOAP. This also helps in creating your Magento 2 frontend headless because this way you will have all the APIs available to fetch data from Magento 2 so it doesn’t matter whether you use REACT, ANGULAR, KNOCKOUT or any other javascript framework.

Before doing more talking, lets crack on with creating our first custom Magento 2 web API using our step by step approach.

Step 1 – Create webapi.xml under your custom module \Scommerce\Custom\etc\

<route url="/V1/custom/:categoryId/products" method="GET">
    <service class="Scommerce\Custom\Api\CategoryLinkManagementInterface" method="getAssignedProducts" />
    <resources>
        <resource ref="self"/>
    </resources>
</route>

Let us walk you through with the above code to make you understand what’s happening behind the scene -:

– Route – This is the URL which will be used to call our API https://{{MagentoBaseURL}}/index.php/rest/V1/custom/{{categoryId}}/products

– Service Class – This is the interface class of our API and the main method “getAssignedProducts” will be called with {{categoryId}} as the parameter

– Resources- This defines who has the permission to call this API. It could be anonymous (everyone) or self (customer) or specific admin user with specific permission for example Scommerce_Custom::custom which can be added in acl.xml

Step 2 – Lets now create the main interface file for our web API CategoryLinkManagementInterface.php under Scommerce\Custom\Api\ as specified in webapi.xml in Step 1

namespace Scommerce\Custom\Api;

/**
 * @api
 */
interface CategoryLinkManagementInterface
{
    /**
     * Get products assigned to a category
     *
     * @param int $categoryId
     * @return \Scommerce\Custom\Api\Data\CategoryProductLinkInterface[]
     */
    public function getAssignedProducts($categoryId);
}

In the above code, we have created an interface and define the main method i.e. getAssignedProducts as specified in webapi.xml in Step 1. The other thing to notice here is the@return parameter which is the data interface \Scommerce\Custom\Api\Data\CategoryProductLinkInterface[]. Will explain what is data interface in our next step.

Step 3 – Based on the return parameter in Step 2, let’s create our data interface CategoryProductLinkInterface.php under \Scommerce\Custom\Api\Data\

namespace Scommerce\Custom\Api\Data;

/**
 * @api
 */
interface CategoryProductLinkInterface
{
    /**
     * @return string|null
     */
    public function getSku();

    /**
     * @param string $sku
     * @return $this
     */
    public function setSku($sku);

    /**
     * @return string|null
     */
    public function getName();

    /**
     * @param string $name
     * @return $this
     */
    public function setName($name);

    /**
     * @return float|null
     */
    public function getPrice();

    /**
     * @param float $price
     * @return $this
     */
    public function setPrice($price);

    /**
     * @return int|null
     */
    public function getPosition();

    /**
     * @param int $position
     * @return $this
     */
    public function setPosition($position);

    /**
     * @return string|null
     */
    public function getCategoryDescription();

    /**
     * @param string $description
     * @return $this
     */
    public function setCategoryDescription($description);
}

The above data interface class allows you define the response/output of our API request, so as you can see this API will return sku, name, price, position and category description as an output.

Step 4 – Now our interface files are created, let’s create our model classes where we can put the actual business logic, to do so we would need to specify this in our di.xml file under \Scommerce\Custom\etc\

<config ...>
    <preference for="Scommerce\Custom\Api\CategoryLinkManagementInterface" type="Scommerce\Custom\Model\CategoryLinkManagement" />
    <preference for="Scommerce\Custom\Api\Data\CategoryProductLinkInterface" type="Scommerce\Custom\Model\CategoryProductLink" />
</config>

In the above step, we have specified which model classes will be created against our interfaces to add our business logic.

Step 5 – Let’s create our first model class CategoryLinkManagement.php under Scommerce\Custom\Model\ as specified in di.xml

namespace Scommerce\Custom\Model;

/**
 * Class CategoryLinkManagement
 */
class CategoryLinkManagement implements \Scommerce\Custom\Api\CategoryLinkManagementInterface
{
    /**
     * @var \Magento\Catalog\Api\CategoryRepositoryInterface
     */
    protected $categoryRepository;

    /**
     * @var \Scommerce\Custom\Api\Data\CategoryProductLinkInterfaceFactory
     */
    protected $productLinkFactory;

    /**
     * CategoryLinkManagement constructor.
     *
     * @param \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository
     * @param \Scommerce\Custom\Api\Data\CategoryProductLinkInterfaceFactory $productLinkFactory
     */
    public function __construct(
        \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository,
        \Scommerce\Custom\Api\Data\CategoryProductLinkInterfaceFactory $productLinkFactory
    ) {
        $this->categoryRepository = $categoryRepository;
        $this->productLinkFactory = $productLinkFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function getAssignedProducts($categoryId)
    {
        $category = $this->categoryRepository->get($categoryId);
        if (!$category->getIsActive()) {
            return [[
                'error' => true,
                'error_desc' => 'Category is disabled'
            ]];
        }
        $categoryDesc = $category->getDescription();

        /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $products */
        $products = $category->getProductCollection()
            ->addFieldToSelect('position')
            ->addFieldToSelect('name')
            ->addFieldToSelect('price');

        /** @var \Scommerce\Custom\Api\Data\CategoryProductLinkInterface[] $links */
        $links = [];

        /** @var \Magento\Catalog\Model\Product $product */
        foreach ($products->getItems() as $product) {
            /** @var \Scommerce\Custom\Api\Data\CategoryProductLinkInterface $link */
            $link = $this->productLinkFactory->create();
            $link->setSku($product->getSku())
                ->setName($product->getName())
                ->setPrice($product->getFinalPrice())
                ->setPosition($product->getData('cat_index_position'))
                ->setCategoryDescription($categoryDesc);
            $links[] = $link;
        }

        return $links;
    }
}

Step 6 – Lets now create our second model class CategoryProductLink.php under Scommerce\Custom\Model\ as specified in di.xml

namespace Scommerce\Custom\Model;

/**
 * @codeCoverageIgnore
 */
class CategoryProductLink implements \Scommerce\Custom\Api\Data\CategoryProductLinkInterface
{
    /**#@+
     * Constant for confirmation status
     */
    const KEY_SKU                   = 'sku';
    const KEY_NAME                  = 'name';
    const KEY_PRICE                 = 'price';
    const KEY_CATEGORY_DESC         = 'category_description';
    const KEY_POSITION              = 'position';
    /**#@-*/

    /**
     * {@inheritdoc}
     */
    public function getSku()
    {
        return $this->_get(self::KEY_SKU);
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return $this->_get(self::KEY_NAME);
    }

    /**
     * {@inheritdoc}
     */
    public function getPosition()
    {
        return $this->_get(self::KEY_POSITION);
    }

    /**
     * {@inheritdoc}
     */
    public function getPrice()
    {
        return $this->_get(self::KEY_PRICE);
    }

    /**
     * {@inheritdoc}
     */
    public function getCategoryDescription()
    {
        return $this->_get(self::KEY_CATEGORY_DESC);
    }

    /**
     * @param string $sku
     * @return $this
     */
    public function setSku($sku)
    {
        return $this->setData(self::KEY_SKU, $sku);
    }

    /**
     * @param string $name
     * @return $this
     */
    public function setName($name)
    {
        return $this->setData(self::KEY_NAME, $name);
    }

    /**
     * @param int $position
     * @return $this
     */
    public function setPosition($position)
    {
        return $this->setData(self::KEY_POSITION, $position);
    }

    /**
     * @param float $price
     * @return $this
     */
    public function setPrice($price)
    {
        return $this->setData(self::KEY_PRICE, $price);
    }

    /**
     * @param string $description
     * @return $this
     */
    public function setCategoryDescription($description)
    {
        return $this->setData(self::KEY_CATEGORY_DESC, $description);
    }

}

The above will allow us to call our first Magento 2 web API using the customer token. To retrieve admin or custom token, please have a look at Magento official token retrieval documentation

That’s it, Hope this article helped you in some way. Please leave us your comment and let us know what do you think? Thanks.

Scommerce

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.