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が使用するデータのうち、配列型はオブジェクト型になるように定義と実装を行う

ということになります。