どうもこんにちは伊藤です。きよっちです。半年ぶりの更新となりました。真面目に書けよ!と思われるかもしれませんが、まったくそのとおりですね。ちょっといろいろ思うところがございまして、沈んでましたが、それはまたおいおい。
はい。ところで。楽天さんの動きが激しいですね。楽天Payへの移行などなど。やらなくてはいけないことがたくさん。ちょうど今年2018年はヤマト運輸さんの配送料金大改革などなどもありましたし、Instagram上で通販が可能になったりしましたし、環境は大きく揺れ動いています。日本のECがはじまって以来、最も大きな変革期に来ているのかもしれません。ECを主戦場にしている業者さんは、自社の立ち位置、目指す場所、戦い方(戦わないという選択肢も含めて)などを明確にできる機会かもしれません。
ちょっと話がズレてしまいましたが、さて、楽天は改革を迎えているわけで、個人情報の扱い厳格化、決済方法の統一化などがあり、なるべく多くの受注操作をRMS上で行わなければならないようになってきています。
そんなこともあり、最近では、自社開発DBとの連携のために、RMS Web Service APIを利用しなければならないということもかなり増えてきました。今日はそのお話です。
RMSのAPI
まず、もってですね、楽天のRMSのAPIというのは、みなさんご存知でしょうか。2012年ごろからスタートしているRMS用のAPIです。それより以前は、公開情報(つまり商品情報ですね)を取得して、楽天外のwebサイトで活用できるようになっていたわけですが、RMS APIができてからは、RMSを楽天のシステム外で利用できるようになっています。(もちろん自社運営の楽天サイトの情報しかとることはできません) 経緯はこのあたりにくわしいです。
このRMSのAPIというやつがですね、わたしたちwebをメインにしているエンジニア・プログラマには、あまり馴染みのない「SOAP」という規格のAPIを採用しています。こいつがなかなか厄介で、webで多く使われているPHPでは、コードが冗長になりがちなのです。
そのコードについてはこちらのサイトにてサンプルが書かれていますので、参考になります。わたしも最初は参考にしました。
楽天PayOrderのAPI
上記のように、まぁぶっちゃけて言うと大変に分かりづらいSOAPを仕様したRMS APIなんですが、一回実装してしまえば、そうそう変更するものでもないので良しとしていました。
ここからが本題です。
ところがですね、楽天Pay移行により注文情報取得APIを変えなければならなくなりました。2018年以降、楽天各店は決済方法統一のため楽天Payに強制移行となりますので、既存APIを利用していた事業者さんは、いずれ、のりかえが必要ということです。 楽天Payへの移行については、こちらの記事がよくまとめられています。
しかし、文句ばかりも言っていられませんので、楽天へ出店しているクライアントさんのために、API改造に着手しました。いつもそうなんですが、楽天さんのエンジニア向けドキュメントは、ぜんぜんまとまってなくて、どこにいけばわかるのかがわからない。たどり着いたとしても、実は全体像はそこだけではわからない…など前途多難なのです。
とりあえずドキュメントにたどり着いたので、従前のOrderAPIを書き換えてみる。
…あれ…なんか変だ…動かない…というよりは、楽天から返ってくる書式が変だ…
…ん???
…あれ??????
(ここまで1時間)
ようやく気付いたのですが、楽天PayOrderAPIだけが、基底となっている技術そのものを変えてきやがったのです!!!もう「やがった」といいますが許してください!
よく読めと言われれば、それまでですが、楽天PayOrderAPIだけは「JSONベースのSOAP」なのです。APIさわったことのあるエンジニアならわかるとおもいますが「お前何いってんだよ!」ってなりました。「SOAP」はもともとXML通信インターフェイスだろうよ!!!リクエストもレスポンスもJSONでやるのに、技術そのものはSOAPなのです。この矛盾に気づくのに時間がかかりました。(ここから想像するに、おそらく楽天PayのAPIの基底フレームワークはIBMのCICSだと思われます。もう少し標準的な仕様にしてくれませんかね???)
とっととコードを出せ
はい。。。ごめんなさい。。。取り乱しました。
class RMS {
public static $serviceSecret;
public static $licenseKey;
// ----------------------------------------------------
/**
* オーダー取得
*/
public static function searchOrder(){
////認証キーを作成
// oAuthのが1289倍楽なんですけど!!!
$authkey = "ESA " . base64_encode( self::$serviceSecret . ':' . self::$licenseKey );
////検索日付
// そんなもん必須にせずに良きに計らえや!!!!
// しかもいちいちGMTに変換しなきゃあかんのかい!!!それも良きに計らえよ!!!!
// 第二引数で日本時間指定できるようにしておいた
$beginDate = gmdate( 'Y-m-d\TH:i:s+0900', strtotime('2018-07-05 00:00:00'));
$endDate = gmdate( 'Y-m-d\TH:i:s+0900', strtotime('2018-07-29 00:00:00'));
//// なぜか楽天ペイAPIだけ しかも形の上ではSOAPなのに JSONでリクエスト…
// 統一してくれんかな!!!ライブラリ書くのめんどくさいんだけど!!!!
$requestJson = json_encode([
'dateType' => 1,//期間検索種別
'startDatetime' => $beginDate,//検索対象期間先頭日時(普通startじゃなくてbeginじゃねぇか??)
'endDatetime' => $endDate,//検索対象エンド点
'orderProgressList'=> [ 100, 200, 300, 400 ],//取得したいオーダーステータス
]);
//// リクエストヘッダ作成
// うーん なんかこの認証いまいちだなー・・・
$header = [
'Authorization: '.$authkey,
'Content-Type: application/json; charset=utf-8',
];
//// SOAPリクエスト
// この辺はREST APIでのPOSTと一緒。ただし、レスポンスコードで結果コードをとるので
// レスポンスヘッダについては厳重目にとっておくべき。
$url = 'https://api.rms.rakuten.co.jp/es/2.0/order/searchOrder/';
$curl = curl_init($url);
curl_setopt( $curl, CURLOPT_POST, true );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $curl, CURLOPT_HTTPHEADER, $header );
curl_setopt( $curl, CURLOPT_POSTFIELDS, $requestJson );
curl_setopt( $curl, CURLOPT_HEADER, true);//これを指定するとレスポンスにヘッダがついてくる
// curlセッションを実行 ヘッダが付いているので分解
$response = curl_exec( $curl );
// ステータスコード取得
$statusCode = curl_getinfo( $curl, CURLINFO_HTTP_CODE );
// ヘッダサイズを取得して、その分を切り取ってしまう方策
// もう少しいい方法があるかもしれない??
$headerSize = curl_getinfo( $curl, CURLINFO_HEADER_SIZE );
$requestHeader = substr( $response, 0, $headerSize);
$requestBody = substr( $response, $headerSize );//ここに結果JSONがかえる
//// jsonをオブジェクトにー
$return = json_decode( $requestBody );
curl_close( $curl );
return $return;
}
// ----------------------------------------------------
}
ざっくりとclassにしました。モダンなコードではないですし、何かが漏れていますが気にしないでください。
引数でパラメータを指定できるようにするなどの改造は必要だとおもいますし、いくつかのエンドポイントを実装するにあたってはPOST部分を独立メソッドにすべきでしょう。そこは、皆さんのセンス。
このクラスをロードしておいて
<?php
RMS::$licenseKey = 'ライセンスキー';
RMS::$serviceSecret = 'シークレットキー';
$res = RMS::searchOrder();
とかでだいたい勝てます。
以上、現場からでした。
「室井さん。どうして現場に血が流れるんだ!」(←古い)
コメントを残す