How to Create Custom API and Use CRUD Operations in Magento 2

Creating a custom API and utilizing REST API for tax zones and rates CRUD operations in Magento 2 involves defining a set of functions to perform HTTP requests and responses. A custom REST API is created to manage custom data and fields. 

An API, or Application Programming Interface, acts as a middleman between a programmer and an application, allowing access to data. In Magento 2, default APIs are available, but one must create custom APIs or specific functionalities or data requirements beyond the default offerings. 

This article will cover different methods such as getTaxRates, updateTaxRate, deleteTaxRate, insertTaxRate, and loadTaxRateById, as well as different API request methods like GET, PUT, DELETE, and POST. 

Step-by-Step Guide to Create Custom API in Magento 2

Here are the steps to Create a Custom REST API in Magento 2: 

Step 1

Create a “registration.php”

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

Step 2

Create a “Module.xml” file and the file path app/code/Dckap/AlphanumericTax/etc/module.xml

<?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="Dckap_AlphanumericTax" setup_version="1.0.3">
       <sequence>
           <module name="Magento_Tax"/>
       </sequence>
   </module>   
</config>

Step 3

Now, create one more file “webapi.xml” and file path that has
app/code/Dckap/AlphanumericTax/etc/webapi.xml

<!-- tax rate api -->
   <route url="/V1/taxrates/get" method="GET">
       <service class="Dckap\AlphanumericTax\Api\TaxRateManagementInterface" method="getTaxRates"/>
       <resources>
           <resource ref="Magento_Tax::manage_tax"/>
       </resources>
   </route>
   <route url="/V1/taxrates/update/" method="PUT">
       <service class="Dckap\AlphanumericTax\Api\TaxRateManagementInterface" method="updateTaxRate"/>
       <resources>
           <resource ref="Magento_Tax::manage_tax"/>
       </resources>
   </route>
   <route url="/V1/taxrates/delete/:taxRateId" method="DELETE">
       <service class="Dckap\AlphanumericTax\Api\TaxRateManagementInterface" method="deleteTaxRate"/>
       <resources>
           <resource ref="Magento_Tax::manage_tax"/>
       </resources>
   </route>
   <route url="/V1/taxrates/insert" method="POST">
       <service class="Dckap\AlphanumericTax\Api\TaxRateManagementInterface" method="insertTaxRate"/>
       <resources>
           <resource ref="Magento_Tax::manage_tax"/>
       </resources>
   </route>
   <route url="/V1/taxrates/load/:taxRateId" method="GET">
       <service class="Dckap\AlphanumericTax\Api\TaxRateManagementInterface" method="loadTaxRateById"/>
       <resources>
           <resource ref="Magento_Tax::manage_tax"/>
       </resources>
   </route>




</routes>

Step 4

Create “di.xml” file and file path has and the file path: 

app/code/Dckap/AlphanumericTax/etc/di.xml

<?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="Dckap\AlphanumericTax\Api\TaxRateManagementInterface" type="Dckap\AlphanumericTax\Model\Api\TaxRateManagement"/>


</config>

Step 5

Then create TaxRateManagementInterface.php and the file path: 

app/code/Dckap/AlphanumericTax/Api/TaxRateManagementInterface.php

<?php


namespace Dckap\AlphanumericTax\Api;


interface TaxRateManagementInterface
{
   /**
    * Get tax rates
    *
    * @return array
    */
   public function getTaxRates();


   /**
    * GET for Post api
    * @param string[] $title
    * @return string
    */
   public function updateTaxRate();


   /**
    * Delete tax rate by ID
    *
    * @param int $taxRateId
    * @return bool
    */
   public function deleteTaxRate($taxRateId);


   /**
   * POST for test api
   * @param string[] $data
   * @return string
   */
   public function insertTaxRate($data);


   /**
    * Load tax rate by ID
    *
    * @param int $taxRateId
    * @return array
    */
   public function loadTaxRateById($taxRateId);
}

Step 6

The last step is to create TaxRateManagement.php and file path

app/code/Dckap/AlphanumericTax/Model/Api/TaxRateManagement.php

<?php


namespace Dckap\AlphanumericTax\Model\Api;


use Dckap\AlphanumericTax\Api\TaxRateManagementInterface;
use Magento\Tax\Model\Calculation\RateFactory;
use Psr\Log\LoggerInterface;


class TaxRateManagement implements TaxRateManagementInterface
{
   /**
    * @var RateFactory
    */
   protected $rateFactory;


   /**
    * @var LoggerInterface
    */
   protected $logger;


   /**
    * TaxRateManagement constructor.
    *
    * @param RateFactory $rateFactory
    */
   public function __construct(
       RateFactory $rateFactory,
       LoggerInterface $logger


   ) {
       $this->rateFactory = $rateFactory;
       $this->logger = $logger;
   }


   /**
    * @inheritDoc
    */
   public function getTaxRates()
   {
       try {
           $taxRates = $this->rateFactory->create()->getCollection()->getData();
           return ['status' => true, 'tax_rates' => $taxRates];
       } catch (\Exception $e) {
           return ['status' => false, 'message' => $e->getMessage()];
       }
   }


      /** * GET for Post api * * @param string[] $title * @return string[] */


      public function updateTaxRate()
      {
          $edit = file_get_contents("php://input");
          $data = json_decode($edit, true);
     
          $taxRateId = $data['tax_calculation_rate_id'];
     
          $taxRate = $this->rateFactory->create()->load($taxRateId);
          $taxid = $taxRate->getData('tax_calculation_rate_id');
         
          if (in_array($taxRateId,(array)$taxid)) {
              try {


                                 $existingRate = $this->rateFactory->create()
                   ->getCollection()
                   ->addFieldToFilter('code', $data['code'])
                   ->addFieldToFilter('tax_calculation_rate_id', ['neq' => $taxRateId])
                   ->getFirstItem();


               if ($existingRate->getId()) {
                   return ['status' => false, 'message' => 'Code already exists for another tax rate.'];
               }
                   $taxRate->load($taxRateId);
                   $taxRate->setTaxCountryId($data['tax_country_id'])->save();
                   $taxRate->setTaxRegionId($data['tax_region_id'])->save();
                   $taxRate->setTaxPostcode($data['tax_postcode'])->save(); 
                   $taxRate->setCode($data['code'])->save(); 
                   $taxRate->setRate($data['rate'])->save();
                   $taxRate->setZipIsRange($data['zip_is_range'])->save(); 
                   $taxRate->setZipFrom($data['zip_from'])->save(); 
                   $taxRate->setZipTo($data['zip_to'])->save();
                   $taxRate->setTaxIdentifierLabel($data['tax_identifier_label'])->save(); 
                   
                  $response = ['status' => true, 'message' => 'Tax rate updated successfully.'];
                  return $response;
              } catch (\Exception $e) {
                  $this->logger->error('Error in updateTaxRate: ' . $e->getMessage());
                  return ['status' => false, 'message' => $e->getMessage()];
              }
          } else {
              $this->logger->info('Tax rate not found for ID: ' . $taxRateId);
     
              return ['status' => false, 'message' => 'Tax rate does not exist.'];
          }
      }




   /**
    * @inheritDoc
    */
   public function deleteTaxRate($taxRateId)
   {
       try {
           $taxRate = $this->rateFactory->create()->load($taxRateId);
           if (!$taxRate->getId()) {
               return ['status' => false, 'message' => 'Tax rate not found.'];
           }


           $taxRate->delete();
           return ['status' => true, 'message' => 'Tax rate deleted successfully.'];
       } catch (\Exception $e) {
           return ['status' => false, 'message' => $e->getMessage()];
       }
   }




   /**
    * @inheritDoc
    */
   public function insertTaxRate($data)
   {


       try {
           $taxRate = $this->rateFactory->create();


           $taxRate->setTaxCountryId(!empty($data["tax_country_id"]) ? $data["tax_country_id"] : 'default_country_id');
           $taxRate->setTaxRegionId($data["tax_region_id"]);
           $taxRate->setTaxPostcode($data["tax_postcode"]);
           $taxRate->setCode($data["code"]);
           $taxRate->setRate($data["rate"]);
           $taxRate->setZipIsRange($data["zip_is_range"]);
           $taxRate->setZipFrom($data["zip_from"]);
           $taxRate->setZipTo($data["zip_to"]);
           $taxRate->setTaxIdentifierLabel($data["tax_identifier_label"]);


           $taxRate->save();


           $response = ['status' => true, 'message' => 'Tax rate inserted successfully.'];


           return $response;
       } catch (\Exception $e) {
           $this->logger->error('Error in insertTaxRate: ' . $e->getMessage());
           return ['status' => false, 'message' => $e->getMessage()];
       }




   }




   /**
    * @inheritDoc
    */
   public function loadTaxRateById($taxRateId)
   {
       try {
           $taxRate = $this->rateFactory->create()->load($taxRateId);


           if (!$taxRate->getId()) {
               return ['status' => false, 'message' => 'Tax rate not found.'];
           }


           return ['status' => true, 'tax_rate' => $taxRate->getData()];
       } catch (\Exception $e) {
           return ['status' => false, 'message' => $e->getMessage()];
       }
   }


}

4 API Methods Using POSTMAN

Afterward, we can use POSTMAN to send requests and receive responses. We can try each of the four methods individually, including GET, POST, PUT, and DELETE, to interact with the API and observe the corresponding responses.

getTaxRates – In this method, we can get all data for the tax-rated grid by using this API

1. Method: GET

Request: http://localhost/stenvens.com/rest/V1/taxrates/get

Output:

updateTaxRate – update the data by IDs and tax_calculation_rate_id is needed 

2. Method: PUT

Request:http://localhost/stenvens.com/rest/V1/taxrates/update/

Payload:

{

    “tax_calculation_rate_id”: “3”,

    “tax_country_id”: “CA”,

    “tax_region_id”: “0”,

    “tax_postcode”: “M0A 0A0-M9Z 9Z9”,

    “code”: “testing2222222”,

    “rate”: “15.0000”,

    “zip_is_range”: “1”,

    “zip_from”: “M0A 0A0”,

    “zip_to”: “M9Z 9Z9”,

    “tax_identifier_label”: “SK”

}

Output:

deleteTaxRate  – we need to remove the data by tax_calculation_rate_id

3. Method: DELETE

Request: http://localhost/stenvens.com/rest/V1/taxrates/delete/8

Output:

insertTaxRate   – we need to insert data by payload data in the grid 

4. Method: POST

Request:http://localhost/stenvens.com/rest/V1/taxrates/insert

Payload:

{

    "data":{

    "tax_calculation_rate_id": "164",

    "tax_country_id": "CA",

    "tax_region_id": "0",

    "tax_postcode": "M0A 0A0-M9Z 9Z9",

    "code": "testing",

    "rate": "13.0000",

    "zip_is_range": "1",

    "zip_from": "M0A 0A0",

    "zip_to": "M9Z 9Z9",

    "tax_identifier_label": "ON-HST"

    }

}

Output:


loadTaxRateById – we need to load the data by tax_calculation_rate_id

Method: GET

Request: http://localhost/stenvens.com/rest/V1/taxrates/load/7

Output:

You have successfully Implemented Custom Rest API in Magento 2 and you can also customize this code according to your need for fetching data using REST API.

Magento 2 REST API Authentication and User Access Levels

1. In Magento 2, you can access both frontend and backend functionalities by calling REST API endpoints. These requests use three types of authentication:

  • Token-Based Authentication: Uses tokens generated using a username and password to authenticate the requests.
  • Session-Based Authentication: Uses a Session ID generated by the server for request authentication.
  • OAuth-Based Authentication: Uses Authorization Tokens to validate the API requests.

Magento 2 REST API endpoints can also be categorized based on the type of user:

  • Guest User: Public API endpoints that require no authentication. (For example, get product information)
  • Admin User: Private API endpoints that require admin-level access. (For example, change product information)
  • Customer: Private API endpoints that require customer-level access. (For example, view previous orders)

Advantages of Rest API

  • Allows for real-time data access, enabling you to provide up-to-date 
  • Is easy to use and understand, with a simple and consistent interface that makes it easy to work with.
  • REST API allows for easy integration with third-party systems, making it easier to scale your business
  • Magento 2 is secure, with built-in authentication and authorization mechanisms, ensuring that only authorized users can access the data.
  • Magento 2 allows you to easily integrate with third-party services, such as payment gateways, shipping providers, and more.

Disadvantages of Rest API

  • We need to pass the data properly or we can face issues with the request and response.
  • We must follow the endpoint steps, as some APIs accept both labels and numbers, while others do not.
  • Implementing and managing a REST API can be complex, especially for developers who are not familiar with the technology.
  • If your application relies heavily on third-party services, any issues with those services can impact the functionality of your application.
  • Some APIs may have rate limits, which can restrict the number of requests that can be made within a certain period.

Conclusion

In this blog post, we have developed and implemented a custom API for managing tax zones and rates in Magento 2. Additionally, we have explored and discussed several default APIs by Magento, such as those for products, customers, and categories. 

You can create, update, and retrieve data using these APIs by following the step-by-step instructions given above. Furthermore, we have demonstrated how to use tools like Postman to send requests and receive responses, ensuring that your APIs are functioning as expected. By understanding these concepts, you can utilize the APIs in Magento 2 to streamline your ecommerce operations and enhance the overall user experience.

About The Author

We take the guesswork out of ecommerce.
Schedule a consultation call today