福岡市の公開データをFIWARE APIで取得してみよう!
0. はじめに:福岡市データ連携基盤と申請方法
福岡市データ連携基盤とは?
「福岡市データ連携基盤」は、福岡市がスマートシティ化に向けて構築した、行政や民間の様々な分野のデータを横断して共有・活用できる仕組み(都市OS)です。EUを中心に世界中のスマートシティで採用されているオープンソース「FIWARE(ファイウェア)」をベースにしており、屋台情報、区役所のリアルタイム混雑状況、人口統計、キッチンカーなど、幅広いデータがWeb API(NGSI v2規格)を通じて公開されています。
APIアクセスの利用申請方法
このデータ連携基盤のAPIを使って開発を行うには、事前に利用申請を行い、認証用の「アクセストークン」を発行してもらう必要があります。手続きはすべてオンラインで完結し、数日程度で利用可能になります。
利用申請書の作成
「BODIK ODCS(福岡市)」のサイトから「福岡市データ連携基盤利用登録申請書」をダウンロードし、必要事項を記入します。
オンライン申請の送信
福岡市のオンライン申請システム(グラファー)の専用フォームから、作成した申請書を添付して送信します。アカウントなしでもメール認証だけで申請可能です。
トークンとドキュメントの受取
申請が承認されると、数日以内にAPIアクセスに必要な「アクセストークン(WSO2)」と詳細な仕様書が送られてきます。準備はこれで完了です!
それでは、手元にトークンが用意できた前提で、具体的なAPIの仕組みと使い方を見ていきましょう。
1. FIWAREって何?普通のAPIと何が違うの?
FIWAREは、スマートシティ向けのオープンソース基盤です。EU主導で開発され、世界中の自治体・行政がIoTデータや都市データを管理するために採用しています。その中心となるのが Context Broker(Orion)というサーバーで、「今この瞬間の状態」を管理することが得意です。
普通のREST APIと比べて何が違うのか、ざっくりまとめると:
普通のREST API
「リソース」単位でエンドポイントが決まる。例:/users、/products。設計はサービスごとに自由。
FIWARE(NGSI v2)
「エンティティ(Entity)」という統一された概念でデータを管理。屋台も人口も同じ /entities エンドポイントでアクセスする。
NGSI v2というのはFIWAREが採用しているAPIの仕様名です。エンドポイントの形や必須ヘッダーが規格で決まっているので、一度覚えれば世界中のFIWARE対応システムで同じ知識が使えます。
2. 福岡市の連携基盤の構成を理解する
福岡市のシステムは、Orionの前にWSO2 API Managerというゲートウェイが立っています。クライアント(あなたのコード)は直接Orionに触れず、必ずゲートウェイ経由でアクセスします。
pf-drk.city.fukuoka.lg.jp というURLが書かれていることがありますが、これは内部のOrion本体のアドレスです。実際のアクセス先は api-drk.city.fukuoka.lg.jp です。間違えると403エラーになります。
3. アクセスの準備(認証・必須ヘッダー)
APIのベースURL
https://www.api-drk.city.fukuoka.lg.jp/orion/v2.0
必須HTTPヘッダー3点セット
FIWAREのAPIには、普通のAPIにはない特有のヘッダーが必要です。この3つが揃わないとデータが取得できません。
| ヘッダー名 | 値 | 説明 |
|---|---|---|
Authorization | Bearer <TOKEN> | WSO2発行のアクセストークン |
Fiware-Service | yatai など | テナント名。データの種類によって変わる |
Fiware-ServicePath | /# | データの格納パス。#は全パス対象のワイルドカード |
[] が返ってくるだけなので、原因に気づきにくいです。必ず指定してください。
4. 実際にアクセスしてみる(curl編)
エンティティタイプの一覧を確認する
まず、どんな種類のデータがあるか確認しましょう。
curl -s \ -H "Authorization: Bearer <YOUR_TOKEN>" \ -H "Fiware-Service: yatai" \ -H "Fiware-ServicePath: /#" \ "https://www.api-drk.city.fukuoka.lg.jp/orion/v2.0/types?options=values"
["LightCode", "population", "yataiBasedata", "yataiBasedataTest"]
屋台情報を5件取得する
curl -s \ -H "Authorization: Bearer <YOUR_TOKEN>" \ -H "Fiware-Service: yatai" \ -H "Fiware-ServicePath: /#" \ "https://www.api-drk.city.fukuoka.lg.jp/orion/v2.0/entities\ ?type=yataiBasedata&limit=5&options=count,keyValues"
[
{
"id": "fcod.yataiBasedata.401307.1778688143.97664.00000001",
"type": "yataiBasedata",
"name": "寅政",
"area": "東区",
"category": "ラーメン/焼きラーメン/焼き鳥/おでん",
"businessHours": "19:00~3:00",
"yataiAddress": "〒813-0044 福岡県福岡市東区千早5-9"
}
]
"value"・"type"・"metadata" が付いた冗長な形式です。keyValues オプションを指定すると、シンプルなキー=値形式になって扱いやすくなります。
件数の確認とページネーション
データが多い場合は limit と offset でページを送ります。また options=count を付けると、レスポンスヘッダーに総件数が入ります。
# 1ページ目(1~100件) curl -s ... "...?type=yataiBasedata&limit=100&offset=0&options=keyValues" # 2ページ目(101~200件) curl -s ... "...?type=yataiBasedata&limit=100&offset=100&options=keyValues"
curl -s -I \ -H "Authorization: Bearer <YOUR_TOKEN>" \ -H "Fiware-Service: yatai" \ -H "Fiware-ServicePath: /#" \ "https://www.api-drk.city.fukuoka.lg.jp/orion/v2.0/entities\ ?type=yataiBasedata&limit=1&options=count" # レスポンスヘッダーに以下が含まれる # Fiware-Total-Count: 107
5. Pythonで取得してみる
import requests
API_BASE = "https://www.api-drk.city.fukuoka.lg.jp/orion/v2.0"
TOKEN = "<YOUR_TOKEN>"
def get_headers(service, path="/#"):
return {
"Authorization": f"Bearer {TOKEN}",
"Accept": "application/json",
"Fiware-Service": service,
"Fiware-ServicePath": path,
}
def fetch_all(entity_type, service="yatai"):
"""全件をページネーションで取得する"""
results = []
limit = 100
# まず総件数を確認
r = requests.get(
f"{API_BASE}/entities",
headers=get_headers(service),
params={"type": entity_type, "limit": 1, "options": "count,keyValues"},
timeout=30,
)
r.raise_for_status()
total = int(r.headers.get("Fiware-Total-Count", 0))
print(f"総件数: {total}")
# ページネーションで全件取得
for offset in range(0, total, limit):
r = requests.get(
f"{API_BASE}/entities",
headers=get_headers(service),
params={
"type": entity_type,
"limit": limit,
"offset": offset,
"options": "keyValues",
},
timeout=30,
)
r.raise_for_status()
results.extend(r.json())
print(f" 取得: {offset + 1}~{min(offset + limit, total)} 件")
return results
# 屋台情報を全件取得
yatai_list = fetch_all("yataiBasedata", service="yatai")
print(f"\n取得完了: {len(yatai_list)} 件")
リアルタイム混雑情報を取得する例
def get_congestion():
"""区役所の現在の混雑状況を取得"""
r = requests.get(
f"{API_BASE}/entities",
headers=get_headers("aicamera", path="/"),
params={"type": "CongestionInfo", "limit": 17, "options": "keyValues"},
timeout=30,
)
r.raise_for_status()
data = r.json()
for cam in data:
count = cam.get("count", 0)
threshold = cam.get("threshold", [10, 20])
if count < threshold[0]:
status = "空いている"
elif count < threshold[1]:
status = "普通"
else:
status = "混雑"
print(f"{cam['name']}: {count}人 → {status}")
get_congestion()
6. 利用できるデータ一覧(2026-05-18時点)
| Fiware-Service | エンティティタイプ | 件数 | 更新頻度 |
|---|---|---|---|
yatai | yataiBasedata | 107件 | 随時 |
yatai | LightCode | 90件 | 随時 |
fcod | population(各区分) | 約34,000件 | 月次 |
fcod | waterSpot | 34件 | 随時 |
fdc | foodTruckData | 42件 | 随時 |
aicamera | CongestionInfo | 17件 | リアルタイム |
people_flow | PeopleFlow | 18件 | 月次 |
7. ハマりやすいポイント6選
-
1
Fiware-Serviceを指定し忘れる
省略してもエラーにならず、空配列[]が返ってくるだけ。「データが存在しない」と勘違いしやすい。アクセスするデータに対応したサービス名(yatai/fcod/aicameraなど)を必ず指定する。 -
2
ServicePathのワイルドカードを
*にする
NGSI v2のワイルドカードは#であり、*は400エラー(IllegalCharacter)になる。Fiware-ServicePath: /#が正解。 -
3
アクセス先のドメインを間違える
ドキュメントや資料に内部URLのpf-drkドメインが書かれていることがある。実際に接続できるのはapi-drkドメイン(ゲートウェイ)のみ。pf-drkに直接アクセスすると403になる。 -
4
存在しないエンティティタイプを指定する
定義書に書かれているyataiStatusはOrion上に存在しない(データ未登録)。実際に存在するタイプは/typesエンドポイントで事前に確認しておくのがおすすめ。 -
5
全件取得時にlimitの上限に気づかない
limitを指定しないとデフォルトで20件しか返らない。options=countでレスポンスヘッダーに総件数を出力し、offsetでページネーションする設計が必要。 -
6
NGSI v1エンドポイントにアクセスしようとする
/orion/v1/への接続は発行されたトークンでは403になる。このシステムで使えるのは/orion/v2.0/のみ。
FIWAREはとっつきにくい印象がありますが、「エンティティ=データの1件」という概念と、3点セットのHTTPヘッダーさえ理解すれば、あとは普通のREST APIと同じように操作できます。
福岡市の場合は屋台・人口統計・AIカメラ混雑情報・キッチンカー・給水スポットなど幅広いデータが6万件以上公開されています。特にAIカメラ混雑情報はリアルタイムで更新されているので、混雑可視化アプリや通知システムなど面白い活用が期待できます。


