Let’s be honest. Creating an endpoint in Magento is like trying to remember the lyrics to a summer hit from 2003. You know you know it, but getting it right on the first try is impossible.
You’ve been fighting with it all morning, and your Google history looks like a cry for help (magento api endpoint example not working please help
), and you’re not having any better luck with AI. Of course, it answers with the confidence of a politician on the campaign trail: it sounds like it knows what it’s talking about, but it doesn’t have a f***ing clue.
Relax, take a breath. I’m here to give you a guide that ACTUALLY works, explained so you don’t have to sell your soul to the devil.
Today, we’re going to create:
- A private REST endpoint (a good old-fashioned POST request)
- The input and output data will be in JSON
- Accessible with customer authentication (access token) from your store (not an admin, but a registered customer—that’s a topic for another post…)
At first glance, the Magento API can look like a mythological beast made of interfaces, XMLs, and classes calling each other. But the reality is, once you get the hang of it, it’s a pretty logical process. Like assembling IKEA furniture, but with fewer leftover screws (usually).
I’ll skip the usual spiel about starting by creating a module… you already know how to do that… or I hope you do. If not, I’m not really sure what you’re doing here 😜.
Create the Interfaces. They’re a pain in the ass, but they’re your lifesaver.
Doing this is like when your mom told you to grab a jacket “just in case it gets chilly.” You really couldn’t be bothered, but then when it gets cold and you don’t have it, you freeze your ass off (though you’d never admit it to her).
And yes, I know what you’re thinking: “An interface and a class just to pass one measly string? Are we crazy?”. Trust the process. This is Magento’s black magic. Today it’s a string; tomorrow, they’ll ask for 15 more fields, and you’ll thank me. So just write them.
Define an interface for the request (in other words, for the input):
<?php
namespace Bydn\Helpdesk\Api\Ai;
interface RequestInterface {
const CONVERSATION = 'conversation';
/**
* @return string
*/
public function getConversation();
/**
* @param string $description
* @return $this
*/
public function setConversation(string $conversation);
}
And another interface for the response (the output):
<?php
namespace Bydn\Helpdesk\Api\Ai;
interface ResponseInterface {
const RESPONSE = 'response';
/**
* @return string
*/
public function getResponse();
/**
* @param string $response
* @return $this
*/
public function setResponse(string $response);
}
Now you’ll need an Interface for the “orchestra conductor,” the class that will manage the call. Logically, it will use the two interfaces you’ve just created.
<?php
namespace Bydn\Helpdesk\Api;
interface AiInterface
{
/**
* @param \Bydn\Helpdesk\Api\Ai\RequestInterface $data Input data
* @return \Bydn\Helpdesk\Api\Ai\ResponseInterface data return
* @throws \Magento\Framework\Webapi\Exception Exception thrown
*/
public function process(\Bydn\Helpdesk\Api\Ai\RequestInterface $data): \Bydn\Helpdesk\Api\Ai\ResponseInterface;
}
The Implementation. Time to actually write some code 🤘
Alright. We’ve already promised Magento the world with the interfaces. Now for the fun part (or the less boring part).
The Request (the box for the input data):
<?php
namespace Bydn\Helpdesk\Model\Api\Ai;
class Request implements \Bydn\Helpdesk\Api\Ai\RequestInterface
{
/**
* @var string|null
*/
private $conversation;
/**
* Get conversation
*
* @return string|null
*/
public function getConversation()
{
return $this->conversation;
}
/**
* Set conversation
*
* @param string $conversation
* @return $this
*/
public function setConversation($conversation)
{
$this->conversation = $conversation;
return $this;
}
}
The Response (the box for the output data):
<?php
namespace Bydn\Helpdesk\Model\Api\Ai;
class Response implements \Bydn\Helpdesk\Api\Ai\ResponseInterface
{
/**
* @var string|null
*/
private $response;
/**
* Get Description
*
* @return string|null
*/
public function getResponse()
{
return $this->response;
}
/**
* Set Description
*
* @param string $description
* @return $this
*/
public function setResponse($response)
{
$this->response = $response;
return $this;
}
}
And the class that does the real magic:
<?php
namespace Bydn\Helpdesk\Model\Api;
use Bydn\Helpdesk\Api\AiInterface;
use Magento\Framework\HTTP\Client\Curl;
use Magento\Framework\Serialize\Serializer\Json;
use Magento\Framework\Webapi\Exception as WebapiException;
use Magento\Framework\Phrase;
class Ai implements AiInterface
{
private Curl $curl;
private Json $json;
private \Bydn\Helpdesk\Model\Api\Ai\ResponseFactory $responseFactory;
public function __construct(
Curl $curl,
Json $json,
\Bydn\Helpdesk\Model\Api\Ai\ResponseFactory $responseFactory
) {
$this->curl = $curl;
$this->json = $json;
$this->responseFactory = $responseFactory;
}
/**
* @inheritdoc
*/
public function process(\Bydn\Helpdesk\Api\Ai\RequestInterface $data): \Bydn\Helpdesk\Api\Ai\ResponseInterface
{
try {
// Pon aquí tiu lógica maravillosa
$r = $this->responseFactory->create();
$requestText = $data->getConversation();
$r->setResponse($requestText . " => hola caracola");
return $r;
}
catch (\Exception $e) {
// Gestiona aquí los errores
}
}
}
Configuring the XMLs (the least sexy part)
Alright, we’ve got the logic. Now we need to hang a neon sign on the door so the requests know where to call. That’s done in the wonderful world of XML.
etc/webapi.xml
With this, we’re telling Magento: “The URL https://<my-store>/rest/V1/ai/process
is handled by the process
method of the class that implements \Bydn\Helpdesk\Api\AiInterface
.” And with ref="self"
, we’re putting a bouncer at the door who only lets in customers with their token. 💪
<?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/ai/process" method="POST">
<service class="Bydn\Helpdesk\Api\AiInterface" method="process"/>
<resources>
<resource ref="self"/>
</resources>
</route>
</routes>
And now for the final puzzle. We have the promises (Interfaces) and those who keep the promises (Classes). Now we just need the snitch that tells Magento who’s who. In other words, the di.xml
. Basically, here we’re playing “Connect the Dots.”
<?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="Bydn\Helpdesk\Api\AiInterface"
type="Bydn\Helpdesk\Model\Api\Ai" />
<preference for="Bydn\Helpdesk\Api\Ai\RequestInterface"
type="Bydn\Helpdesk\Model\Api\Ai\Request" />
<preference for="Bydn\Helpdesk\Api\Ai\ResponseInterface"
type="Bydn\Helpdesk\Model\Api\Ai\Response" />
</config>
And… voilà! 🎩✨ With this magic spell, I promise you it works. If it doesn’t, it’s the cache’s fault (99.9% of the time, it’s the damn cache). Now you have the skeleton. Let’s get integrating!
Testing the endpoint (it’s guaranteed to work, but you should probably test it just in case 😅)
Time to play with the command line.
First, we need an access token. Remember, from a store customer, not an admin.
curl -X POST \
-H "Content-Type: application/json" \
-d '{"username":"<email del cliente>","password":"<password>"}' \
https://<url-de-la-tienda>/rest/V1/integration/customer/token
This will return your precious token. Copy it.
And now, the moment of truth. Fire off the request to your brand-new endpoint:
curl -X POST "https://<url-de-mi-tienda>/rest/V1/ai/process" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token-del-usuario>" \
-d '{"data": {"conversation": "Texto de entrada"}}'
So, what do you think ?