RMS APIは楽天市場の店舗管理、商品管理の自動化を実現するAPIです。あまりサンプルがまとまっていないので、APIの全パターンを下記記事でまとめています。
楽天 RMS APIのPHPサンプル集・使い方 ほぼ全パターン(随時更新中)
今回は商品登録の商品API(Item API)、item.insertを解説します。
APIを使用できる環境がない場合は、下記から出店申請をしてください。結構費用がかかるので資料請求しつつ、担当と色々相談しながらやってみてくださいね。APIを試すだけなら出店アカウントを持っている人に頼んでテスト店舗を使わせてもらうのも手です。
サンプルソースコードは下記です。
こちらの記事は当初運営者メンバーの執筆でしたが現在は離れており、寄稿記事となっています。そのため当記事の情報アップデートにつきましては2020年1月をもって終了・サポート・内容についての問合せなどは受けておりません。また、記事内容を利用された際に生じた内容にも責任を負えませんのでご了承ください。
item.insertの概要
item.insertのRESTのエンドポイントにPOSTすると、RMS上に商品を新規登録できます。
登録できる設定項目例は下記です。
- 商品の名前
- 商品の価格
- 在庫数
- 納期管理番号(1-2日以内に届きます的なやつ)
- 倉庫指定
- ポイント倍率
- ポイントキャンペーン実施期間
- 店舗内カテゴリー
- ディレクトリID
- カタログID(JANコード)
- 各画像のURL
- PC用説明文
- スマホ用説明文
- 携帯用説明文
- キャッチコピー
- 送料
設定項目多すぎますね。無論これ以外にも設定できる項目があるため、詳しくはRMSのAPI仕様書を確認ください。
POST リクエスト例
リクエスト例さえ分かれば使えたようなものです。
<?xml version="1.0" encoding="UTF-8"?>
<request>
<itemInsertRequest>
<item>
<itemUrl>hogehoge</itemUrl>
<itemNumber>hogehoge</itemNumber>
<itemName>テスト商品につき購入不可_testrrrz_lvt_20180626130715</itemName>
<itemPrice>100</itemPrice>
<genreId>209124</genreId>
<catalogId>9784797347852</catalogId>
<images>
<image>
<imageUrl>https://image.rakuten.co.jp/_shop_hoge/cabinet/images/rrrz_01.jpg</imageUrl>
<imageAlt>テスト商品につき購入不可_testrrrz_lvt_20180626130715</imageAlt>
</image>
<image>
<imageUrl>https://image.rakuten.co.jp/_shop_hoge/cabinet/images/rrrz_01.jpg</imageUrl>
<imageAlt>テスト商品につき購入不可_testrrrz_lvt_20180626130715</imageAlt>
</image>
</images>
<descriptionForPC>結構html使える</descriptionForPC>
<descriptionForMobile>一部html使用可能</descriptionForMobile>
<descriptionForSmartPhone>一部html使用可能</descriptionForSmartPhone>
<catchCopyForPC>PC用キャッチコピー</catchCopyForPC>
<catchCopyForMobile>モバイル用キャッチコピー</catchCopyForMobile>
<isIncludedPostage>0</isIncludedPostage>
<isIncludedCashOnDeliveryPostage>1</isIncludedCashOnDeliveryPostage>
<postage>108</postage>
<isDepot>1</isDepot>
<point>
<pointRate>2</pointRate>
<pointRateStart>2018-06-26T15:37:15+09:00</pointRateStart>
<pointRateEnd>2018-08-25T14:37:15+09:00</pointRateEnd>
</point>
<itemInventory>
<inventoryType>1</inventoryType>
<inventories>
<inventory>
<inventoryCount>1</inventoryCount>
<normalDeliveryDateId>1000</normalDeliveryDateId>
<backorderDeliveryDateId>1000</backorderDeliveryDateId>
</inventory>
</inventories>
<inventoryQuantityFlag>1</inventoryQuantityFlag>
</itemInventory>
</item>
</itemInsertRequest>
</request>
リクエストBodyと共に、リクエストheaderにbase64エンコードしたサービスシークレットとライセンスキーを付与してPOSTすることで、APIが使用できます。
ソースコード解説
やることは、単純で
- POSTリクエストする商品情報パラメータのクラスを作成
- 商品情報クラスパラメータをxmlに変換
- curlでPOST
です。
POSTリクエストする商品情報パラメータのクラスを作成
最終的に下記のようなXMLのリクエストを作れれば良いわけです。
<?xml version="1.0" encoding="UTF-8"?>
<request>
<itemInsertRequest>
<item>
<itemUrl>hogehoge</itemUrl>
<itemNumber>hogehoge</itemNumber>
<itemName>テスト商品につき購入不可_testrrrz_lvt_20180626130715</itemName>
<itemPrice>100</itemPrice>
<genreId>209124</genreId>
<catalogId>9784797347852</catalogId>
<images>
<image>
<imageUrl>https://image.rakuten.co.jp/_shop_hoge/cabinet/images/rrrz_01.jpg</imageUrl>
...省略
</item>
</itemInsertRequest>
</request>
つまりこれをクラスで定義して、値を設定した後、XMLに変換するような仕組みが必要です。そのためにまずはItemクラスを作成します。
<?php
class Item
{
// xmlで自動生成するときに順番通りに要素が並ぶ
// RMS APIは順番を組み替えると400が返ってくるので注意すること
public $itemUrl;
public $itemNumber;
public $itemName;
public $itemPrice;
public $genreId; //ディレクトリID
public $catalogId; //カタログID(JAN)
public $catalogIdExemptionReason;
public $images; // 画像のリスト Imageクラスのオブジェクトをarrayで追加していく
public $descriptionForPC;
public $descriptionForMobile;
public $descriptionForSmartPhone;
public $catchCopyForPC;
public $catchCopyForMobile;
public $isIncludedPostage;
public $isIncludedCashOnDeliveryPostage;
public $postage;
public $isDepot; //倉庫指定
public $point; // Pointクラスのオブジェクトが入る
public $itemInventory; // ItemInventoryクラスのオブジェクトが入る
public $categories; // CategoryInfoオブジェクトが入る
function __construct() {
}
}
<item></item>の中に入るものを記述しています。後ほどこのクラスオブジェクトをある関数にぶちこむと勝手にxml化してくれるようにします。当然、<item>配下には、<image>やら<point>やら在庫定義の<itemInventory>なんて要素がネストされているので、そのクラスも作ります。
class/image.php
class/point.php
class/itemInventory.php
class/inventory.php
class/categoryInfo.php
これはitem.insertのリクエストの仕様書を見ながら作りました。異常に設定項目が多いので、最低限必要なものしか定義していません。必要があれば、このクラスにメンバーを追加していく必要があります。注意して欲しいのが、仕様書の順番通りにxmlを作成しないと400が返却されてうまくいかないこと。例えば$catchCopyForPCと$catchCopyForMobileの順番を入れ替えると400エラーが返ってきます(2018/7/1時点)。こちらの知る限り、item.insertでしかそういう挙動は確認されていません。
[st-kaiwa-186]messageに「Request data is wrong format」みたいなのが返ってくるんですが、Wrong formatなのはそちらなんじゃないでしょうか?(XMLは仕様的に順番を保証してないはず。つまり順番が違うということでサーバーが処理できないのであれば以下略)[/st-kaiwa-186]僕のコーディング誤りかもしれませんので、何かあればこっそりご指摘ください。
クラスを作ったら、商品情報の値を入れていきます。
/***
* 商品情報のセット
* */
$item = new Item();
// 商品管理番号(商品URL)、商品番号、商品名、販売価格
$item->itemUrl = 'testrrrz_' . randomStr(3) . '_' . date_format(new DateTime('now', new DateTimeZone('Asia/Tokyo')), 'YmdHis');;
$item->itemNumber = $item->itemUrl;
$item->itemName = 'テスト商品につき購入不可_' . $item->itemUrl;
$item->itemPrice = 100;
// 在庫関連設定
$itemInventory = new ItemInventory();
$itemInventory->inventoryType = RMS_ITEM_INVENTORY_TYPE_NORMAL; // 通常在庫設定
$itemInventory->inventoryQuantityFlag = 1;
// 個別の在庫
$inventory = new Inventory();
$inventory->inventoryCount = 1;
$inventory->normalDeliveryDateId = 1000; // RMSのデフォルト設定「1~2日以内に発送予定(店舗休業日を除く)」
$inventory->backorderDeliveryDateId = 1000; // RMSのデフォルト設定「1~2日以内に発送予定(店舗休業日を除く)」
// 在庫リストに個別の在庫を格納
$itemInventory->inventories[] = $inventory;
// 商品に在庫情報をセット
$item->itemInventory = $itemInventory;
// 倉庫指定
$item->isDepot = 1; // true(1)で倉庫行き、false(0)で販売中
// ポイント倍率設定
$point = new Point();
$point->pointRate = 2; //変倍率
$pointRateStart = new DateTime('now');
$pointRateStart->modify('+2 hours +30 minutes'); //現在時刻から2時間30分後を変倍の開始に
$pointRateStart->setTimeZone( new DateTimeZone('Asia/Tokyo'));
$pointRateEnd = clone $pointRateStart;
$pointRateEnd->modify('+60 day -1hour'); // 変倍開始から60日後を変倍の終了に
$point->pointRateStart = $pointRateStart->format(DATE_RFC3339); // 変倍開始時期を文字列でセット
$point->pointRateEnd = $pointRateEnd->format(DATE_RFC3339); // 変倍終了時期を文字列でセット
// 商品にポイント倍率をセット
$item->point = $point;
// カテゴリー設定 (設定したい場合は首開けして)
// $categoryInfo = new CategoryInfo();
// $categoryInfo->categoryId = 100; // 設定したいカテゴリーIDを指定
// 商品にカテゴリーをセット(設定したい場合は首開けして)
// $item->categories = array('categoryInfo' => $categoryInfo);
// ↑イリーガルなセットの仕方。本当はarray($categoryInfo, ...) とやりたいが今のcreateRequestXml関数だと無理。
// 普通categoriesの下はcategory要素が来るだろうに仕様上そうなっていない為の苦肉の策。ミスった。
// ディレクトリID カタログID(JAN)設定
$item->genreId = 209124; //本・雑誌・コミック>PC・システム開発>プログラミング>PHP この値は連関表から取得
$item->catalogId = 9784797347852; // カタログID(JANコード)
//$item->catalogIdExemptionReason = RMS_CATALOG_EXCEPTION_REASON_NO_JAN;
// 画像関連設定
// 画像が二つある場合 こちらはR-Cabinetにあげたやつを指定。適宜カスタマイズして
for($i = 0; $i < 2; $i++) {
$image = new Image();
$image->imageUrl = RMS_IMAGE_BASE_URL . RMS_SETTLEMENT_SHOP_URL . "/cabinet/images/rrrz_01.jpg";
$image->imageAlt = "$item->itemName";
$item->images[] = $image; // 商品に画像をセット
}
// 説明文関連設定
$item->descriptionForPC = '結構html使える';
$item->descriptionForMobile = '一部html使用可能';
$item->descriptionForSmartPhone = '一部html使用可能';
$item->catchCopyForPC = 'PC用キャッチコピー';
$item->catchCopyForMobile = 'モバイル用キャッチコピー';
// 送料など設定
$item->isIncludedPostage = 0; // 送料無料フラグ (0:送料別 1:送料込)
$item->postage = 108; // 個別送料
$item->isIncludedCashOnDeliveryPostage = 1; // 1:代引料込 (デフォルト0:代引き料別)
// 楽天へRMS APIを使って登録
list($reqXml, $httpStatusCode, $response) = insertItem($item);
商品情報クラスパラメータをxmlに変換
ここが難しい。何か便利なライブラリをご存知の方がいたら教えて欲しいです。(AndroidのGSONみたいなやつ)
やることとしては、
- クラスオブジェクトを一旦配列に変換
- リクエストのXMLをarray情報から作成する
- arrayをforeachで回し、keyとvalueを元にSimpleXMLElementに追加していく
/*
* 渡したclassオブジェクトからリクエストのXMLを自動生成する
* 注意. xmlの要素の順番を変えると400でwrong formatエラーが返却されるクソ仕様。
* item.getでxmlの要素の順番を確認しながら行うと無難(API仕様書でも良いが間違ってないという保証はない)
*/
function _createRequestXml($item) {
// リクエストXMLのガワを作る
$rootXml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><request/>');
$itemInsertRequestXml = $rootXml->addChild('itemInsertRequest');
$itemXml = $itemInsertRequestXml->addChild('item');
// 受け取った商品情報オブジェクトをarrayに変換
$array = _convertClassObjectToArray($item); //★クラスオブジェクトを一旦配列に変換
_arrayToXml($array, $itemXml); // リクエストのXMLをarray情報から作成する
return $rootXml->asXML(); // リクエストのXMLを返却する
}
/**
* Convert an array to XML
* @param array $array
* @param SimpleXMLElement $xml
* @param array $parentKeyName (その要素が配列で、子要素を親要素の単数形にして登録したい時指定)
*/
function _arrayToXml($array, &$xml, $parentKeyName=null){
// ★arrayをforeachで回し、keyとvalueを元にSimpleXMLElementに追加していく
foreach ($array as $key => $value) {
if(is_array($value)){
if(is_int($key)){
if(!empty($parentKeyName)) {
// 親要素が存在する時、子要素を親要素の単数形の名前にして登録
$key = singularByPlural($parentKeyName); // 自作関数
}
}
$label = $xml->addChild($key);
_arrayToXml($value, $label, $key);
}
else if(!is_null($value)){
// 値がセットされている時だけxml要素に追加
$xml->addChild($key, $value);
}
}
}
/**
* Convert an classObject to array
*/
function _convertClassObjectToArray($object) {
$json = json_encode($object);
return (array)json_decode($json, true);
}
なんというか、全部xmlを愚直にstringでつないで作ってもいいんですが、めんどくさ過ぎなので苦闘してみました。こんな感じにした方が楽だよというお話があれば、是非@yhei_heiまでご連絡いただくかisuueをあげて頂けると幸いです。
curlでPOST
Itemクラスが無事xmlに変換できたら、POSTしましょう。API申請時に発行したサービスシークレットとライセンスキーをヘッダーに付与する必要があります(★部分)ので注意ください。
/*
* APIのリクエストを行う
* xmlを作って curlでpostしてる
* @param 挿入したい商品情報のクラスオブジェクト
* @return リクエストしたxml文字列, httpステータスコード, レスポンス文字列(xmlで返ってくる)
*/
function insertItem($item) {
$authkey = base64_encode(RMS_SERVICE_SECRET . ':' . RMS_LICENSE_KEY); // ★サービスシークレットとライセンスキーをbase64エンコードして
$header = array(
"Content-Type: text/xml;charset=UTF-8",
"Authorization: ESA {$authkey}",// ★Authorization: ESA ほげほげ的な感じで付与
);
$url = RMS_API_ITEM_INSERT;
$ch = curl_init($url);
$reqXml = _createRequestXml($item);
// return array($reqXml, $httpStatusCode, $response);
curl_setopt($ch, CURLOPT_POSTFIELDS, $reqXml);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header); // ★ヘッダーを付与
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //返り値を 文字列で返します
$response = curl_exec($ch);
if(curl_error($ch)){
$response = curl_error($ch);
}
$httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return array($reqXml, $httpStatusCode, $response);
}
レスポンスとして下記のようなのが返ってきたら成功です。
<?xml version="1.0" encoding="UTF-8"?>
<result>
<status>
<interfaceId>item.insert</interfaceId>
<systemStatus>OK</systemStatus>
<message>OK</message>
<requestId>989e35ba-01a8-4cb8-963b-713bbf067414</requestId>
<requests/>
</status>
<itemInsertResult>
<code>N000</code>
<item>
<itemUrl>testrrrz_w84_20180701151725</itemUrl>
</item>
</itemInsertResult>
</result>
まとめ
item.insert APIを突っ込んで解説してみました。設定項目が多いので、クラス化して情報設定→xmlに変換するっていう工程が結構面倒でした。
「ここ間違ってるよ」や「ここがよく分からないのだけど」というところがあれば、isuueをあげて質問いただければと思います。
サンプルソースコードは下記です。基本的にconfig.phpだけ設定した後は、いじらずにphpファイルを開けばそのまま使えるようになってるので、改造前にオリジナルで試していただくと理解がスムーズです。