REST インターフェースの使用法

概要

Things Cloudでは、すべての外部通信にRESTを採用しています。 通信の発信元がIoTデバイス、Webアプリケーション、またはバックオフィスITシステムであるかに関わらず、通信プロトコルは常にRESTです。

RESTはHTTP(S) とTCPをベースにした非常にシンプルでセキュアなプロトコルです。現在、非常にシンプルなデバイスから大規模なITに至るまで、すべてのネットワーク型プログラミング環境でサポートされている事実上のインターネット標準となっています。RESTを紹介している多くの本の中の1つにRESTful Web Servicesがあります。

ここでの説明は、各インターフェースの詳細が記載されたThings Cloud OpenAPI仕様と密接に関連しています。 Things Cloud OpenAPI仕様内の関連するセクションは、次の通りです。

JavaまたはC#を使用してアプリケーションを開発する場合は、Things Cloudの機能にさらに簡単にアクセスできるよう、このガイドの関連するセクションもご覧ください。 RESTインターフェース全般、およびRESTによるデバイス統合の詳細については、「デバイスSDKガイド」の REST セクション をご覧ください。

RESTインターフェースの使用法

現在、ほとんどのプログラミング環境において、RESTベース通信への対応は際立っています。Things CloudのRESTインターフェースを理解し、使用するにあたり、利用できる膨大なコマンドラインツールやブラウザ拡張機能が役立ちます。

例えば、多数のオペレーティングシステムに「curl」コマンドがあらかじめインストールされています。Things Cloud APIのブラウジングを開始したい場合、以下のコマンドラインが基本となります。

$ curl -u <username>:<password> https://<yourTenant>.je1.thingscloud.ntt.com/platform

<username><password> を、自分がThings Cloudに登録する際に使用するユーザー名とパスワードに書き換えます。同様に、<yourTenant>を、テナント名に書き換えます。

このコマンドはThings Cloudのあらゆる基本インターフェースにリンクを返します。

...
"inventory": {
    "managedObjects": {
        "references": [],
        "self": "https://<yourURL>/inventory/managedObjects"
    },
    "managedObjectsForFragmentType": "https://<yourURL>/inventory/managedObjects?fragmentType={fragmentType}",
    "managedObjectsForListOfIds": "https://<yourURL>/inventory/managedObjects?ids={ids}",
    "managedObjectsForType": "https://<yourURL>/inventory/managedObjects?type={type}",
    "self": "https://<yourURL>/inventory"
},
...

出力形式をもっと整えたい場合、curl … | python -mjson.toolを試してみてください。

$ curl -u <username>:<password> https://<yourTenant>.je1.thingscloud.ntt.com/platform | python -m json.tool

この時点より、返されるさまざまなオブジェクトへ移動することができます。例えば、managedObjectsエンドポイントに従って、インベントリ内の項目を取得できます。

$ curl -u <username>:<password> https://<yourTenant>.je1.thingscloud.ntt.com/inventory/managedObjects

インベントリ内の項目のサブセットが実際に返されることが分かります。これが所謂「ページ」です。ページについての詳細はThings Cloud OpenAPI仕様のRESTの用法 > クエリ結果のページングをご覧ください。

Postmanの使用

RESTインターフェースやThings Cloudデータベースのコンテンツを探索する場合、PostmanのようなグラフィカルRESTクライアントが便利です。

Example REST client

Software AG 社から多くの API コマンドのサンプルが提供されています。利用する場合、Postman をダウンロードしてインストール してください。Postman を開始した後、create an account または、Take me straight to the app を選べます。

Run in Postman

では、最上段のタブにある Collections をクリックしてください。Things Cloud API というフォルダがサンプルと共に表示されているはずです。そのフォルダとサブフォルダ Alarms を開き、Get collection of alarms をクリックしてください。これで Things Cloud からどのようにアラームを取得するかの例が示されます。

例にはプレースホルダーが含まれていることに注意してください。この例では、 {{url}}/alarm/alarms の {{url}} がプレースホルダーです。 Postmanにこれらのプレースホルダーの埋め方と、Things Cloudのアカウントへの接続方法を指定する必要があります。そのためには、environment を作成し、プレースホルダーを設定してください。

Postman environment setup

例えば、テナント ID がt07007007、ユーザー名がWinter、パスワードがjh0nS0nwであるとします。authキーの正しい値を判断する簡単な方法は、次のように Base64 コマンドを使用することです。

$ echo -n t07007007/winter:jh0nS0nw | base64

結果のテキストは「dDA3MDA3MDA3L3dpbnRlcjpqaDBuUzBudw==」であり、authキーの値としてBasic dDA3MDA3MDA3L3dpbnRlcjpqaDBuUzBudw==を使用する必要があります。 オンラインの Base64 エンコード/デコード ツールを使用しても、同じ結果を得ることができます。

色々なAPI を使ってみましょう。

アプリケーションの開発

本セクションでは、アプリケーション開発向けにThings Cloud REST APIを使用する場合の基本的なユースケースを簡単に説明します。

基本ユースケース

アセットの登録

アセットとは、あなたのビジネスとアプリケーションが対象としているオブジェクトのことです。例えば、主にビル管理またはホームオートメーションのビジネスを展開する場合、アセットはビルや部屋になります。または、機器の修理に関するビジネスであれば、アセットは経路や機器となるでしょう。

アセットはデバイスとともにインベントリに保存されますが、多くの場合、デバイスに依存しない独自の構造を持っています。アセットを作成するには、インベントリ内のマネージドオブジェクトのコレクションにPOSTし作成します。例えば、インベントリに新たな建物を作成するには、次のように入力します。

POST /inventory/managedObjects
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json
Accept: application/vnd.com.nsn.cumulocity.managedobject+json
Authorization: Basic ...
{
    "name": "Building 043",
    "type": "c8y_Building"
}

レスポンス:

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json;charset=UTF-8;ver=0.9
...

デバイス(アセット)が正常に作成された場合は、ステータスコード201が返されます。上記の例のように、元のリクエストに「Accept」ヘッダーが含まれている場合は、今後のリクエストでオブジェクトを参照するためのIDとURLを含む、完全なオブジェクトが返却されます。返されるオブジェクトには、デバイスに子を追加するために使用できる子デバイスおよび子アセットへの参照も含まれます。

例えば、部屋も作成し、その部屋の「self」プロパティが「https://…/inventory/managedObjects/2549700」である場合、部屋を建物にリンクするには、建物の子アセットコレクション(上記の「childAssets」の「self」プロパティ参照)にPOSTします。

POST /inventory/managedObjects/2549800/childAssets HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectreference+json
{

ここで建物を再度取得すると、部屋が建物の子として登録されていることが分かります。

GET /inventory/managedObjects/2549800

レスポンス:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json; charset=UTF-8; ver=0.9
...

デバイスとアセットのリンク

アセットを他の子アセットにリンクするのと同様に、アセットをモニタリングおよび制御するデバイスにリンクすることもできます。例えば、部屋に光センサーが設置されており、その光センサーのURLが「https://…/inventory/managedObjects/2480500」であるとします。次のように、部屋のchildDevicesにPOSTします。

POST /inventory/managedObjects/2549700/childDevices
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectreference+json
{
    "managedObject" : {
        "self" : "https://.../inventory/managedObjects/2480500"
    }
}

アセットと外部システムとの同期

多くの場合、企業のアセットを扱うITシステムはThings Cloudだけではありません。外部ITシステムに格納されているアセットの同期の手順は、デバイスの登録手順とまったく同じです。

特定の機能のクエリ

アプリケーションを特定のタイプのデバイスの仕様から切り離すために、アプリケーションはフラグメントを使用してインベントリに問い合わせることができます(Things Cloud のドメインモデルのフラグメントのセクションをご覧ください)。たとえば、位置情報を持つすべてのマネージドオブジェクトを検索するには、以下を使用します。

GET /inventory/managedObjects?fragmentType=c8y_Position&withTotalPages=true

レスポンス:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectcollection+json; charset=UTF-8; ver=0.9
...

例えば、プロパティのc8y_Position を使用して、地図上にオブジェクトを配置することができます。標準フラグメントは、デバイス管理ライブラリセンサー・ライブラリで定義されています。

/platform リソースにクエリすると、さらにどのようなデータをクエリすることができるかがわかります(「デバイスSDKガイド」の RESTデバイスインテグレーションをご覧ください)。

クエリは必ずしもすべての結果を一度に返すわけではなく、1ページ分の結果のみを返すことに注意してください。ページングの詳細については、Things Cloud OpenAPI仕様のREST implementation > RESTの用法 >クエリ結果のページングをご覧ください。オプションパラメータwithTotalPagesを指定すると、クエリにページ全体の統計情報が含まれますが、パフォーマンスは多少低下します。

センサーデータのクエリ

インベントリと同様に、特定のセンサーデータを取得することもできます。例えば、前月(この文章の執筆時点から)の光センサーメジャーメントを次のようにクエリすることができます。

GET /measurement/measurements?dateFrom=2019-04-01&dateTo=2019-05-31&fragmentType=c8y_LightMeasurement

レスポンス:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.measurementcollection+json; charset=UTF-8; ver=0.9
...

オペレーションをデバイスへ送信

デバイスのオペレーションをトリガーするには、オペレーションをデバイス制御APIへPOSTします。次の例では、ID「2480300」のデバイスを再起動します(デバイスSDKガイド内のデバイス統合で統合されているRaspberry Pi)。

POST /devicecontrol/operations
Content-Type: application/vnd.com.nsn.cumulocity.operation+json;
Accept: application/vnd.com.nsn.cumulocity.operation+json;
{
    "deviceId": "2480300",
    "c8y_Restart":{}
}

レスポンス:

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.operation+json; charset=UTF-8; ver=0.9
...

POSTコマンドは、該当のデバイスに対するオペレーションを作成した後、その作成結果を即座に返します。オペレーションの作成と実行は非同期です。リクエスト例でオプションの「Accept」ヘッダーを追加したので、レスポンスにおいてはselfプロパティにおけるURLを含む、すべての発行済オペレーションを取得することになります。そのURLに対してGETを使用すると、以下の通り、現在のオペレーション実行状態をチェックすることができます。

GET /devicecontrol/operations/2550200 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.operation+json; charset=UTF-8; ver=0.9
{
    "status": "PENDING",
    ...
}

ここでの「PENDING」ステータスとは、デバイスがまだオペレーションを受け取っていないことを意味します。「EXECUTING」は、デバイスがオペレーションを実行中であることを意味します。最後に、「SUCCESSFUL」または「FAILED」は、オペレーションが完了したことを示します。

イベントの応答を受信する

Things Cloudデータストアへの問い合わせに加え、Things Cloudにおけるリアルタイム処理に記載の通り、イベントをリアルタイムで処理/受信することもできます。例えば、リアルタイムの位置更新情報をマップに表示させたいと想定しましょう。この場合、管理アプリケーション(またはREST API)を使用して、「myRule」という新しいルールモジュールを作成します。

select *
from EventCreated e
where e.event.type = "c8y_LocationUpdate";

位置情報の更新を送信するデバイスをお持ちの場合、ユーザーインターフェースに即座に表示されるはずです。自分のRESTクライアントでこれらを受け取りたい場合、リアルタイム通知APIを使ってそれらにチャネル接続できるようにします。このAPIは、HTTPSロングポーリングを使用したBayeuxプロトコルに基づいています。適用される制限については、リアルタイム通知 APIをご覧ください。まず、ハンドシェイクが必要です。ハンドシェイクは、クライアントが通知のためにサポートするプロトコルを Things Cloud に伝え、クライアントにクライアントIDを割り当てる機能です。

POST /cep/notifications
Content-Type: application/json
...
[ {
    "id": "1",
    "supportedConnectionTypes": ["long-polling"],
    "channel": "/meta/handshake",
    "version": "1.0"
} ]

HTTP/1.1 200 OK
...
[ {
    "id": "1",
    "supportedConnectionTypes": ["long-polling"],
    "channel": "/meta/handshake",
    "version": "1.0",
    "clientId": "71fjkmy0495rxrkfcmp0mhcev1",
    "minimumVersion": "1.0",
    "successful": true
}]

ハンドシェイクの後、クライアントは上記のルールの出力にチャネル接続する必要があります。これは、モジュール名とステートメント名を接続チャネルとして持つPOSTリクエストを使用して行われます。次の例では、モジュール名に「myRule」を使用し、selectステートメント(@Name(''))に名前を付与していませんので、接続チャネルは「/myRule/*」になります。

POST /cep/notifications
Content-Type: application/json
...
[ {
    "id": "2",
    "channel": "/meta/subscribe",
    "subscription": "/myRule/*",
    "clientId": "71fjkmy0495rxrkfcmp0mhcev1"
}]

HTTP/1.1 200 OK
...
[ {
    "id":"2",
    "channel": "/meta/subscribe",
    "subscription": "/myRule/*",
    "successful": true,
} ]

最後に、クライアントは接続状態のまま、イベントが送られてくるのを待ちます。

POST /cep/notifications HTTP/1.1
Content-Type: application/json
...

このリクエストは、モジュールイベントが発生するまでブロックします。1つの位置更新を含むレスポンス例を紹介します。

HTTP/1.1 200 OK
...
[
    {
        "id": "139",
        "data": {
            "creationTime": "...",
            "id": "2481400",
            "self": "https://.../event/events/2481400",
            "source": {
                "id": "2480700",
                "name": "RaspPi BCM2708 0000000017b769d5 Gps eM9",
                "self": "https://.../inventory/managedObjects/2480700"
            },
            "text": "Location updated",
            "time": "...",
            "type": "c8y_LocationUpdate",
            "c8y_Position": {
                "alt": 58.34,
                "lng": 6.769717,
                "lat": 51.267259
            },
            "channel": "/myRule/*"
        },
        "id": "3",
        "successful": true,
        "channel": "/meta/connect"
    }
]