どうもこんにちは伊藤です。きよっちです。半年ぶりの更新となりました。真面目に書けよ!と思われるかもしれませんが、まったくそのとおりですね。ちょっといろいろ思うところがございまして、沈んでましたが、それはまたおいおい。

はい。ところで。楽天さんの動きが激しいですね。楽天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();

とかでだいたい勝てます。

以上、現場からでした。
「室井さん。どうして現場に血が流れるんだ!」(←古い)