この記事はFIWAREを始めたい人の為の入門となります。手軽に始められるように簡単な例を挙げながら基本的な機能を紹介していきます。
FIWAREについて検索して資料を読んでもピンとこなくて、どこから始めたらいいかわからない人の為に書いています。
はじめに
大まかな説明
FIWAREって何なの?という説明は本当に難しいことです。私は仕事で使うことになったから勉強することになったが、最初はこれがわからないことが多くて困難でした。やっとわかってきた今だからこのように、自分の納得できる説明と始め方を記事に残すことにしました。
簡単に言うと、FIWAREとは「APIを作るプラットフォーム」です。「プラットフォーム」と言ってもピンとこないならもっと簡単に「APIを作る手段」や「APIを作るツール」と言ってもいいです。用はこれを使うことでAPIが作れること。
APIの意味がよくわからない方もいるかと思いますが、ここでの説明は割愛して、前提の知識として進めていきます。FIWAREはAPIを構築する為にあるものだから、まずAPIの意味を理解してからにしましょう。
APIを作る手段は色々ありますが、FIWAREはその一つに過ぎないです。APIも目的や機能によって色んな種類に分けられますが、FIWAREで作れるAPIは「データ連携基盤」というものです。
これも又説明必要な単語ですが、データ連携基盤は簡単にいうとデータを提供する者とデータを使う者を連携(つまりやり取りの仲介)するAPIのことです。
- データを提供する者はFIWAREのプラットフォームにデータを預かる
- データを使う者はそのプラットフォームからデータを取得する
ただしデータ連携基盤はただ連携する役目でありデータベース自体ではないので、データを保存するデータベースも別として準備する必要があります。
イメージはこんな感じです。
又、複数のデータ連携基盤を関連付けして管理することもできます。複雑になりますが、こういうイメージです。
普段APIはrails、django、springなどウェブアプリケーションフレームワークによって作られることが多いが、もし作りたいAPIがデータ連携基盤ならFIWAREを使う方が手軽に作れます。その為に特化されたプラットフォームだから。
それにFIWAREによって作られたデータ連携基盤の間の連携はレジストレーションという方法を通じて、やりやすいというメリットがあります。もしどこでもFIWAREを使っていたら標準化されて、色々単純になるでしょう。
だからFIWAREは推奨されて、今でも普及していきます。
FIWARE Orionとは
FIWAREを始める人にとって混乱しやすいのは、FIWAREの概念の曖昧さです。
実はFIWAREとはただの一つのソフトウェアやフレームワークのことではなく、色んなコンポーネントからなされるものです。
- FIWARE Orion
- FIWARE Cygnus
- FIWARE Draco
- FIWARE QuantumLeap
- FIWARE Wirecloud
- などなど
このように色んなコンポーネントがあって、目的によってこれらを組み合わせることで望んだAPIを作れます。
ただし殆どの場合、必ず使われるのはFIWARE Orionです。これはFIWAREの中心のコンポーネントとも言えます。
OrionはOrion Context Brokerとも呼ばれます。Brokerは「仲介人」という意味です。つまりOrionの役目はコンテキスト(データ、情報)のやり取りを仲介することです。
名前の由来は星座のオリオン座でしょうね。CygnusやDracoなど他のコンポーネントの名前も星座の名前が多いです。私は天文学出身なのでよく馴染んでいる名前です。
でも今オリオンというと、丁度放送中のこのアニメ……。
……全然関係ない話ですみません。
OrionはFIWAREの基本機能であり、他はFIWAREの拡張機能、と認識してもいいと思います。
以下の説明はFIWARE Orionの説明となります。この記事は入門なので、他のコンポーネントのことはここで一切触れません。FIWAREの理解はまずFIWARE Orionの理解からにしましょう。
勉強の為の資料に関して
FIWARE Orionの勉強の為に、FIWAREコミュニティの公式ドキュメントやチュートリアルがあります。
ただし私はこれを読んでも正直難しすぎて殆ど飲み込めませんでした。その後deepseekに聞いたりqiitaの記事など色んなところから情報を集めたりして整理して漸く理解できたのです。
FIWAREの入門は全然簡単なものではないのです。幸い現在ネットで関連の資料が豊富なので読み漁るのも手です。相性もあるからどの入門がいいかは一概には言えないでしょう。私のこの記事もその資料の一つになれたら嬉しいです。
NGSI v2とは
本題に入る前にもう一つ理解しておいた方がいいのはNGSIのことです。NGSIとはデータを記述する方式の一つであり、JSONの一種です。
そのNGSIは昔からあって、その後改善が行われてNGSI v2になって今広く使われています。そしてこのNGSI v2はFIWAREのデータのやり取りに使われている標準の形式となっています。
NGSI v2についてこの記事はおすすめです。
ただし、すぐちゃんと覚える必要がないと思います。「こういう書き方」だと認識しておけばいいです。
ではここから本番に入ります。
FIWARE Orionのサーバー構築と起動
FIWARE Orionを使い始める方法は色々あります。これも入門しようとする人が戸惑いやすいところの一つですね。ここで私が一番簡単だと思っている方法を採用します。それはdockerを使うという方法です。
ただしdockerの知識がなくても大丈夫です。dockerが難しいということは私も同感。私も今までdockerを使ったことありません。今回ただdockerをインストールして、コマンドを打つだけで終わりなので、本格的なdockerの理解がなくてもいいです。
dockerを使ったことないという人も多いと思いますが、やはりこれを使うと便利です。FIWARE Orionの起動はOSや環境に依存するので、手動で設定するのはかなり面倒です。そこでdockerを使うとたった2行のコマンドですぐ済みます。
まずはdockerのインストールから始めましょう。その後コマンドラインでdocker
を打ってエラーが出なければ準備完了です。
そしてコマンドラインでこれを実行したらFIWARE Orionのサーバーが起動するはずです。(ここでインターネットで設定用ファイルを取得することになるので、暫く時間がかかります)
docker run --name mongo600 -d mongo:6.0
docker run -d --name orionza --link mongo600:mongodb -p 1026:1026 telefonicaiot/fiware-orion -dbURI mongodb://mongo600
起動した後、ちゃんと動いているかブラウザでこのURLにアクセスして確認できます。
http://localhost:1026/v2
もしこのようなJSONが現れたら、成功です。
{"entities_url":"/v2/entities","types_url":"/v2/types","subscriptions_url":"/v2/subscriptions","registrations_url":"/v2/registrations"}
若しくは、Pythonのrequestsを使って同様なことをすることもできます。
import requests,json
url = "http://localhost:1026/v2"
res = requests.get(url)
print(res) # 応答コードを表示
# わかりやすいjson形式で表示
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
<Response [200]>
{
"entities_url": "/v2/entities",
"types_url": "/v2/types",
"subscriptions_url": "/v2/subscriptions",
"registrations_url": "/v2/registrations"
}
ここに表示されたのは、ただこれから使うAPIのルーティングの一部です。
URLにv2
がありますが、これはNGSI v2を使っているからです。だからこれからアクセスするAPIのURLは全部http://localhost:1026/v2
から始めます。
dockerの起動に使ったコマンドに関しては簡単に説明すると、1行目はmongodbのデータベースサーバーを立てる為です。FIWARE Orion自体はただの仲介するものであり、データベース自体ではないから、データを保存する為にmongodbが使われます。
そして2行目こそ本当にOrionのサーバーを立てるコマンドです。その中でmongo600
はmongodbのサーバーにつけられた任意の名前であり、好きに変えればいいです。orionza
という名前もです。
1026
はデフォルトのポート番号であり、普段はそのまま使っていいです。今回はローカルでサーバーを作ったからhttp://localhost:1026
はFIWARE Orionのサーバーとなります。
こうやって立てられたFIWARE Orionによって、これからデータベースと接続してデータを閲覧、取得、追加、削除、修正などできます。こんなイメージです。
使い始める
データを入れる
今のデータベースの中にまだ何のデータも入っていないので、まずはデータを入れることから始めます。データ追加はhttp://localhost:1026/v2/entities
のpost
メソッドでできます。
ここから先「エンティティ」entity
/ entities
という単語がよく出てきますが、これは簡単に説明できる概念ではないので、見ていって自分で理解するしかないと思いますが、さっくりいうと「エンティティ」とはFIWAREにおいて「取り扱うデータの塊」と認識してもいいでしょう。つまりデータは「エンティティ」という形で扱われます。具体的にどんなものなのか例を読んでいくとわかってくると思います。
このhttp://localhost:1026/v2/entities
はその名の通りエンティティを扱う為のURLです。post
でエンティティを1つ追加することになります。
ただしpost
に使うデータNGSI v2形式のJSONです。ここで書きやすいようにPythonでやりますが、cURLなど他の方法でも勿論いいです。実は公式サイトの例などでも主にcURLを使っているのですが、正直わかりづらいです。
Pythonの方がJSONとほぼ同じ書き方ができて、NGSIを扱う時直感的でわかりやすいはずだと思うのでPythonで説明することにします。ここでただリクエストを作る手段としてPythonを使うだけでPythonは必須ではなく、自分の使いしやすい方法を選べばいいです。大事なのは特定のURLに適切なデータでリクエストを送ることです。
では、次のコードは「駅」の簡単データを登録する例となります。
import requests
url = "http://localhost:1026/v2/entities"
data_dic = {
"id": "hakataeki",
"type": "Eki",
"namae": {"value": "博多駅"},
"ido": {"value": 33.590000},
"keido": {"value": 130.420611}
}
res = requests.post(url,json=data_dic)
print(res)
リクエストの結果として201
が返されたら成功です。
<Response [201]>
これでデータが登録されているはずです。
エンティティのデータの構造に関して
今回の例で入れたデータについて簡単な説明をします。このデータの入れ方はNGSI v2の形式です。色んな属性を入れるが、特別なのはid
とtype
で、他の属性は任意です。
id
はそのエンティティを示す重複不可のものであり、type
はそのエンティティが何のエンティティかを説明するものです。
FIWAREでは色んなエンティティを全部扱うが、どんなデータかを区別するのはtype
です。例えば今回は駅のデータを登録したいのでtype
はEki
にします。会社のデータを入れたい時はKaisha
などの名前のtype
でもいいです。
id
もtype
もどんな名前にするかは自由ですが、使える文字は英文字a-z
A-Z
と数字0-9
と-
、_
、.
、:
のみです。type
は大文字で始めるという習慣もありますが、必須ではありません。
他の属性は特定のtype
のエンティティが持つべき値を入れる為です。例えば今回は駅の「名前」と「緯度」と「軽度」3つ入れました。id
もtype
と違って、書き方は"属性名": {"value": "属性の値"}
という形になって面倒に見えますが、それは属性はただの値だけではなく、データ型やメタデータの情報も入れられるからです。これについて後でもっと詳しく説明します。
データ追加の失敗例
データ登録は色んな原因によって失敗で終わる可能性があります。その時エラーメッセージが返されて原因をわかることができます。
例えばid
に使ってはいけない文字が入っている場合です。
import requests
url = "http://localhost:1026/v2/entities"
data_dic = {"id": "東京駅?"}
res = requests.post(url,json=data_dic)
print(res,res.text)
<Response [400]> {"error":"BadRequest","description":"Invalid characters in entity id"}
こうやってデータ追加が成功かどうかわかりますね。
入れたデータを表示してみる
http://localhost:1026/v2/entities
に普通のgetでアクセスしたら全てのエンティティが表示されます。
今データを入れたから、ブラウザなどでhttp://localhost:1026/v2/entities
にアクセスしてみたら入れられたデータが表示されるはずです。ここで綺麗で読みやすい形で表示する為にPythonを使います。
import requests,json
url = "http://localhost:1026/v2/entities"
res = requests.get(url)
print(res)
# 取得できたデータ
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
# ヘッダー
print(json.dumps(dict(res.headers),indent=2,ensure_ascii=False))
<Response [200]>
[
{
"id": "hakataeki",
"type": "Eki",
"ido": {
"type": "Number",
"value": 33.59,
"metadata": {}
},
"keido": {
"type": "Number",
"value": 130.420611,
"metadata": {}
},
"namae": {
"type": "Text",
"value": "博多駅",
"metadata": {}
}
}
]
{
"Date": "Sat, 8 Mar 2025 10:39:39 GMT",
"Fiware-Correlator": "8387bc64-ef98-11ef-9ada-0242ac110003",
"Content-Type": "application/json",
"Content-Length": "202"
}
出てきたエンティティは最初に入れたそのものですが、少し余計な部分が入っていますね。それは各属性のtype
とmetadata
です。紛らわしいですが、属性のtype
はエンティティのtype
とは別物です。属性のtype
はどんなデータ型かを示すものです。エンティティ登録の時にわざわざtype
を入れなくてもText
かNumber
か適切に決められるから今回はvalue
だけ入れました。
ただし実際にtype
の名前は絶対ではなく、自分が勝手に作った任意のtype
でも何でもいいです。それに基本的にFIWARE Orion自体ではtype
が考慮されません。例えば文字列なのに"type": "Number"
にしてもエラーが出ません。
だから属性のtype
はただ区別する為のものだと思ってもいいです。しかし一部のFIWAREの追加機能ではtype
が使われることもあります。
metadata
に関してはただの追加で入れられる情報です。なくてもいいので、今回はとりあえず使いません。詳しい説明も割愛します。
指定のIDのエンティティの処理
1つのエンティティの情報を表示
entities/{エンティティID}
へget
したら指定のIDのエンティティを取得することになります。
import requests,json
url = "http://localhost:1026/v2/entities/hakataeki"
res = requests.get(url)
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
{
"id": "hakataeki",
"type": "Eki",
"ido": {
"type": "Number",
"value": 33.59,
"metadata": {}
},
"keido": {
"type": "Number",
"value": 130.420611,
"metadata": {}
},
"namae": {
"type": "Text",
"value": "博多駅",
"metadata": {}
}
}
このAPIには色んなパラメータを入れることで表示がかわるので紹介していきます。
表示の形式を調整
options
というパラメータにkeyValues
を入れることで属性の表示は簡潔になります。つまりtype
とmetadata
が省略されます。これはよく使われて便利です。
import requests,json
url = "http://localhost:1026/v2/entities/hakataeki"
param_dic = {"options": "keyValues"}
res = requests.get(url,params=param_dic)
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
{
"id": "hakataeki",
"type": "Eki",
"ido": 33.59,
"keido": 130.420611,
"namae": "博多駅"
}
表示する属性を選ぶ
attrs
パラメータに属性名を入れたらその他の属性が表示されなくなります。複数の属性が欲しい場合はカンマ,
で挟みます。ただしid
とtype
は指定しなくても常に表示されます。
import requests,json
url = "http://localhost:1026/v2/entities/hakataeki"
param_dic = {"options": "keyValues", "attrs": "ido,keido"}
res = requests.get(url,params=param_dic)
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
{
"id": "hakataeki",
"type": "Eki",
"ido": 33.59,
"keido": 130.420611
}
エンティティを削除
entities/{エンティティID}
にdelete
メソッドを使ったらそのIDエンティティを消すことになります。これは1つのエンティティを削除する基本的な方法となります。
import requests
url = "http://localhost:1026/v2/entities/hakataeki"
res = requests.delete(url)
print(res)
削除が成功したら204
が返されます。
<Response [204]>
エンティティの属性の処理
属性を追加
entities/{エンティティID}/attrs
で指定のIDのエンティティの属性を弄ることになります。まずpost
メソッドで新しい属性を追加することができます。
例えば新しいエンティティを追加してからそのエンティティに新しい属性を追加してみます。
import requests,json
url = "http://localhost:1026/v2/entities"
data_dic = {
"id": "hakataramen",
"type": "Ramen",
"namae": {"value": "博多ラーメン"}
}
res = requests.post(url,json=data_dic)
url = "http://localhost:1026/v2/entities/hakataramen/attrs"
data_dic = {"nedan": {"value": 290}}
res = requests.post(url,json=data_dic)
url = "http://localhost:1026/v2/entities/hakataramen"
res = requests.get(url,params={"options": "keyValues"})
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
{
"id": "hakataramen",
"type": "Ramen",
"namae": "博多ラーメン",
"nedan": 290
}
今回のエンティティは「ラーメン」です。まず属性は名前だけ入れたが、その後「値段」を追加しました。因みに290円という値段は本当に存在します!。
尚このentities/{エンティティID}/attrs
のpostは既存の名前の所属を入れても問題ありません。その場合属性が書き換えられます。複数入れることもできます。
属性の値を取得
entities/{エンティティID}/attrs
のget
メソッドで指定のIDのエンティティの全部の属性が見られます。ただしエンティティのid
とtype
が表示されません。"options": "keyValues"
で値だけ表示することもできます。
import requests,json
url = "http://localhost:1026/v2/entities/hakataramen/attrs"
res = requests.get(url,params={"options": "keyValues"})
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
{
"namae": "博多ラーメン",
"nedan": 290
}
特定の属性だけ欲しい場合はentities/{エンティティID}/attrs/{属性名}
でもいいです。
import requests,json
url = "http://localhost:1026/v2/entities/hakataramen/attrs/nedan"
res = requests.get(url,params={"options": "keyValues"})
print(json.dumps(res.json()))
{"nedan": 290}
属性を更新
一つだけの属性を更新
entities/{エンティティID}/attrs/{属性名}
のpatch
メソッドで指定のIDのエンティティのその属性を更新することができます。
import requests,json
data_dic = {"value": 440}
url = "http://localhost:1026/v2/entities/hakataramen/attrs/nedan"
res = requests.put(url,json=data_dic)
url = "http://localhost:1026/v2/entities/hakataramen/attrs"
res = requests.get(url,params={"options": "keyValues"})
# 更新した後の結果を見る
print(json.dumps(res.json(),ensure_ascii=False))
{"namae": "博多ラーメン", "nedan": 440}
複数の属性を更新/追加
上で書きましたが、entities/{エンティティID}/attrs
のpost
メソッドで既存の属性に使うこともできます。その場合は追加ではなく、更新となります。しかも同時に複数の属性の追加と更新ができます。
import requests,json
url = "http://localhost:1026/v2/entities/hakataramen/attrs"
data_dic = {
"nedan": {"value": 600},
"kcal": {"value": 358}
}
res = requests.post(url,json=data_dic)
url = "http://localhost:1026/v2/entities/hakataramen/attrs"
res = requests.get(url,params={"options": "keyValues"})
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
{
"kcal": 358,
"namae": "博多ラーメン",
"nedan": 600
}
属性を削除
entities/{エンティティID}/attrs/{属性名}
のdelete
メソッドで指定の属性を削除することができます。
import requests
url = "http://localhost:1026/v2/entities/hakataramen"
res = requests.delete(url)
print(res)
<Response [204]>
エンティティのタイプに関して
登録された全部のタイプを取得
上述でも説明しましたが、FIWAREにおいてエンティティのtype
はエンティティを区別する為の存在です。同時に色んなエンティティを入れることができるからどんなエンティティか区別することが重要となります。
今までどんなtype
のエンティティが登録されているかhttp://localhost:1026/v2/types
で調べられます。(このAPIは読み取り専用なのでget
メソッドしかない)
これでそのtype
のエンティティの属性まで表示されますが、type
の名前だけ欲しい場合はパラメータに{"options": "values"}
入れます。
違うタイプで同じIDを持つエンティティの問題
本来エンティティのid
は重複不可であるべきですが、実はtype
が違ったらid
が重複でも大丈夫です。だから実際に「type
とid
が同時に重複は不可」と言った方が正しいです。
試しに同じid
を持つ違うtype
のエンティティ2つ追加してtype
一蘭を見てみます。
import requests,json
url = "http://localhost:1026/v2/entities"
data_dic = {
"id": "kaizukaeki",
"type": "NishitetsuEki",
"namae": {"value": "貝塚駅"}
}
res = requests.post(url,json=data_dic)
data_dic = {
"id": "kaizukaeki",
"type": "ChikatetsuEki"
}
res = requests.post(url,json=data_dic)
url = "http://localhost:1026/v2/types"
res = requests.get(url)
print(json.dumps(res.json(),indent=2))
# タイプの名前だけ取得
res = requests.get(url,params={"options": "values"})
print(json.dumps(res.json()))
[
{
"type": "ChikatetsuEki",
"attrs": {},
"count": 1
},
{
"type": "NishitetsuEki",
"attrs": {
"namae": {
"types": [
"Text"
]
}
},
"count": 1
}
]
["ChikatetsuEki", "NishitetsuEki"]
このように同じkaizukaeki
というid
を持つ違うChikatetsuEki
とNishitetsuEki
というtype
のエンティティが問題なく登録されましたが、これはややこしい問題の原因になるかもしれないので、注意する必要があります。
まず、重複のid
があると、entities/{エンティティID}
でのアクセスがエラーになります。エラーコードは409
であり、「矛盾がある」ということが示されます。
import requests,json
url = "http://localhost:1026/v2/entities/kaizukaeki"
res = requests.get(url)
print(res,json.dumps(res.json(),indent=2,ensure_ascii=False))
<Response [409]> {
"error": "TooManyResults",
"description": "More than one matching entity. Please refine your query"
}
このように同じid
があってどっちなのかわからなくなるからです。その場合id
だけでなくtype
までパラメータのとして指定する必要があります。
import requests,json
url = "http://localhost:1026/v2/entities/kaizukaeki"
res = requests.get(url,params={"type": "ChikatetsuEki"})
print(res,json.dumps(res.json(),indent=2,ensure_ascii=False))
<Response [200]> {
"id": "kaizukaeki",
"type": "ChikatetsuEki"
}
こうやって指定のエンティティにアクセスすることができます。
削除する時も同様です。type
を指定しないとエラーになります。
import requests
res = requests.delete(url)
print(res) # ここでエラー
res = requests.delete(url,params={"type": "NishitetsuEki"})
print(res) # type指定したから問題ない
res = requests.delete(url,params={"type": "ChikatetsuEki"})
print(res)
<Response [409]>
<Response [204]>
<Response [204]>
要するに、違うtype
のエンティティで同じid
を持つことがないような命名をしていたらエンティティを指定する時にtype
を気にしなくてもid
を指定するだけで十分なはずですが、重複の可能性があったらいつもtype
を指定しておいたら無難でしょう。
一気に処理
複数のエンティティを追加、又は更新
大きいデータを扱う時に何件もののデータを一つずつ扱うよりも、一気にいっぱい扱った方が効果的です。その為にFIWARE Orionではop/update
のpost
メソッドが使われます。
この方法は追加も更新も削除も同じpost
メソッドを使いますが、actionType
というパラメータで区別します。追加/更新の場合は"actionType": "append"
とします。
使う例。
import requests
url = "http://localhost:1026/v2/op/update"
data_dic = {
"actionType": "append",
"entities": [
{
"id": "chashumen",
"type": "Ramen",
"namae": {"value": "チャーシューメン"},
"nedan": {"value": 900}
},
{
"id": "chahan",
"type": "Gohan",
"namae": {"value": "チャーハン"},
"nedan": {"value": 750}
}
]
}
res = requests.post(url,json=data_dic)
print(res)
<Response [204]>
これで2つのエンティティが一気に追加されます。追加したいエンティティのデータはこのように"entities": [ ]
というリストの形で入れます。
今回まだ存在していないから追加となりましたが、指定のid
のエンティティが既存の場合はそのid
のエンティティを書き換えることになります。
複数のエンティティの属性を更新
既存のエンティティの更新は"actionType": "append"
の他に、"actionType": "update"
も使えます。ただしappend
の場合が新しいエンティティに入れ替えられるのに対し、update
はただ指定の属性を更新するだけとなります。指定されていない属性はそのまま。
import requests,json
url = "http://localhost:1026/v2/op/update"
data_dic = {
"actionType": "update",
"entities": [
{
"id": "chashumen",
"nedan": {"value": 950}
},
{
"id": "chahan",
"nedan": {"value": 800}
}
]
}
res = requests.post(url,json=data_dic)
# 変更した後の結果を見てみる
url = "http://localhost:1026/v2/entities"
res = requests.get(url,params={"options": "keyValues"})
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
[
{
"id": "chashumen",
"type": "Ramen",
"namae": "チャーシューメン",
"nedan": 950
},
{
"id": "chahan",
"type": "Gohan",
"namae": "チャーハン",
"nedan": 800
}
]
複数のエンティティを削除
"actionType": "delete"
で指定の複数のid
のエンティティを削除することができます。
import requests
url = "http://localhost:1026/v2/op/update"
data_dic = {
"actionType": "delete",
"entities" :[
{"id": "chashumen"},
{"id": "chahan"}
]
}
res = requests.post(url,json=data_dic)
print(res)
<Response [204]>
エンティティ取得のオプション
件数を取得
最初から説明したhttp://localhost:1026/v2/entities
のget
ですが、実は色んなパラメータによって表示の調整ができるので、ここで補足します。
例えば"options": "count"
を入れたら応答のヘッダーの中にエンティティの数が表示されます。どれくらいあるか知りたい時に使うと便利です。
例えばいっぱいエンティティを追加して数を表示させてみます。今回その為にPythonのfor
ループを使いますが、詳しくは割愛します。要はこれで「x1, x2, x3, ..., x1003, x1004」というid
を持つ1004個のエンティティをop/update
によって追加します。
import requests,json
url = "http://localhost:1026/v2/op/update"
entity_list = [{"id": f"x{i}", "type": "X"} for i in range(1,1005)]
data_dic = {
"actionType": "append",
"entities" : entity_list
}
res = requests.post(url,json=data_dic)
url = "http://localhost:1026/v2/entities"
res = requests.get(url,params={"options": "count"})
# ヘッダーを表示
print(json.dumps(dict(res.headers),indent=2))
{
"Date": "Sat, 8 Mar 2025 13:04:40 GMT",
"Fiware-Correlator": "93d0daa2-f11d-11ef-86de-0242ac110003",
"Fiware-Total-Count": "1004",
"Content-Type": "application/json",
"Content-Length": "472"
}
正規表現でIDやタイプから検索
一部のid
の名前のパターンを持つエンティティだけ欲しい場合はidPattern
というパラメータを使うことでできます。パターンは正規表現で書きます。
前の例において追加されたエンティティで例を挙げます。
import requests,json
url = "http://localhost:1026/v2/entities"
res = requests.get(url,params={"idPattern": "x50.*"})
print(json.dumps(res.json()))
[{"id": "x50", "type": "X"}, {"id": "x500", "type": "X"}, {"id": "x501", "type": "X"}, {"id": "x502", "type": "X"}, {"id": "x503", "type": "X"}, {"id": "x504", "type": "X"}, {"id": "x505", "type": "X"}, {"id": "x506", "type": "X"}, {"id": "x507", "type": "X"}, {"id": "x508", "type": "X"}, {"id": "x509", "type": "X"}]
同じようにtype
の名前で絞りたい場合はtypePattern
が使われます。
ページング
limit
パラメータは表示されるエンティティの数を指定するものとなります。ただし既定値は20となっています。つまり普段特に指定しない限りどれくらい沢山エンティティを持っていても20しか表示されません。又、limit
は最大1000でそれ以上入れても1000しか出てきません。
offset
というパラメータで何番目から表示されるか指定することができます。limit
とoffset
を一緒に使うことでページ分けでエンティティを表示することができます。
使う例。
import requests,json
url = "http://localhost:1026/v2/entities"
res = requests.get(url,params={"limit": 4})
print(json.dumps(res.json()))
res = requests.get(url,params={"limit": 4, "offset": 8})
print(json.dumps(res.json()))
[{"id": "x1", "type": "X"}, {"id": "x2", "type": "X"}, {"id": "x3", "type": "X"}, {"id": "x4", "type": "X"}]
[{"id": "x9", "type": "X"}, {"id": "x10", "type": "X"}, {"id": "x11", "type": "X"}, {"id": "x12", "type": "X"}]
尚"options": "count"
を使った場合のヘッダーの中ではこのlimit
と関係なく常に実際の数が表示されます。
[幕間]エンティティを全部削除
全部エンティティを削除するという便利な方法はFIWARE Orionの中で準備されていないらしいですが、今まで勉強した知識を使って、APIの組み合わせによって実装のコードが書けるでしょう。例えばPythonではこんな感じで書けばいいです。
import requests
while 1:
url = "http://localhost:1026/v2/entities"
# 最大の1000件でエンティティのIDを取得
res = requests.get(url,params={"attrs": "id", "limit": 1000})
entity_list = res.json()
# エンティティが存在しない、又は何かのエラーが出た場合はもう終わりでいい
if(res.status_code!=200 or len(entity_list)==0):
break
# 取得したエンティティのIDを入れて削除を行う
url = "http://localhost:1026/v2/op/update"
data_dic = {
"actionType": "delete",
"entities" : entity_list
}
res = requests.post(url,json=data_dic)
並べ替え
基本的に追加した順でエンティティが表示されますが、orderBy
パラメータで順番の基準にしたい属性を指定することができます。
例えばランダムのr
という属性を持つエンティティを追加して、その順で表示させてみます。
import requests,random
url = "http://localhost:1026/v2/op/update"
entity_list = []
for i in range(1,6):
entity = {
"id": f"r{i}",
"type": "R",
"r": {"value": random.random()}
}
entity_list.append(entity)
data_dic = {
"actionType": "append",
"entities" : entity_list
}
res = requests.post(url,json=data_dic)
url = "http://localhost:1026/v2/entities"
res = requests.get(url,params={"orderBy": "r", "options": "keyValues"})
print(res.text)
# "!"を入れたら上からの順になる
res = requests.get(url,params={"orderBy": "!r", "options": "keyValues"})
print(res.text)
[{"id":"r3","type":"R","r":0.022399299},{"id":"r2","type":"R","r":0.18084051},{"id":"r4","type":"R","r":0.325210582},{"id":"r1","type":"R","r":0.332001331},{"id":"r5","type":"R","r":0.746004846}]
[{"id":"r5","type":"R","r":0.746004846},{"id":"r1","type":"R","r":0.332001331},{"id":"r4","type":"R","r":0.325210582},{"id":"r2","type":"R","r":0.18084051},{"id":"r3","type":"R","r":0.022399299}]
クエリーで検索
q
というパラメータで指定の条件でエンティティを絞り込むことができます。使い方は色々ありますが、今回は例として数値の属性の値の範囲で絞り込むことを試してみます。
import requests,json
# まずはテストに使うデータを追加
url = "http://localhost:1026/v2/op/update"
data_dic = {
"actionType": "append",
"entities" :[
{
"id": "kitsunedon",
"type": "Donburi",
"namae": {"value": "きつね丼"},
"nedan": {"value": 650}
},
{
"id": "tanindon",
"type": "Donburi",
"namae": {"value": "他人丼"},
"nedan": {"value": 700}
},
{
"id": "tentojidon",
"type": "Donburi",
"namae": {"value": "天とじ丼"},
"nedan": {"value": 800}
}
]
}
res = requests.post(url,json=data_dic)
# 検索
url = "http://localhost:1026/v2/entities"
res = requests.get(url,params={"q": "nedan<=700", "options": "values"})
print(json.dumps(res.json(),ensure_ascii=False))
[["きつね丼", 650], ["他人丼", 700]]
ここでnedan<=700
は要するに「値段は700以下」という条件となります。
[幕間]dockerの補足
サーバーの停止、起動、削除
ここまであまり説明せずに最初からdockerで立てたFIWARE Orionサーバーでやっていたのですが、ここでこう少し補足します。
今起動して使用していたサーバーを止めるにはこのコマンドを打つのです。
docker stop orionza
docker stop mongo600
これは一時的な停止となって、もう一度起動したいならこれを打つといいです。
docker start mongo600
docker start orionza
永遠に消したい場合はrm
を使います。ただしこれはstop
した状態でないとエラーになります。
docker rm orionza
docker rm mongo600
これを使うとmongodbに保存されたエンティティのデータも削除されて取り戻すことができなくなるので注意です。
docker-composeを使うという方法
今まで使っていた方法の他にもう一つの使い方をここで紹介しておきたいです。
まずこのようなymlファイルを作っておくのです。
services:
orionza:
image: telefonicaiot/fiware-orion
ports:
- "1026:1026"
depends_on:
- mongo600
command: -dbURI mongodb://mongo600
mongo600:
image: mongo:6.0
command: --nojournal
書き方については割愛しますが、簡単にいうとymlでサーバーに関する設定をここに書いたのです。そしてこのymlを使ってこのように実行したら上の方法と同じようにサーバーが建てられます。
docker compose -f docker-compose.yml up -d
サーバーを止めて消したい時はこれを打つのです。
docker compose -f docker-compose.yml down
この方法を使うと、作りたいサーバーの設定は一つのファイルに纏められて使いやすいです。今回はただFIWARE Orionとmongodbの2つしかないのですが、特に沢山のサーバーを同時にある場合この方法を使った方が便利だというのは明らかになるでしょう。
次に説明する機能もそうだから、予めこれを説明しておくことにしました。
レジストレーション
レジストレーションの概要
FIWAREの中でレジストレーション(registration)というのは、別のデータ連携基盤からデータを取得することで複数のデータベースを連携する機能です。
例えば2のデータベースmongo-aとmongo-bを管理する2つのデータ連携基盤orion-aとorion-bがあるとしましょう。とあるデータ利用者はmongo-bの中のデータが欲しい場合、普段ならorion-bに対して要求を送る必要がありますが、もしorion-aがorion-bに対してレジストレーションをしておいたら、データ利用者はorion-aに要求を送ることでそのデータを取得することができます。
イメージとしてはこんな感じです。
このように、FIWAREサーバーがレジストレーションで繋がっているから一つのFIWAREサーバーに接続することで他のFIWAREサーバーのデータも入手できます。その為の仕組みです。
2つのサーバーの準備
レジストレーション機能を実際に使ってみる為にはまず2つのサーバーを立てます。今回はdocker-composeで準備します。このようなymlファイルを使います。
services:
orion-a:
image: telefonicaiot/fiware-orion
ports:
- "1026:1026"
depends_on:
- mongo-a
command: -dbURI mongodb://mongo-a
mongo-a:
image: mongo:6.0
command: --nojournal
orion-b:
image: telefonicaiot/fiware-orion
ports:
- "1027:1026"
depends_on:
- mongo-b
command: -dbURI mongodb://mongo-b
mongo-b:
image: mongo:6.0
command: --nojournal
そしてこれを実行したら準備完了です。
docker compose -f docker-compose.yml up -d
ここでorion-aはデータ利用者が直接にやり取りするサーバーとして、orion-bが対象のデータが保存されてレジストレーションを通じて接続するサーバーとします。
こうやって2つのサーバーは立てられますが、デフォルトの1026ポートは1つのサーバーにしか使えないので、ここで2つ目のサーバーは1027を使います。
http://localhost:1027/v2
でアクセスできます。
このように複雑になりますが、本番では2つのサーバーはこのように同じパソコンではなく、ちゃんと物理的に違う場所にあるはずなので設定は又別に違うでしょう。
レジストレーションを追加
準備が整ったら次は実際に使ってみます。レジストレーションを追加するにはhttp://localhost:1026/v2/registraions
のpost
メソッドを使います。
import requests
url = "http://localhost:1026/v2/registrations"
data_dic = {
"description": "ラーメンデータの連携",
"dataProvided": {
"entities": [
{
"idPattern": ".*",
"type": "Ramen"
}
],
"attrs": ["namae"]
},
"provider": {
"http": {
"url": "http://orion-b:1026/v2"
}
}
}
res = requests.post(url,json=data_dic)
print(res)
<Response [201]>
そしてデータをorion-bの方に入れておきます。
import requests
url = "http://localhost:1027/v2/op/update"
data_dic = {
"actionType": "append",
"entities": [
{
"id": "tonkotsuramen",
"type": "Ramen",
"namae": {"value": "とんこつラーメン"},
"nedan": {"value": 650}
},
{
"id": "misoramen",
"type": "Ramen",
"namae": {"value": "みそラーメン"},
"nedan": {"value": 750}
}
]
}
res = requests.post(url,json=data_dic)
どのエンティティを要求するかを決めるのはdataProvided
のところです。その中でentities
でtype
とid
を指定します。今回はあるtype
のあらゆるid
のエンティティが欲しいということで"idPattern": ".*"
にします。そしてattrs
を入れることで取得したい属性だけ取ることができますが、これは省略できます。その場合全部の属性が取得されます。
そしてprovider
でデータ元のサーバーのURLを指定します。
ただしここで注意して欲しいのは、データを追加する時にhttp://localhost:1027/v2
というURLにアクセスするのに対し、レジストレーションの時は"url": "http://orion-b:1026/v2"
と書いている、ということです。ややこしいですが、これはdockerを使っているからです。
実はどっちもorion-bサーバーを指すURLですが、http://orion-b:1026
はdockerの間に使うURLです。レジストレーションで通じる時にorion-aとorion-bは勝手にやり取りするので、その時このURLを使うのです。それに対しデータを追加する時はそうではないので、普通にhttp://localhost:1027/
を使います。
次は実際にデータ取得してみましょう。
import requests,json
url = "http://localhost:1026/v2/entities"
res = requests.get(url,params={"type": "Ramen", "options": "keyValues"})
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
[
{
"id": "tonkotsuramen",
"type": "Ramen",
"namae": "とんこつラーメン"
},
{
"id": "misoramen",
"type": "Ramen",
"namae": "みそラーメン"
}
]
このように無事でorion-bのデータをorion-aから取得することができました。
レジストレーションを全部表示
registrations
のget
メソッドで、追加したレジストレーションの詳細を全て表示することができます。
import requests,json
url = "http://localhost:1026/v2/registrations"
res = requests.get(url)
print(json.dumps(res.json(),indent=2,ensure_ascii=False))
[
{
"id": "67bef7f9a35f42af3e085d2f",
"description": "ラーメンデータの連携",
"dataProvided": {
"entities": [
{
"idPattern": ".*",
"type": "Ramen"
}
],
"attrs": [
"namae"
]
},
"provider": {
"http": {
"url": "http://orion-b:1026/v2"
},
"supportedForwardingMode": "all",
"legacyForwarding": false
},
"status": "active"
}
]
レジストレーションを削除
registraions/{レジストレーションID}
のdelete
メソッドレジストレーションを消すことができますが、ここでid
が必要です。しかし追加の時にid
は勝手に決められたものなので、私達はid
がわかるわけではないですね。だったらまずid
を調べた上でやるしかないでしょう。
例えば全部のレジストレーションを削除したい場合はPythonでこうしたらいいでしょう。
url = "http://localhost:1026/v2/registrations"
# レジストレーションの一蘭を取得
res = requests.get(url,params={"options": "keyValues"})
# IDだけ取って1つずつ削除する
for r in res.json():
url = "http://localhost:1026/v2/registrations/"+r["id"]
res = requests.delete(url)
終わりに
これでFIWAREの基本的な機能を一通り紹介できたと思います。それでもまだ触れていないところはいっぱいあります。全てはまだ始まったばかりです。
実はまだ沢山書きたい内容があるが、長すぎるので書くなら別の記事にします。サブスクリプションのこととか。
私は仕事でFIWAREを使うことになっているので、まだまだ勉強してFIWAREに関する記事を書いていきます。
もっと読みたい人は公式ドキュメントや下の載っている参考の記事や資料を読んでもいいと思います。
参考
FIWARE関連
- スマートシティを実現するFIWAREとは
- FIWAREとは
- 誰でもすぐに試せる初心者向けFIWARE学習コンテンツを作成した話
- 無知から学ぶFIWARE #1 ~ FIWAREってなんぞや?
- 無知から学ぶFIWARE #2 ~ GEをひとつ動かしてみる
- Fiware Orion Context Brokerに関する6つの誤解
- FIWARE エコシステムについて
- PCで FIWARE ( Orion Context Broker ) を体験する、 MIRACLE LINUX 8.4 も試してみる
- IoTプラットフォームをOSSで手軽に構築する その1
- メモ: FIWARE
- FIWARE Orion Context Broker コンテキスト情報管理 (Orion 3.6.0対応)
- データ利活用基盤サービス(FIWARE)アプリケーション開発ガイド
その他に、一部の情報とサンプルコードはdeepseekに聞いて得られたものです。