どうもーキュービックでテックリードをやっている尾﨑です。 本日は会計や組織データなどのマスタ管理を行なっているNetSuiteとAPI連携した時のお話をしたいと思います。 スクラッチで連携した事例は希少だと思うので、困っている方の課題解決に繋がると嬉しいです。 今回は前回のクライアント証明書認証によるREST API連携に続いて、トークンベース認証によるRESTlet API連携をご紹介したいと思います。
・OAuth2.0トークン認証によるREST API連携 ・OAuth2.0クライアント認証によるREST API連携 ・トークンベース認証によるRESTlet API連携★
本日はトークンベース認証によるRESTlet API連携とハマったポイントなどをご紹介したいと思います。
アーキテクチャ構成
1.ORACLE NETSUITEに登録されているマスターに更新が発生(登録/更新/削除) 2.Suite Scriptにて更新をトリガーにRestlet APIにて更新レコード情報を取得 3.Suite Scriptからtrocco APIをコールしてSaaSサービスtroccoにpostデータを送信 4.trocco からRedshiftにマスタ情報を連携
前回の課題のおさらい
クライアント証明書認証によるREST API連携の課題
- 証明書が2年おきに更新が必要(PJ離任時のリスク)
- Netsuiteの更新トリガーではない
はまった点
アカウントに複数ロールが割当たっている場合にアクセストークンに不整合が起きた
- トークンベース/ロール/アカウントが同一であるかを確認
AuthorizatonのRESTlet ヘッダーの生成には個別にスクリプティングが必須
- パラメータのoauth_timestampは前回リクエスト時から更新する必要がある
解決策
アクセストークンの不整合の解消を試る
- 1.Youtubeのこちらの動画を参考にAPI連携用のロールの作成とアカウントへの割り当てを実施
- 2.API連携用のロールを割り当てたアカウントにてトークンベース認証を設定
- 3.テクニカルサポートとビデオ会議でペアプロを行いつつpostmanで疎通に成功
実装に向けてRESTlet ヘッダーの生成を行う
- 1.PHPで個別にRESTlet ヘッダーの生成スクリプトを実装
- 2.この時点で疎通エラーとなったため再度、テクニカルサポートとペアプロを実施
- 3.ペアプロでは問題がなかったため、テクニカルサポートに情報を連携し、詳細調査依頼
- 4.アカウントIDの指定が微妙に異なる点が判明
- URLでは「-小文字」だが「大文字指定」になる(-sb1はSB1となる)
フロー
順序としては1〜8になります。
- 1.TBAのログインが行えるロールを新規作成する
- 2.TBAのロールを付与するユーザーを新規作成する
- 3.インテグレーションでTBA認証を作成する
- consumner_keyを取得する
- consumer_secretを取得する
- 4.アクセストークンを作成する
- アプリケーションはインテグレーションと紐付け
- ※ユーザーに複数のロールが存在する場合は、ログインしているロールをTBAのロールに設定して実施する
- 5.NetSuiteにscriptファイルをアップロードする
- 6.NetSuiteにscriptファイルをデプロイする
- 7.エンドポイントを取得する
- 8.RESTlet ヘッダーの生成を行い、外部からRESTlets APIで連携する
手順
1〜7までは以下の解説動画を参考に進めてください。 www.youtube.com
今回は以下を中心に解説します
- 8.RESTlet ヘッダーの生成を行い、外部からRESTlet APIで連携する
エンドポイントを以下のように取得したら、RESTlet ヘッダーの生成に進みます。 参考にした動画ではNETSUITE上で生成ができるようでしたが、生成できないようでした。
大項目 | 中項目 | 設定値 |
---|---|---|
Authorization | Signature Method | HMAC-SHA256 |
Authorization | Consumer Key | インテグレーション作成時の消費者キー/クライアントID |
Authorization | Consumer Secret | インテグレーション作成時の消費者のシークレット/クライアントのシークレット |
Authorization | Access Token | アクセストークン作成時のトークンID |
Authorization | Token Secret | アクセストークン作成時のトークン・シークレット |
Authorization | Timestamp | 現在のunixtimeを指定。postmanでは自動補完されるので不要 |
Authorization | Nonce | ランダムな10文字以上の英数字を指定。postmanでは自動補完されるので不要 |
Authorization | version | 1.0 |
Authorization | Realm | アカウントID。URLでは小文字だが大文字指定かつハイフンがアンダースコートになる(-sb1だが_SB1)となる点に注意 |
Authorization | Signature Method | HMAC-SHA256 |
User-Agent-X | - | SuiteScript-Call(なくても大丈夫) |
Content-Type | - | application/json |
APIの設定
- postmanであればRESTlet ヘッダーを生成しなくとも、疎通ができます。
- 以下にjsonの例を示すので、コピーしてインポートしてください。
- パラメータやエンドポイントなどは適宜ご自身の情報に更新してください。
{ "info": { "_postman_id": "557cee83-97ed-470e-b0f2-c15b46bb3319", "name": "NETSUITE", "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json", "_exporter_id": "25370205" }, "item": [ { "name": "RestletTest", "request": { "auth": { "type": "oauth1", "oauth1": { "consumerSecret": "youre consumerSecret", "consumerKey": "youre consumerKey", "tokenSecret": "your tokenSecret", "token": "your token", "realm": "your account_id", "timestamp": "", "nonce": "", "signatureMethod": "HMAC-SHA256", "addParamsToHeader": true, "version": "1.0", "addEmptyParamsToSign": false } }, "method": "GET", "header": [ { "key": "User-Agent-X", "value": "SuiteScript-Call", "type": "text" }, { "key": "Content-Type", "value": "application/json", "type": "text" } ], "url": { "raw": "https://{your_account_id}.restlets.api.netsuite.com/app/site/hosting/restlet.nl?deploy={deploy_id}&script={script_id}", "protocol": "https", "host": [ "{your_account_id}", "restlets", "api", "netsuite", "com" ], "path": [ "app", "site", "hosting", "restlet.nl" ], "query": [ { "key": "", "value": "", "disabled": true }, { "key": "deploy", "value": "{deploy_id}" }, { "key": "script", "value": "{script_id}" } ] } }, "response": [] } ] }
どうしてもTalend API TESTERで確認したいあなたへ
Talend API TESTERでどうしても疎通したい場合 PHPで以下を実装し、AuthorizatonのRESTlet ヘッダーを生成する。 ※$timestampは毎回新ものを生成する必要があるので注意
1.authのライブラリーの関数oauth_get_sbsを使用して居るので、oauthをインストールする
pecl install oauth
2.以下の要領でRESTlet ヘッダーを生成する
<?php $requestUrl = 'https://{your_account_id}.restlets.api.netsuite.com/app/site/hosting/restlet.nl?deploy={deploy_id}&script={script_id}'; $consumerKey = 'youre Consumer Key'; $consumerSecret = 'youre Consumer Secret'; $nonce = 'aqwsedrftgyhujiko'; $timestamp = time(); $signatureMethod = 'HMAC-SHA256'; $tokenKey = 'youre Access Token'; $tokenSecret = 'youre Token Secret'; $version = '1.0'; $realm = 'youre account Name'; $httpMethod = 'GET'; $baseString = oauth_get_sbs($httpMethod, $requestUrl, array('oauth_consumer_key' => $consumerKey, 'oauth_nonce' => $nonce, 'oauth_signature_method' => $signatureMethod, 'oauth_timestamp' => $timestamp, 'oauth_token' => $tokenKey, 'oauth_version' => $version)); var_dump("baseString:".$baseString); $key = rawurlencode($consumerSecret) .'&'. rawurlencode($tokenSecret); $signature = base64_encode(hash_hmac('sha256', $baseString, $key, true)); var_dump("signature:".$signature); //認証ヘッダー //https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_1534941295.html $authorization = 'Authorization: OAuth ' .'realm="' .rawurlencode($realm) .'", ' .'oauth_consumer_key="' .rawurlencode($consumerKey) .'", ' .'oauth_token="' .rawurlencode($tokenKey) .'", ' .'oauth_nonce="' .rawurlencode($nonce) .'", ' .'oauth_timestamp="' .rawurlencode($timestamp) .'", ' .'oauth_signature_method="' .rawurlencode($signatureMethod) .'", ' .'oauth_version="' .rawurlencode($version) .'", ' .'oauth_signature="' .rawurlencode($signature) .'"' ; var_dump("Authorization:".$authorization); //疎通時のみ使用 //getRestletInfo($requestUrl,$authorization); function getRestletInfo($requestUrl,$authorization){ $header = [ "Content-Type: application/json", $authorization ]; var_dump($header); $curl=curl_init(); curl_setopt($curl,CURLOPT_URL, $requestUrl); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET'); curl_setopt($curl, CURLOPT_HTTPHEADER, $header); curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, FALSE); // 証明書の検証を無効化 curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, FALSE); // 証明書の検証を無効化 curl_setopt($curl,CURLOPT_RETURNTRANSFER, TRUE); // 返り値を文字列に変更 curl_setopt($curl,CURLOPT_FOLLOWLOCATION, TRUE); // Locationヘッダを追跡 $output= curl_exec($curl); // エラーハンドリング用 $errno = curl_errno($curl); // コネクションを閉じる curl_close($curl); // エラーハンドリング if ($errno !== CURLE_OK) { //エラー処理 } echo $output; } ?>
3.以下の要領でリクエストを送信する
リクエスト情報
大項目 | 小項目 |
---|---|
エンドポイント | https://{your_account_id}.restlets.api.netsuite.com/app/site/hosting/restlet.nl |
HTTPメソッド | GET |
- ※site-idに関しては「アクセストークン取得」にて取得
ヘッダー | 設定値 |
---|---|
Authorization | RESTlet ヘッダーの出力結果を使用する |
User-Agent | SuiteScript-Call |
Content-type | application/json |
Accept | application/json |
パラメータ | 概要 /設定値 |
---|---|
script | ビルド時に発行されたscript_id |
deploy | ビルド時に発行されたdeploy_id |
最後に
如何でしたでしょうか?NetSuiteのAPIの連携方式に関して以下の3つの連携方式を その1、その2、本記事の3回に分けてでご紹介しました。これから利用しようと思っている方の参考になると幸いです。
・OAuth2.0トークン認証によるREST API連携 ・OAuth2.0クライアント認証によるREST API連携 ・トークンベース認証によるRESTlet API連携
次回は、Netsuiteに続いて、Komawoを構成しているアーキテクチャーのtroccoに関して 導入のメリットやはまった点などを中心に説明していきたいと思います。