Magento2 How to create a custom rest API


Today we will talk about creating a custom REST API for your magento store. Before proceeding we assume you have already created a module and familiar with the magento basics.
Let us begin by creating an interface Vendor\Module\Api\CustomApiInterface.php and add a method getAllPosts() to it.
<?php
namespace Vendor\Module\Api;
/**
* Custom Api Interface
*/
interface CustomApiInterface
{
/**
* Get All Posts.
*
* @return array
*/
public function getAllPosts(): array;
}
Now create CustomApi Model class implementing the CustomApiInterface: Vendor\Module\Model\CustomApi.php
<?php
namespace Vendor\Module\Model;
/**
* Custom Api Model.
*/
class CustomApi implements \Vendor\Module\Api\CustomApiInterface
{
/**
* @inheritDoc
*/
public function getAllPosts(): array
{
return [
[
"id" => 1,
"title" => "My Post 1",
"categories" => ["my posts", "custom posts"],
"description" => "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
],
[
"id" => 2,
"title" => __("My Post 2"),
"categories" => ["my posts", "custom post2"],
"description" => "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
],
];
}
}
Now we need to define the preference using di.xml: Vendor\Module\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="Vendor\Module\Api\CustomApiInterface" type="Vendor\Module\Model\CustomApi" />
</config>
Now our final step will be creating webapi.xml, where we will define our webservice and declare a url to it. Vendor\Module\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 method="GET" url="/V1/custom-api/posts">
<service class="Vendor\Module\Api\CustomApiInterface" method="getAllPosts"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
</routes>
The route url will be our path to access the api. Now try accessing it with {base_url}/rest/V1/custom-api/posts. It will list all your posts.
[
{
"id": 1,
"title": "My Post 1",
"categories": [
"my posts",
"custom posts"
],
"description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
},
{
"id": 2,
"title": "My Post 2",
"categories": [
"my posts",
"custom post2"
],
"description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
}
]
Let us get a single post using an id parameter in our request. Declare a new method to the interface and define it inside the model.
{
...
/**
* Get a post by id
*
* @param int $id
* @return array
*/
public function getPost(int $id): array;
...
}
You should add PHPDoc annotations in order to follow the DocBlock standards. Read here more about DocBlock standards
Add getPost(int $id) definition inside Vendor\Module\Model\CustomApi.php
{
...
public function getPost(int $id): array
{
$allposts = $this->getAllPosts();
$post = [];
foreach ($allposts as $item) {
if ($id == $item['id']) {
$post[] = $item;
break;
}
}
return $post;
}
...
}
Now add the post route inside Vendor/Module/etc/webapi.xml
...
<route method="GET" url="/V1/custom-api/post/:id">
<service class="Vendor\Module\Api\CustomApiInterface" method="getPost"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
...
According to the route url we are specifying id with colon(:) which shows that it is a required parameter and must match with the method parameter. Now the request looks like this:
{base_url}/rest/V1/custom-api/post/1
Here 1 is the value of id parameter. If this value is not provided in request, the url will not match any route.
Below is the output to our new request:
We can also change the method type from GET to POST. We usually require POST method to send form input.
Now add a new route using Post method for same service method Vendor/Module/etc/webapi.xml:
...
<route method="POST" url="/V1/custom-api/get-post/:id">
<service class="Vendor\Module\Api\CustomApiInterface" method="getPost"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
...
If we try requesting {base_url}/rest/V1/custom-api/get-post/1 using GET or directly from browser, a no route error will be returned by api.
So Let us change GET to POST and retry request, we will get the correct results.
The output will be:










