GBFS(General Bikeshare Feed Specification)に入門しよう (GBFS v2.2)

本記事はマイクロモビリティの標準的なデータフォーマットとして規格化されている「GBFS(General Bikeshare Feed Specification)」について紹介する記事です。バージョンによって定義が異なる場合は、記事執筆時点で最新のv2.2を優先します。

https://github.com/NABSA/gbfs

# 概要
公共交通機関における標準的なデータフォーマットとして「GTFS（General Transit Feed Specification）」が世界的に広く普及しています。日本国内においてもGTFS(またはGTFS-JP)にのっとって整備されたデータがオープンデータとして公開されるケースが、一般的になりつつあります。

https://text.odekake.co.jp/20201105-2/

そんな中、より「小さな公共交通」としてマイクロモビリティのシェアリングサービスが注目を集めています。シェアサイクルや電動キックボードシェアリングなどがこれに当たります。
例えば東京都心部において真っ赤な小さめの自転車を目にする機会が増えていますが、あれは [ドコモ・バイクシェア社](https://www.d-bikeshare.com/) が運営するシェアサイクルサービスの一つです。また全国に目を広げると、OpenStreet社が運営する[HELLO CYCLING](https://www.hellocycling.jp/)の展開が目立ちます。同社のステーション(自転車を貸し借りできる場所)の数は4000を超えており、全国最大のサービスと言えるでしょう[^1]。

[^1]: https://www.hellocycling.jp/map/  HELLO CYCLING ステーションマップ

さらに2020年からは[LUUP社](https://luup.sc/)が運営する電動キックボードのシェアリングサービスも始まりました。ここに挙げた以外のサービス事業者も多く参入しており、特に都市部において、マイクロモビリティのシェアリングサービスはすでに日常の一部になっていると言っても過言では無いでしょう。

これらのサービスのリアルタイムな状態を、GTFSのように統一された情報フォーマットに格納してオンラインで公開しよう、という取り組みの中で生まれたのが、本記事で扱うGBFSです。

GBFSの原型は、[Mitch Vars](https://github.com/mplsmitch)さんによって2014年に策定されました。その後NABSAを経て、現在はGTFS同様に[MobilityData](https://mobilitydata.org/)がサポートを続けています。詳しい経緯はGBFSの[リポジトリ](https://github.com/NABSA/gbfs)に記載されています。

## 規格の対象
GBFSが表現するのは以下の情報です。

* ◯ モビリティのシェアリングサービスが対象です。
    * × 鉄道やバスなど旧来のいわゆる公共交通手段は対象ではありません。
    * 対象とできる乗り物の定義はVehicle_types.jsonに詳述されています。
* ◯ サービスの現在の状態を表します。
    * シェアリングサービスの利用にはリアルタイムな情報が欠かせません。
    * × 過去の情報を表現することはできません。
* ◯ 実際にサービスを利用するユーザーのための情報が格納されます。
    * × 情報の記録や分析という目的は志向されていません。
    * もちろんGBFSにのっとったデータを蓄積することで興味深い分析対象になります。

## 公開例
GBFSのリポジトリ内にある [systems.csv](https://github.com/NABSA/gbfs/blob/master/systems.csv)では、公開されているデータを見ることができます。一番右の`Auto-Discovery URL`カラムで配信されているデータを直接見ることができます。
また[bikeshare-research](https://bikeshare-research.org/#/)という団体が整備しているカタログサイトもあります。

いずれかのカタログにて、行ったことのある都市や知っている場所を探してみると良いかもしれません。

:::note info
日本でも2022/06に「ドコモバイクシェア」・「HELLOCYCLING」のデータがオープンデータになりました!
https://www.odpt.org/2022/06/28/press20220628_bikeshare/
:::


本記事では以下のサービスが配信しているデータ(v2.2)を使って、仕様を見ていきます。

* Bird
    * アメリカ ニューヨーク
    * サービスサイト　https://www.bird.co/
    * gbfs.json https://mds.bird.co/gbfs/v2/public/new-york/gbfs.json
* Capital Bikeshare
    * サービスサイト https://www.capitalbikeshare.com/
    * gbfs.json https://s3.amazonaws.com/lyft-lastmile-production-iad/lbs/dca/gbfs.json

## 技術的なアウトライン

GBFS自体はあくまでFeed Specification(=配信仕様)であって、データの規格などではありません。実態はwebサーバー上で公開され、相互に参照されたJSONファイルの集合です。
例えばデータの入り口となる`gbfs.json`には以下のデータが格納されています。

```json
{
	"version": "2.2",
	"data": {
		"en": {
			"feeds": [
				{
					"name": "system_information",
					"url": "https://mds.bird.co/gbfs/v2/public/new-york/system_information.json"
				},
				{
					"name": "system_pricing_plans",
					"url": "https://mds.bird.co/gbfs/v2/public/new-york/system_pricing_plans.json"
				},
(中略)
			]
		}
	},
	"last_updated": 1645074233,
	"ttl": 60
}
```

アプリケーション開発者はこのgbfs.jsonから、サービス全体の詳細を参照したい場合は `data.en.feeds[0].url` 、料金についての情報を参照したい場合は `data.en.feeds[1].url` それぞれに格納されたURLが指し示すJSONを取得すれば良いわけです。

ご存知の通り大抵の言語においてJSONをパースすることは難しくありません。webブラウザからも容易に確認することができるので、実際のデータを見ながら本記事を読んでください。
なお以下、実際のサービスを運営しデータを配信している会社/団体をサービサー、GBFSにのっとって配信されているデータを利用してアプリケーションを開発する人をアプリケーション実装者、実際のサービスを利用するユーザーをエンドユーザーと表します。


# 実際の仕様
GBFSは先述の通り複数のJSONファイルの集合です。それぞれ実際のデータと併せて見ていきますが、特に着目すべきファイルや定義に絞って言及します。

## ファイル一覧とgbfs.json

v2.2では以下のファイルが定義されています。

| ファイル名 | 用途 | 必須 |
|:-----------|:------------|:------------|
|gbfs.json|データのトップページのようなファイル。下記のそれぞれのファイルへのリンクが記載される|○|
|gbfs_versions.json|配信しているデータのGBFSバージョンの一覧 |×|
|system_information.json|サービスサイトのURLやサービサーの連絡先など、サービスの詳細が記載される | ○|
|vehicle_types.json|提供されている車両の種類が定義される | サービス形態によっては必須|
|station_information.json|モビリティを貸したり返したりできるステーション(ポートとも呼ばれます)の情報が記載される |サービス形態によっては必須 |
|station_status.json|ステーションのリアルタイムな情報が記載される|サービス形態によっては必須 |
|free_bike_status.json|現在借りることができる車両の情報が記載される | サービス形態によっては必須|
|system_hours.json|サービスの運営時間が記載される |× |
|system_calendar.json|サービスの運営日の情報が記載される |× |
|system_regions.json|サービスが提供しているリージョン(※後述)の情報が記載される |× |
|system_pricing_plans.json|サービスの料金設定に関する情報が記載される |× |
|system_alerts.json|サービサーからエンドユーザーへ発出されているお知らせが記載される |× |
|geofencing_zones.json|他のファイルで参照されるジオフェンスが記載される |× |

まずは選んだサービスの`gbfs.json`を確認します。[gbfs.jsonの定義](https://github.com/NABSA/gbfs/blob/master/gbfs.md#gbfsjson)はこちらを参照してください。

gbfs.jsonの `data`配下には配信データが対応している言語ごとに、このサービスが配信しているJSONファイルへのリンクが格納されています。

先ほど例に出したbirdとCapital Bikeshareの例をみると以下のように違いがあることがわかります。

|  | bird | Capital Bikeshare |
|:-----------|:------------|:------------|
|gbfs.json|○|○|
|gbfs_versions.json| ○| |
|system_information.json|○ |○ |
|vehicle_types.json|○ | |
|station_information.json| |○ |
|station_status.json| |○ |
|free_bike_status.json|○|○ |
|system_hours.json| |○ |
|system_calendar.json| |○ |
|system_regions.json|○ |○ |
|system_pricing_plans.json|○ |○ |
|system_alerts.json| |○ |
|geofencing_zones.json|○ | |

これはそれぞれのサービスの形態が異なるためです。詳しくはそれぞれのファイルの項で詳述します。


## gbfs_versions.json
https://github.com/NABSA/gbfs/blob/master/gbfs.md#gbfs_versionsjson
このサービサーが配信しているデータの一覧がバージョンごとに取得できます。
GBFSはバージョンを跨いでも後方互換性が保たれるよう努力されています。しかしメジャーバージョン(バージョン名の整数部分)が上がる時には破壊的な変更がなされる可能性にも言及されています。この辺りは一般のライブラリやプログラミング言語のバージョニングの考え方と一緒と考えて良いでしょう。

[Guiding Principles](https://github.com/NABSA/gbfs#guiding-principles)
> Changes to the spec should be backwards-compatible, when possible. 

[Specification Versioning](https://github.com/NABSA/gbfs#specification-versioning)
>A whole integer increase is used for breaking changes (MAJOR changes).

アプリ実装者は自分が利用したいバージョンや、現在使っているバージョンより新しいバージョンのデータが配信されているかを確かめることができます。
アプリからの普段の通信では利用する用途はなさそうです。

## system_information
https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md#system_informationjson
一連のデータやサービスのメタ的な情報が格納されています。アプリ開発者はアプリでユーザーに見せたい情報をここからピックアップすることができます。

着目したフィールドは以下です。

:::note alert
本項では投稿当初、`license_url`が空ないし未定義時の仕様について、バージョンを明記せずに説明していました。下記の通りv3.0-RC以降に追加された仕様であり、本記事が取り上げるv2.2時点では存在しない仕様でした。訂正するとともに、正確な仕様、特にライセンス関連について、GBFSの原本と配信データそのものを参照し、各自で判断いただくよう改めてお願いします。(2022/04/23追記)
:::

| フィールド | 例 | 備考 |
|:-----------|:------------|:------------|
| system_id | cabi |サービスを一意に指ししめすID。文字通りグローバルで一意であり他のサービサーが配信するデータのsyste_idと重ならないことが求められています。そのための仕組みは後述します。|
| rental_apps|(object)|車両を借りるために利用するモバイルアプリの情報。iOSとandroidそれぞれで定義ができます。|
| license_url |(空文字列)|データのライセンスを表示したURL。|

### system_idを一意に保つ仕組み
サービサーはデータ配信を始めるときにsystem_idを決定しますが、この値は全世界で一意になることが必要です。これはアプリケーション実装者が複数のGBFSデータを束ねて利用する時に、競合が起きることを防ぐためと思われます。
GBFSではsystem_idの一意性を保つために、必ずsystems.csvを確認することを求めています。systems.csvはgbfsリポジトリ直下に存在するファイルで、現在世界で配信されているGBFSデータのカタログです。つまりこの一覧の中に無い値でsystem_idを定めるということです。
さらに(明言はされていませんが)後続のサービサーのために、自らが配信を始めるデータに関する情報をsystems.csvに掲載することも求めています。

* system_idを決めるために、systems.csvを参照するよう仕向ける。
* systems.csvの存在とそこに掲載する必要性を認知させ、systems.csvへ掲載するモチベーションを高める。

という流れを自然に作ることで、system_idの一意性とsystems.csvの網羅性を保つ仕組みです。ひいてはエコシステムの持続性へ繋がっており、この仕組みは非常に興味深いです。

データを配信するサービサー自身がIDを決めるというルールはGTFSにおけるagency_idと似ています。しかしGTFSにおけるそれには指針がなく、アプリケーション実装者はそれぞれで定められたagency_idが競合することを考慮する必要がありました。そのような中でも「標準的なバス情報フォーマット(GTFS-JP)」がagency_idには法人番号を利用することを定めるなど、一意性を担保する試みが行われているものの、仕様自身が構造的にこの問題を解決する仕組みを得るには至っていません。

### ライセンスが明言されていない時のフォールバック (v3.0-RC以降)

:::note warn
v2.2時点での仕様ではないことに留意してください。
:::

v3.0-RC以降では、`license_url`や`license_id` の項目が空または未定義で、データ全体のライセンスが特に明言されていない場合、[Creative Commons](https://creativecommons.org/publicdomain/zero/1.0/legalcode)とみなすことが定められています。
このようなルール、いわばフォールバックを導入することで、ライセンスの明文化を促したり、ライセンスが不明であることによってデータが「死んでしまう」ことを防ぐ仕組みがGBFSには導入されていると言えそうです。


> If the license_id and license_url fields are blank or omitted, this indicates that the feed is provided under the Creative Commons Universal Public Domain Dedication. (as of v3.0-RC)

GTFSに基づくデータのオープンデータでは、そのライセンスが明言されないことで、アプリ実装者が取り扱いを判断できず利用できないという問題が、しばしば起こりました。system_idの仕組み同様に、その反省から生まれた仕様かもしれません。

## vehicle_types
https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md#vehicle_typesjson-added-in-v21
サービスで提供されている車両の種類が定義されています。例えばbirdでは以下のように2種類の車両が使えることが分かります。

```json
[
	{
		"vehicle_type_id": "bae2102b-56ba-42ba-9097-720e5990b4b2",
		"form_factor": "scooter",
		"propulsion_type": "electric",
		"max_range_meters": 24000
	},
	{
		"vehicle_type_id": "2ea3c8b2-ed07-4c53-b87e-638c08471309",
		"form_factor": "bicycle",
		"propulsion_type": "electric_assist",
		"max_range_meters": 60000
	}
]
```

`form_factor`と`propulsion_type`を組み合わせることで、車両がどのようなタイプの乗り物なのかを判別することができます。
例えば上記のbirdの例の1つ目の車両は以下のようなタイプでしょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159912/4f8262f2-d55e-428e-6310-07dc43d2974e.png)
(https://www.bird.co/how/ より引用)

着目したフィールドは以下です

| フィールド | 例 | 備考 |
|:-----------|:------------|:------------|
| max_range_meters | 24000 |その車両が何らかの動力で動くものである場合に、そのエネルギーが満タンである時に移動できる距離。経路検索における最大距離として活用できそうです。|

単一車種しか提供していないなど、特にユーザーに明示する必要がないと考えているサービサーはこのファイルを省略することもできます。

## station_information, station_status
https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md#station_informationjson

この2つのファイルによって、ステーションの情報や状態を表します。

シェアリングモビリティには大きく「所定のステーションで借り、所定のステーションで返す」タイプと「エリア内どこでも借りられて、どこでも利用終了できる」タイプに分かれます。前者を「ステーション型」、後者を「ドックレス型」と呼ぶことがあります。
前者における貸し借りのできる場所を、GBFS上ではstationという単語で表していますが、日本におけるシェアサイクルを利用したことのある方には「ポート」という呼び方の方が馴染みがあるかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159912/57fa7347-7aa4-b4c5-9642-c42140b36a4b.png)
「ポート」のイメージ(筆者撮影)

「エリア内どこでも借りられて、どこでも利用終了できる」タイプのサービスがあるため、この2つのファイルは必須とはなっていません。例えばエリア内ならどこでも利用開始でき、また終了できるBirdではこれらのファイルが定義されていません。対して、stationが決まっているCapital Bikeshareでは定義されています。

station_information.jsonにはstation緯度経度や名称が設定されており、エンドユーザーが現実の世界でstationを探すのに利用できる情報が格納されています。またstation_status.jsonにはstationに止めてある車両台数や返せるラック数、現在アクティブか、などの情報が設定されており、エンドユーザーはこの情報を見て、そのstationへ向かうべきかが判断できます。

## free_bike_status.json
https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md#free_bike_statusjson

現在エンドユーザーが利用開始することができる車両の情報が格納されています。ドックレス型、つまり決まったstationではなくエリア内の路上に車両が散らばっているタイプのサービスでは必須となっています。

```json
{
	"bike_id": "fb8994db-0835-4896-89e2-c27f0a2bb2db",
	"lat": 40.86256,
	"lon": -73.85681166666667,
	"is_disabled": false,
	"is_reserved": false,
	"vehicle_type_id": "bae2102b-56ba-42ba-9097-720e5990b4b2",
	"last_reported": 1645083099,
	"current_range_meters": 29250,
	"pricing_plan_id": "5c469505-2249-4383-9f13-8e4fd1430b0d"
}
```

例えば、この車両は電動スクーター(vehicle_types.jsonから判別)[40.86256,-73.85681166666667](https://www.google.com/maps/place/40%C2%B051'45.2%22N+73%C2%B051'24.5%22W/@40.8549362,-73.8723351,13.52z/data=!4m5!3m4!1s0x0:0x237ba9a197fd1581!8m2!3d40.86256!4d-73.8568117)に停車中で、あと29250m走るバッテリーが残っていることが分かります。

なおステーション型であるCapital Bikeshareでもfree_bike_status.jsonが配信されています。[サービスサイト](https://help.capitalbikeshare.com/hc/en-us/articles/360039401851-How-to-dock-a-bike)を見る限り、車両のタイプによっては必ずしもstationに返却する必要はないようです。それらstation以外の場所で利用終了された車両の情報が格納されています。

Capital Bikeshareは例外ですが、一般的なステーション型のサービスではstation_information.json, station_status.jsonで全ての利用可能な車両を網羅することができるため、このファイルは必須ではありません。

## system_hours.json system_calendar.json
https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md#system_hoursjson
https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md#system_calendarjson
サービス全体の営業時間、営業期間を表現することができます。特に定義がない場合は、24時間365日利用可能であることを示します。

Birdではファイル自体が配信されておらず、24時間365日利用できることが読み取れます。Capital Bikeshareではそれぞれファイルが配信されていますが、内容を見ると同じく24時間365日利用できることが読み取れます。

例えば北海道で運営されている[ポロクル](https://porocle.jp/)というサービスは、冬期にサービスが閉鎖されます。こういったサービスに関する情報をエンドユーザーに提示する場合に利用できる情報です

## system_regions.json
https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md#system_regionsjson
サービスを地理的に分割した「region(リージョン)」を定義するファイルです。
必須ファイルではありませんが、以下に説明する「リージョン」が導入されているサービスでは定義が必要とされています。

:::note info
この項目では、日本のシェアサイクルサービスにおける「リージョン」の概念と、GBFS上での「region」の考え方が一致することを前提としています。しかし、GBFSの関連文書において「region」を詳述する内容を見つけることができなかったため、筆者はこの前提が正しいことに確信を持てていません。
何らかの情報をお持ちの方はコメント等でぜひお示しください。
:::

「リージョン」という考え方について説明します。1つのサービサーが複数のエリアでサービスを展開していることがよくあります。例えばドコモ・バイクシェア社は、単一のブランドで複数のエリアにまたがるサービスを運営しています[^2]。

[^2]: https://docomo-cycle.jp/ より

この時ユーザーはリージョンに気をつける必要があります。例に挙げたドコモバイクシェアのうち「東京リージョン」と「川崎リージョン」を著した模式図が以下です。

![スクリーンショット 2022-03-01 17.37.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159912/a6cbcb1a-02de-d176-6d13-163ca15570ec.png)

リージョンの考え方を持つサービスにおけるポートは、いずれかのリージョンの所属しています。例えば図におけるポートA,Bは「東京リージョン」に、ポートX,Yは「川崎リージョン」に属しています。

この時、異なるリージョン同士に所属するポート間を利用することはできません。(逆にいうと同一リージョン間は利用することができます。)
system_regions.json において、リージョンを定義し、station_information.jsonにおけるstation(ポート)の中で `stations[].region_id` として利用することで、ポートがどのリージョンに所属しているかを表現しています。

## system_pricing_plans.json
https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md#system_pricing_plansjson
サービスを利用するための料金設定が格納されたファイルです。

`plans`の項目は配列となっていて、複数の料金プラン(一回利用と定期間利用など)を表現することができます。Birdの値がオーソドックスであったため具体例を見てみます。

```json
{
	"plan_id": "5c469505-2249-4383-9f13-8e4fd1430b0d",
	"name": "Bird Pricing Plan",
	"currency": "USD",
	"price": 1,
	"is_taxable": true,
	"description": "$1.00 unlock fee, $0.39 per minute",
	"per_min_pricing": [
		{
			"start": 0,
			"interval": 1,
			"rate": 0.39
		}
	]
}
```

 `description` の `$1.00 unlock fee, $0.39 per minute` の通り

* それぞれの値はアメリカドルであること(`currency`)
* 解錠(＝利用開始)1回あたり1ドル(`price`)かかること
* `per_min_pricing[0]`の内容から開始した瞬間から(`start`)、1分(`interval`)経過するごとに、0.39ドル(`rate`)かかること

が分かります。

`per_min_pricing`の項目は配列であるため、前橋市の[cogbe](https://interstreet.jp/maebashi-cogbe/)のように、料金レートが途中で変わる料金体系も表現することができます。

日本国内のシェアサイクルでは時間単位の課金が一般的ですが、`per_km_pricing`を使い、距離に応じた料金体系を表現することもできます。

## system_alerts.json
https://github.com/NABSA/gbfs/blob/v2.2/gbfs.md#system_alertsjson
サービサーからユーザーへ知らせたい内容を格納するファイルです。

`type` には以下の値を設定することができます。これにより、アプリ実装者は情報の重要度を判別することができます。


| type | 意味 | 
|:-----------|:------------|
| system_closure |サービス全体の閉鎖を知らせる情報 |
| station_closure |特定のステーションの閉鎖を知らせる情報|
| station_move |特定のステーションの移転を知らせる情報|
| other |その他の情報|


上記を使い、例えば「`system_closure`であれば、大きくユーザーにアラートする」「`other`であれば通常のお知らせとして知らせる」といった使い分けが考えられます。

また`station_ids` `region_ids` `times`を設定することで空間的、時間的な情報対象範囲を絞ることもできます。

例えばあるタイミングのCapital Bikeshareのsystem_alerts.jsonには下記の内容が格納されていました。

```json
{
	"summary": "We have a big update!",
	"last_updated": 1585937177,
	"times": [
		{
			"end": 1585937280,
			"start": 1585886400
		}
	],
	"type": "OTHER",
	"description": "Our new app is here. Update your app now.",
	"alert_id": "4"
}
```

アプリアップデートですので、緊急度の高いお知らせではなさそうです。こういったプロモーション的な内容も含め、サービサーがエンドユーザーに伝えたい内容を、アプリ実装者へ知らせることができます。

# まとめ

以上、それぞれの項目について解説しました。全体として、仕様が簡便かつ任意項目が多いうえ、GTFSの運用で問題になっていた点の対策が入っているように感じました。また実際のデータが配信されている例が多いため、現地での様子を想像しながらデータを読むことができました。国内サービスのGBFSも扱ってぜひアプリ開発にチャレンジしたいと思いました。

詳細かつ最新の内容はGBFSのリポジトリを確認してください。

https://github.com/NABSA/gbfs

リポジトリに記載の通り2022年1Qにはv3のリリースが予定されています。リリースされたのち、v2.2との差分などをまとめたいと思います。


# 利用データ出典

* Bird
    * gbfs.json https://mds.bird.co/gbfs/v2/public/new-york/gbfs.json
    * ライセンス 
https://www.bird.co/it/gbfs-data-license-agreement/
* Capital Bikeshare
    * gbfs.json https://s3.amazonaws.com/lyft-lastmile-production-iad/lbs/dca/gbfs.json
    * system_information.json内`license_url`の項目が空であるため、[CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/legalcode)に準じているものとみなしました。

いずれのデータも本記事執筆のために一時的に取得し加工したデータであり、同データの正確な表現および第三者への再配信を意図したものではありません。