Adobe Commerce / Magento Open Sourceで独自のREST APIエンドポイントを作成するには〜その3
今回は「Adobe Commerce / Magento Open Sourceで独自のREST APIエンドポイントを作成するには〜その2」の続きとして、Interfaceに対するModelの実装例の紹介と、実際にAPIを動かしてみた結果を紹介したいと思います。
di.xmlでInterfaceと実装を関連付ける
既にMagentoフレームワークにおけるdi.xmlの役割を理解している方からすると、至って当然の作業にはなりますが、di.xmlでInterfaceと実装を関連付けます。
エクステンションディレクトリ/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="Veriteworks\Webapi\Api\ExampleInterface" type="Veriteworks\Webapi\Model\Example" />
<preference for="Veriteworks\Webapi\Api\Data\SampleInfoInterface" type="Veriteworks\Webapi\Model\Info\Sample"/>
</config>
既にあるdi.xmlに追記する場合は、preferenceタグだけを追記してください。
こうすることでInterfaceに対するデフォルトの実装が定義できます。
正確にはそれぞれのInterfaceがコンストラクタ引数で要求された場合に、ObjectManagerがこの定義内容を参照してtype属性に指定したクラスのインスタンスを生成します。
このあたりはMagentoフレームワークにおけるDependency Injectionの仕組みを見ていただくとわかると思います。
Modelの実装
次にModelの実装を行います。
- Veriteworks\Webapi\Model\InfoManager
- Veriteworks\Webapi\Model\Info\InfoData
がまだ未実装なので、この2つのModelクラスを実装しましょう。
Veriteworks\Webapi\Model\Info\InfoData
まず、データを扱うModelを先に実装してしまいましょう。
そうしないとリクエストを受けるModel側でどんなメソッドを呼んでいいかわからなくなります。
(今回の例では呼びません)
<?php
namespace Veriteworks\Webapi\Model\Data;
use \Veriteworks\Webapi\Api\Data\InfoInterface;
class InfoData implements InfoInterface
{
/**
* @var string
*/
private $label = '';
/**
* @var int
*/
private $value = 0;
/**
* @param string $label
* @return InfoInterface
*/
public function setLabel(string $label): InfoInterface
{
$this->label = $label;
return $this;
}
/**
* @return string
*/
public function getLabel(): string
{
return $this->label;
}
/**
* @param int $value
* @return InfoInterface
*/
public function setValue(int $value): InfoInterface
{
$this->value = $value;
return $this;
}
/**
* @return int
*/
public function getValue(): int
{
return $this->value;
}
}
基本的にデータを扱うModelはsetter/getterしかメソッドを持ちません。
それ以外の処理は実装しないようにしましょう。
Veriteworks\Webapi\Model\InfoManager
次は実際にリクエストを受けるModelを実装しましょう。
下記のような内容で実装を行います。
<?php
namespace Veriteworks\Webapi\Model;
use \Veriteworks\Webapi\Api\InfoInterface;
use \Veriteworks\Webapi\Api\Data\InfoInterface as DataInterface;
class InfoManager implements InfoInterface
{
/**
* @var DataInterface
*/
private $info;
/**
* @param DataInterface $info
*/
public function __construct(
DataInterface $info
)
{
$this->info = $info;
}
/**
* @return DataInterface
*/
public function getSampleInfo(): DataInterface
{
return $this->info;
}
/**
* @param DataInterface $info
* @return int
*/
public function setSampleInfo(DataInterface $info): int
{
$this->info = $info;
return 1;
}
}
今回の例ではData\InfoInterface型の値を出し入れするだけ、としておきます。
Data\InfoInterface型のデータを指定したテーブルに保存したり読み出したりする処理については、REST APIを実装したい方は既に理解されている前提です。
モジュールの有効化
では、作成したモジュールを有効にしましょう。
他のモジュールと同様に、以下のmagentoコマンドで有効化します。
php bin/magento module:enable Veriteworks_Webapi
php bin/magento setup:di:compile
で有効化します。
static-contentについては今回は使用しないので対象外とします。
REST APIを動かしてみよう
最後に作成したAPIにアクセスしてみましょう。
webapi.xmlでは
- GET
- POST
の2つのエンドポイントを定義しました。
それぞれのエンドポイントに対し、リクエストを投げてみたいと思います。
GET /V1/example/endpoint/info
まず最初はGETのエンドポイントです。
次のような内容でアクセスしてみましょう。
curl -X GET '<Magentoホスト名>/rest/default/V1/example/endpoint/info'
GETの場合はURLを直接ブラウザに入れてもいいですし、APIテスト用のツールを用いても構いません。
レスポンスとして、以下のようなものが返れば成功です。
{"label":"","value":0}
Data\InfoInterfaceとは書かれていませんが、プロパティの構成は実装のとおりとなっています。
実用的な処理を実装する場合は、
- データベースやファイルなどとのやり取りをするModelクラスの実装
- InfoManagerからの処理の受け渡し
などが必要になります。
POST /V1/example/endpoint/info
次はPOSTのエンドポイントです。
次のような内容でアクセスしてみましょう。
curl -H 'Content-Type: application/json' -X POST '<Magentoホスト名>/rest/default/V1/example/endpoint/info' -d '{"info" : {"label":"test","value":1}}'
レスポンスとして、以下のようなものが返れば成功です。
1
POSTの場合は1を返すように実装したので、これで実装のとおりですね。
実際になにか処理を作る場合は
- 成功時と失敗時の戻り値の定義
- 例外・エラーメッセージの定義
- 送信されてきたデータの保存処理など
などが必要になります。
まとめ
ここまで3回にわたって、MagentoフレームワークにおけるREST APIエンドポイントの実装方法を紹介してきました。
ざっくりまとめると、
- エンドポイントを定義するにはwebapi.xmlを作成する
- APIには権限の設定ができる
- webapi.xmlにはInterfaceとメソッドを指定する
- 実際の実装はdi.xmlでInterfaceに対してマッピングしたクラスで行う
- APIが使用するデータのうち、配列型はオブジェクト型になるように定義と実装を行う
ということになります。