Creating custom web APIs

Let's go ahead and create a miniature, yet full-blown Magento module Magelicious_Boxy that demonstrates the entire flow of creating a custom web API.

We start off by defining a module <MAGELICIOUS_DIR>/Boxy/registration.php as follows:

MagentoFrameworkComponentComponentRegistrar::register(
MagentoFrameworkComponentComponentRegistrar::MODULE,
'Magelicious_Boxy',
__DIR__
);

We then define the <MAGELICIOUS_DIR>/Boxy/etc/module.xml as follows:

<config>
<module name="Magelicious_Boxy" setup_version="2.0.2"/>
</config>

We then define the <MAGELICIOUS_DIR>/Boxy/Setup/InstallSchema.php that adds the following table:

$table = $setup->getConnection()
->newTable($setup->getTable('magelicious_boxy_box'))
->addColumn(
'entity_id',
MagentoFrameworkDBDdlTable::TYPE_INTEGER,
null, [
'identity' => true,
'unsigned' => true,
'nullable' => false,
'primary' => true
], 'Entity ID'
)
->addColumn(
'title',
MagentoFrameworkDBDdlTable::TYPE_TEXT,
32,
['nullable' => false], 'Title'
)
->addColumn(
'content',
MagentoFrameworkDBDdlTable::TYPE_TEXT,
null,
['nullable' => false], 'Content'
)
->setComment('Magelicious Boxy Box Table'),
$setup->getConnection()->createTable($table);

We then define <MAGELICIOUS_DIR>/Boxy/Api/Data/BoxInterface.php as follows:

interface BoxInterface {
const BOX_ID = 'box_id';
const TITLE = 'title';
const CONTENT = 'content';
public function getId();
public function getTitle();
public function getContent();
public function setId($id);
public function setTitle($title);
public function setContent($content);
}

We then define <MAGELICIOUS_DIR>/Boxy/Api/Data/BoxSearchResultsInterface.php as follows:

interface BoxSearchResultsInterface extends MagentoFrameworkApiSearchResultsInterface
{
public function getItems();
public function setItems(array $items);
}

We then add the <MAGELICIOUS_DIR>/Boxy/Api/BoxRepositoryInterface.php as follows:

interface BoxRepositoryInterface
{
public function save(MageliciousBoxyApiDataBoxInterface $box);
public function getById($boxId);
public function getList(MagentoFrameworkApiSearchCriteriaInterface $searchCriteria);
public function delete(MageliciousBoxyApiDataBoxInterface $box);
public function deleteById($boxId);
}

We then define the <MAGELICIOUS_DIR>/Boxy/Model/Box.php as follows:

class Box extends MagentoFrameworkModelAbstractModel implements MageliciousBoxyApiDataBoxInterface
{
protected function _construct() {
$this->_init(MageliciousBoxyModelResourceModelBox::class);
}

public function getId() {
return $this->getData(self::BOX_ID);
}

public function getTitle() {
return $this->getData(self::TITLE);
}

public function getContent() {
return $this->getData(self::CONTENT);
}

public function setId($id) {
return $this->setData(self::BOX_ID, $id);
}

public function setTitle($title) {
return $this->setData(self::TITLE, $title);
}

public function setContent($content) {
return $this->setData(self::CONTENT, $content);
}
}

We then define the <MAGELICIOUS_DIR>/Boxy/Model/ResourceModel/Box.php as follows:

class Box extends MagentoFrameworkModelResourceModelDbAbstractDb
{
protected function _construct() {
$this->_init('magelicious_boxy_box', 'entity_id'),
}
}

We then define the <MAGELICIOUS_DIR>/Boxy/Model/ResourceModel/Box/Collection.php as follows:

class Collection
{
protected function _construct() {
$this->_init(
MageliciousBoxyModelBox::class,
MageliciousBoxyModelResourceModelBox::class
);
}
}

We then define the <MAGELICIOUS_DIR>/Boxy/Model/BoxRepository.php as follows:

class BoxRepository implements MageliciousBoxyApiBoxRepositoryInterface
{
protected $boxFactory;
protected $boxResourceModel;
protected $searchResultsFactory;
protected $collectionProcessor;

public function __construct(
MageliciousBoxyApiDataBoxInterfaceFactory $boxFactory,
MageliciousBoxyModelResourceModelBox $boxResourceModel,
MageliciousBoxyApiDataBoxSearchResultsInterfaceFactory $searchResultsFactory,
MagentoFrameworkApiSearchCriteriaCollectionProcessorInterface $collectionProcessor
)
{
$this->boxFactory = $boxFactory;
$this->boxResourceModel = $boxResourceModel;
$this->searchResultsFactory = $searchResultsFactory;
$this->collectionProcessor = $collectionProcessor;
}
// Todo...
}

Let's go ahead and amend the BoxRepository with the save method as follows:

public function save(MageliciousBoxyApiDataBoxInterface $box)
{
try {
$this->boxResourceModel->save($box);
} catch (Exception $e) {
throw new MagentoFrameworkExceptionCouldNotSaveException(__($e->getMessage()));
}
return $box;
}

Let's go ahead and amend the BoxRepository with the getById method as follows:

public function getById($boxId) {
$box = $this->boxFactory->create();
$this->boxResourceModel->load($box, $boxId);
if (!$box->getId()) {
throw new MagentoFrameworkExceptionNoSuchEntityException(__('Box with id "%1" does not exist.', $boxId));
}
return $box;
}

Let's go ahead and amend the BoxRepository with the getList method as follows:

public function getList(MagentoFrameworkApiSearchCriteriaInterface $searchCriteria) {
$collection = $this->boxCollectionFactory->create();
$this->collectionProcessor->process($searchCriteria, $collection);
$searchResults = $this->searchResultsFactory->create();
$searchResults->setSearchCriteria($searchCriteria);
$searchResults->setItems($collection->getItems());
$searchResults->setTotalCount($collection->getSize());
return $searchResults;
}

Let's go ahead and amend the BoxRepository with the delete method as follows:

public function delete(MageliciousBoxyApiDataBoxInterface $box) {
try {
$this->boxResourceModel->delete($box);
} catch (Exception $e) {
throw new MagentoFrameworkExceptionCouldNotDeleteException(__($e->getMessage()));
}
return true;
}

Let's go ahead and amend the BoxRepository with the deleteById method as follows:

public function deleteById($boxId) {
return $this->delete($this->getById($boxId));
}

We then define the <MAGELICIOUS_DIR>/Boxy/etc/di.xml as follows:

<config>
<preference for="MageliciousBoxyApiDataBoxInterface" type="MageliciousBoxyModelBox"/>
<preference for="MageliciousBoxyApiDataBoxSearchResultsInterface" type="MagentoFrameworkApiSearchResults" />
<preference for="MageliciousBoxyApiBoxRepositoryInterface" type="MageliciousBoxyModelBoxRepository"/>
</config>

We then define the <MAGELICIOUS_DIR>/Boxy/etc/acl.xml as follows:

<config>
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Sales::sales">
<resource id="Magento_Sales::sales_operation">
<resource id="Magento_Sales::shipment">
<resource id="Magelicious_Boxy::box" title="Boxy Box">
<resource id="Magelicious_Boxy::box_get" title="Get"/>
<resource id="Magelicious_Boxy::box_search" title="Search"/>
<resource id="Magelicious_Boxy::box_save" title="Save"/>
<resource id="Magelicious_Boxy::box_update" title="Update"/>
<resource id="Magelicious_Boxy::box_delete" title="Delete"/>
</resource>
</resource>
</resource>
</resource>
</resource>
</resources>
</acl>
</config>

We then define the <MAGELICIOUS_DIR>/Boxy/etc/webapi.xml as follows:

<routes>
<route url="/V1/boxyBox/:boxId" method="GET">
<service class="MageliciousBoxyApiBoxRepositoryInterface" method="getById"/>
<resources>
<resource ref="Magelicious_Boxy::box_get"/>
</resources>
</route>
<route url="/V1/boxyBox/search" method="GET">
<service class="MageliciousBoxyApiBoxRepositoryInterface" method="getList"/>
<resources>
<resource ref="Magelicious_Boxy::box_search"/>
</resources>
</route>
<route url="/V1/boxyBox" method="POST">
<service class="MageliciousBoxyApiBoxRepositoryInterface" method="save"/>
<resources>
<resource ref="Magelicious_Boxy::box_save"/>
</resources>
</route>
<route url="/V1/boxyBox/:id" method="PUT">
<service class="MageliciousBoxyApiBoxRepositoryInterface" method="save"/>
<resources>
<resource ref="Magelicious_Boxy::box_update"/>
</resources>
</route>
<route url="/V1/boxyBox/:boxId" method="DELETE">
<service class="MageliciousBoxyApiBoxRepositoryInterface" method="deleteById"/>
<resources>
<resource ref="Magelicious_Boxy::box_delete"/>
</resources>
</route>
</routes>

With all these bits in place, our API is now ready. We should now be able to CRUD our way through Boxy Box the same way we did with the CMS block. While there certainly is a great deal of boilerplate code to go around, our API is now both REST-and SOAP-ready.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.160.216