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: