How to Create Custom REST API in Magento 2

Magento 2 Create API means helping online retailers generate an Application Programming Interface for the own using. The API is a set of routines, protocols and other tools to design software applications. Thus, API is a required element to connect among the data if you ask for any program or service from other websites. With the creation of API in Magento 2, you can easily get all building blocks to initiate a program successfully.

To support better in Magento 2 module development, Mageplaza team attempts to build API tester in your hello world module of Magento 2 module development series. http://<magento_host>/swagger

Magento API Integration Service by Mageplaza

Connect your store with any 3rd-party software and boost customer experience quickly and efficiently.

Learn more
Magento API Integration service

What is API in Magento 2?

API stands for Application Programming Interface to allow you access the data from an application. API can be called as a middleman between a programmer and an application. When the programmer calls for a request via the middleman, if the request is approved, the right data will be turned back.

As eCommerce stores basing on Magento 2 platform, you should look at two architectural kinds of the web APIs: REST (Representational State Transfer) and SOAP (Simple Object Access Protocol). However, in the official documentation, they only come with raw curl request without any example. In order to connect and use Magento 2 API effectively, this topic will show you PHP examples in specific.

How to create custom REST API in Magento 2 | Detailed guide

Step 1: A custom module creation

Start by creating a custom module. In this example, we’ll use the namespace Dev_RestApi. Create the module.xml and registration.php files within your module directory app/code/Dev/RestApi. The module.xml file defines your module and its dependencies.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
   <module name="Dev_RestApi">
       <sequence>
           <module name="Magento_Webapi" />
           <module name="Magento_Catalog" />
       </sequence>
   </module>
</config>

The registration.php file app/code/Dev/RestApi/registration.php registers your module:

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
   \Magento\Framework\Component\ComponentRegistrar::MODULE,
   'Dev_RestApi',
   __DIR__
);

Step 2: Custom ACL entrie creation

Generate Access Control List (ACL) rules that control who can access specific endpoints. Define ACL entries in app/code/Dev/RestApi/etc/acl.xml.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
   <acl>
       <resources>
           <resource id="Magento_Backend::admin">
               <resource id="Dev_RestApi::products" title="Dev API - Products"
                         translate="title" sortOrder="110">
                   <resource id="Dev_RestApi::products_get" title="Get product"
                             translate="title" sortOrder="10" />
                   <resource id="Dev_RestApi::products_set_description" title="Set description"
                             translate="title" sortOrder="20" />
               </resource>
           </resource>
       </resources>
   </acl>
</config>

Step 3: Custom endpoints definition

To define endpoints, configure a web API service in app/code/Dev/RestApi/etc/webapi.xml

<?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/rest_dev/getProduct/:id" method="GET">
        <service class="Dev\RestApi\Api\ProductRepositoryInterface" method="getItem" />
        <resources>
            <resource ref="Dev_RestApi::products_get" />
        </resources>
    </route>
    <route url="/V1/rest_dev/setDescription" method="PUT">
        <service class="Dev\RestApi\Api\ProductRepositoryInterface" method="setDescription" />
        <resources>
            <resource ref="Dev_RestApi::products_set_description" />
        </resources>
    </route>
</routes>

Where to show: The URL for this endpoint would be <domain>/rest/<store_code>/V1/rest_dev/getProduct/:id. The method determines the request type (GET, POST, PUT, DELETE). The service class and method define the interface to be called when the endpoint is reached. ACL resources can be set using tags.

Step 4: Di.xml creation

Create a di.xml file in app/code/Dev/RestApi/etc/di.xml for interface configuration.

<?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="Dev\RestApi\Api\ProductRepositoryInterface" type="Dev\RestApi\Model\Api\ProductRepository"/>
    <preference for="Dev\RestApi\Api\RequestItemInterface" type="Dev\RestApi\Model\Api\RequestItem"/>
    <preference for="Dev\RestApi\Api\ResponseItemInterface" type="Dev\RestApi\Model\Api\ResponseItem"/>
</config>

Step 5: Interfaces creation

Define interfaces for requests and responses. Example interface for requests in app/code/Dev/RestApi/Api/RequestItemInterface.php

<?php
namespace Dev\RestApi\Api;
interface RequestItemInterface
{
    const DATA_ID = 'id';
    const DATA_DESCRIPTION = 'description';
    /**
     * @return int
     */
    public function getId();
    /**
     * @return string
     */
    public function getDescription();
    /**
     * @param int $id
     * @return $this
     */
    public function setId(int $id);
    /**
     * @param string $description
     * @return $this
     */
    public function setDescription(string $description);
}

Example interface for responses in app/code/Dev/RestApi/Api/ResponseItemInterface.php.

<?php
namespace Dev\RestApi\Api;
interface ResponseItemInterface
{
    const DATA_ID = 'id';
    const DATA_SKU = 'sku';
    const DATA_NAME = 'name';
    const DATA_DESCRIPTION = 'description';
    /**
     * @return int
     */
    public function getId();
    /**
     * @return string
     */
    public function getSku();
    /**
     * @return string
     */
    public function getName();
    /**
     * @return string|null
     */
    public function getDescription();
    /**
     * @param int $id
     * @return $this
     */
    public function setId(int $id);
    /**
     * @param string $sku
     * @return $this
     */
    public function setSku(string $sku);
    /**
     * @param string $name
     * @return $this
     */
    public function setName(string $name);
    /**
     * @param string $description
     * @return $this
     */
    public function setDescription(string $description);
}

Establish the “ProductRepositoryInterface” within the designated file path “app/code/Dev/RestApi/Api/ProductRepositoryInterface.php”.

<?php
namespace Dev\RestApi\Api;
interface ProductRepositoryInterface
{
    /**
     * Return a filtered product.
     *
     * @param int $id
     * @return \Dev\RestApi\Api\ResponseItemInterface
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function getItem(int $id);
    /**
     * Set descriptions for the products.
     *
     * @param \Dev\RestApi\Api\RequestItemInterface[] $products
     * @return void
     */
    public function setDescription(array $products);
}

Step 6. Models creation

Models serve the function of defining classes that adhere to interfaces and effectively managing data. In this example, we’ve created models for requesting, responding to, and processing data. Each model includes two methods: getItem, which retrieves product details depending on a given product ID, and setDescription, which updates the product description. app/code/Dev/RestApi/Model/Api/RequestItem.php:

<?php
namespace Dev\RestApi\Model\Api;
use Dev\RestApi\Api\RequestItemInterface;
use Magento\Framework\DataObject;
/**
 * Class RequestItem
 */
class RequestItem extends DataObject implements RequestItemInterface
{
    public function getId() : int
    {
        return $this->_getData(self::DATA_ID);
    }
    public function getDescription() : string
    {
        return $this->_getData(self::DATA_DESCRIPTION);
    }
    /**
     * @param int $id
     * @return $this
     */
    public function setId(int $id) : mixed
    {
        return $this->setData(self::DATA_ID, $id);
    }
    /**
     * @param string $description
     * @return $this
     */
    public function setDescription(string $description) : mixed
    {
        return $this->setData(self::DATA_DESCRIPTION, $description);
    }
}

app/code/Dev/RestApi/Model/Api/ResponseItem.php:

<?php
namespace Dev\RestApi\Model\Api;
use Dev\RestApi\Api\ResponseItemInterface;
use Magento\Framework\DataObject;
/**
 * Class ResponseItem
 */
class ResponseItem extends DataObject implements ResponseItemInterface
{
    public function getId() : int
    {
        return $this->_getData(self::DATA_ID);
    }
    public function getSku() : string
    {
        return $this->_getData(self::DATA_SKU);
    }
    public function getName() : string
    {
        return $this->_getData(self::DATA_NAME);
    }
    public function getDescription() : string
    {
        return $this->_getData(self::DATA_DESCRIPTION);
    }
    /**
     * @param int $id
     * @return $this
     */
    public function setId(int $id) : mixed
    {
        return $this->setData(self::DATA_ID, $id);
    }
    /**
     * @param string $sku
     * @return $this
     */
    public function setSku(string $sku) : mixed
    {
        return $this->setData(self::DATA_SKU, $sku);
    }
    /**
     * @param string $name
     * @return $this
     */
    public function setName(string $name) : mixed
    {
        return $this->setData(self::DATA_NAME, $name);
    }
    /**
     * @param string $description
     * @return $this
     */
    public function setDescription(string $description) : mixed
    {
        return $this->setData(self::DATA_DESCRIPTION, $description);
    }
}

app/code/Dev/RestApi/Model/Api/ProductRepository.php:

<?php
namespace Dev\RestApi\Model\Api;
use Dev\RestApi\Api\ProductRepositoryInterface;
use Dev\RestApi\Api\RequestItemInterfaceFactory;
use Dev\RestApi\Api\ResponseItemInterfaceFactory;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\ResourceModel\Product\Action;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Store\Model\StoreManagerInterface;
/**
 * Class ProductRepository
 */
class ProductRepository implements ProductRepositoryInterface
{
    /**
     * @var Action
     */
    private $productAction;
    /**
     * @var CollectionFactory
     */
    private $productCollectionFactory;
    /**
     * @var RequestItemInterfaceFactory
     */
    private $requestItemFactory;
    /**
     * @var ResponseItemInterfaceFactory
     */
    private $responseItemFactory;
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;
    /**
     * @param Action $productAction
     * @param CollectionFactory $productCollectionFactory
     * @param RequestItemInterfaceFactory $requestItemFactory
     * @param ResponseItemInterfaceFactory $responseItemFactory
     * @param StoreManagerInterface $storeManager
     */
    public function __construct(
        Action $productAction,
        CollectionFactory $productCollectionFactory,
        RequestItemInterfaceFactory $requestItemFactory,
        ResponseItemInterfaceFactory $responseItemFactory,
        StoreManagerInterface $storeManager
    ) {
        $this->productAction = $productAction;
        $this->productCollectionFactory = $productCollectionFactory;
        $this->requestItemFactory = $requestItemFactory;
        $this->responseItemFactory = $responseItemFactory;
        $this->storeManager = $storeManager;
    }
    /**
     * {@inheritDoc}
     *
     * @param int $id
     * @return ResponseItemInterface
     * @throws NoSuchEntityException
     */
    public function getItem(int $id) : mixed
    {
        $collection = $this->getProductCollection()
            ->addAttributeToFilter('entity_id', ['eq' => $id]);
        /** @var ProductInterface $product */
        $product = $collection->getFirstItem();
        if (!$product->getId()) {
            throw new NoSuchEntityException(__('Product not found'));
        }
        return $this->getResponseItemFromProduct($product);
    }
    /**
     * {@inheritDoc}
     *
     * @param RequestItemInterface[] $products
     * @return void
     */
    public function setDescription(array $products) : void
    {
        foreach ($products as $product) {
            $this->setDescriptionForProduct(
                $product->getId(),
                $product->getDescription()
            );
        }
    }
    /**
     * @return Collection
     */
    private function getProductCollection() : mixed
    {
        /** @var Collection $collection */
        $collection = $this->productCollectionFactory->create();
        $collection
            ->addAttributeToSelect(
                [
                    'entity_id',
                    ProductInterface::SKU,
                    ProductInterface::NAME,
                    'description'
                ],
                'left'
            );
        return $collection;
    }
    /**
     * @param ProductInterface $product
     * @return ResponseItemInterface
     */
    private function getResponseItemFromProduct(ProductInterface $product) : mixed
    {
        /** @var ResponseItemInterface $responseItem */
        $responseItem = $this->responseItemFactory->create();
        $responseItem->setId($product->getId())
            ->setSku($product->getSku())
            ->setName($product->getName())
            ->setDescription($product->getDescription());
        return $responseItem;
    }
    /**
     * Set the description for the product.
     *
     * @param int $id
     * @param string $description
     * @return void
     */
    private function setDescriptionForProduct(int $id, string $description) : void
    {
        $this->productAction->updateAttributes(
            [$id],
            ['description' => $description],
            $this->storeManager->getStore()->getId()
        );
    }
}

To implement changes, update .xml files, and constructors, or add new classes, run bin/magento setup:upgrade or bin/magento setup:di:compile from the Adobe Commerce or Magento Open Source directory.

Step 7: Custom endpoint testing

Use any REST client (e.g., Postman) to send calls to your custom API. Obtain an admin authorization token (required for all calls). Test your endpoints to ensure they work as expected.

GET endpoint testing

This example demonstrates the usage of sample data associated with product ID 1, retrievable from the endpoint http://local.magentoee.com/rest/V1/rest_dev/getProduct/1. Demand to test the GET endpoint: GET <domain>/rest/V1/<store_code>/rest_dev/getProduct/<product_id> Response:

{
    "id": 1,
    "sku": "24-MB01",
    "name": "Joust Duffle Bag",
    "description": "<p>The sporty Joust Duffle Bag can't be beat - not in the gym, not on the luggage carousel, not anywhere. Big enough to haul a basketball or soccer ball and some sneakers with plenty of room to spare, it's ideal for athletes with places to go.<p>\n<ul>\n<li>Dual top handles.</li>\n<li>Adjustable shoulder strap.</li>\n<li>Full-length zipper.</li>\n<li>L 29\" x W 13\" x H 11\".</li>\n</ul>"
}

The PUT endpoint testing

Demand to test the PUT endpoint:

PUT <domain>/rest/V1/<store_code>/rest_dev/setDescription

Payload:

{
   "products":[
      {
         "id":2,
         "description":"Test description"
      }
   ]
}

And the response will be:

[]

If you want to ensure the process is smooth and successful, it’s better to consider a Magento API Integration service. You’ll save a lot of time and effort, while focusing on other essential business aspects.

By using the Magento API Integration service by Mageplaza, you can:

  • Connect your store with other third-party platforms to streamline processes
  • Carry out various tasks and share data via one single dashboard
  • Eliminate manual and tedious tasks
  • Improve customer experience

To make sure you’re completely satisfied with the result, we offer free two-month support after the integration process. Our experts also lead your project from start to finish, so you don’t need to worry about anything!

Contact us for free consultations now!

CONTACT OUR API INTEGRATION EXPERTS

Related Post

Image Description
Hello, I'm the Chief Technology Officer of Mageplaza, and I am thrilled to share my story with you. My deep love and passion for technology have fueled my journey as a professional coder and an ultra-marathon runner. Over the past decade, I have accumulated extensive experience and honed my expertise in PHP development.

People also searched for

  • magento 2 create api
  • magento 2 api
  • magento 2 create api endpoint
  • magento 2 custom rest api example
  • how to create api in magento 2
  • magento 2 create rest api
  • magento 2 create custom api
  • magento 2 custom api
  • create api in magento 2
  • magento api
  • create api magento 2
  • magento 2 create custom rest api
  • magento 2 rest api
  • create rest api magento 2
  • magento 2 api tutorial
  • api in magento 2
  • api magento 2
  • magento 2 rest api example
  • create custom api in magento 2
  • magento2 api
  • rest api magento 2
  • magento 2 webapi
  • custom api in magento 2
  • magento rest api
  • magento 2 rest api post example
  • web api magento 2
  • magento 2 api example
  • rest api in magento 2
  • magento api tutorial
  • magento 2 web api
  • 2.3.x, 2.4.x
x