Overpass API とは
OpenStreetMap には全世界のマッパーたちが登録した道路や建物、さらにはそれらについての詳細なタグ情報が登録されています。
そのような膨大なデータ群を検索可能にし、簡単にアクセスできるような API を公開してくれているプロジェクトが Overpass API です。
Overpass API はOverpass QLという言語で書かれたクエリを送ると、検索結果を JSON,CSV,XML などの形式で送り返してくれます。下の例では京都の市街地にある郵便局の一覧を得ることができます。
[out:json]; // JSONファイルで出力
node
// 四条通から北大路通、西大路通から河原町通で囲まれる四角形から検索
(35.0, 135.73, 35.04, 135.77)
// nameタグに郵便局で終わる文字列が含まれるものを抽出
['name' ~ '郵便局$'];
out;
Overpass API の使い方はOpenStreetMap の Wikiに詳しい解説があります。
Overpass API をJavaScript/TypeScriptから使ってみよう
Overpass API にはOverpass turboという素晴らしいフロントエンドがあって、クエリの実行から結果の表示、地図へのマッピングまで行なってくれる優れものです。
ただ、プログラマチックにデータを取得したい場合や、自分が開発しているアプリにこの API の機能を組み込みたい場合は、 Overpass API のサーバーに直接問い合わせる必要があります。
JavaScript から Overpass API にアクセスする方法は、@t-kurasawaさんによる
OpenStreetMap Advent Calendar 2021 の 4 日目の記事にも紹介されている通り、難しいものではないのですがライブラリがあると便利です。
ただ、数年前で開発が止まっているものや、型定義ファイルがなかったりして TypeScript から呼び出すにはひと手間かける必要があるもの、コールバックで結果を受け取る設計のものが少なくなく、僕のユースケースを満たすものが見つかりませんでした。
僕がほしいライブラリはこんな感じです ↓
- 結果が GeoJSON で出力される
- そのまま Leaflet とか MapLibre とかに持ち込んで表示できる
- TypeScript で開発されている
- JavaScript から呼び出す場合も型定義があれば補完が効いて便利
- async/await を使って書きたい
- コールバック読みにくい...ですよね?
- イマドキな書き方をしてみたい!
ざっとこの要件を満たすラッパーを作ってみたので、今回はそれを紹介させていただけたらと思います。
自作ライブラリ osmQL の紹介
osmQL というライブラリを作成しました。
急いで作ったので Node.js でしか動きませんが、ゆくゆくはブラウザ上でも動作するように改良していこうと考えています。
osmQL でできること
osmQL では主に 2 つのことができます。
- 手書きの Overpass QL を読み込み実行
- 付属のユーティリティを使ってクエリを作成して実行
Overpass QL のファイルを読み込んで実行
ひとつめはクエリ文字列や、クエリを書いたファイルを読み込んでそれを実行する機能です。
たとえば、先程の
[out:json]; // JSONファイルで出力
node
// 四条通から北大路通、西大路通から河原町通で囲まれる四角形から検索
(35.0, 135.73, 35.04, 135.77)
// nameタグに郵便局で終わる文字列が含まれるものを抽出
['name' ~ '郵便局$'];
out;
というファイルがあったとしてこれを読み込んで Overpass API に問い合わせるコードは次のように書くことができます。
import { OSMQuery } from "@toriyama/osmql";
(async () => {
const osmQuery = new OSMQuery();
const query = osmQuery.fromQLFile("./sample.ql");
const result = await query.execute();
})();
さらに、result
にはtoGeoJSON()
というメソッドがあって、これを実行すると Overpass API からの結果を GeoJSON 形式に変換することができます。
console.log(result.toGeoJSON());
{
type: 'FeatureCollection',
features: [
{
type: 'Feature',
id: 'node/796933156',
properties: [Object],
geometry: [Object]
},
{
type: 'Feature',
id: 'node/1422960082',
properties: [Object],
geometry: [Object]
},
...
]
}
ユーティリティを用いてクエリを作成し実行
このライブラリの一番の目玉がクエリを書かなくても付属のQueryBuilder
を使えば、誰でもかんたんに Overpass API にアクセスできる機能です。
たとえば先ほどの京都市街地の郵便局を検索するクエリをQueryBuilder
を使って作成・実行してみましょう。
[out:json]; // JSONファイルで出力
node
// 四条通から北大路通、西大路通から河原町通で囲まれる四角形から検索
(35.0, 135.73, 35.04, 135.77)
// nameタグに郵便局で終わる文字列が含まれるものを抽出
['name' ~ '郵便局$'];
out;
import fs from "fs/promises";
import { OSMQuery } from "@toriyama/osmql";
const query = OSMQuery.queryBuilder({
category: "node",
});
query.setBounding({
south: 35.0,
west: 135.73,
north: 35.04,
east: 135.77,
});
query.filterBy("name")(/郵便局$/);
OSMQuery.get(query).then((result) => {
const geojson = result.toGeoJSON();
fs.writeFile("./postoffices.geojson", JSON.stringify(geojson, "", "\t"));
});
するとカレントディレクトリにpostoffices.geojson
というファイルが出力されると思います。
これをgeojson.ioなどに読み込ませて表示させてみると、こんな感じになると思います!
QueryBuilder
は以下のようにしても読み込むことができます。
import { QueryBuilder } from "@toriyama/osmql";
QueryBuilder
には検索する領域を指定するsetBounding(bounding)
メソッドだけでなく、
- 指定したタグに一致するものがあるか検索する
filterBy(tagName)(value)
メソッド - マッパー ID やユーザーネームを入れてその人の成果を検索できる
editedBy(user)
メソッド
などが用意されています。Overpass QL を書くほどでないかんたんな検索の実行に便利であるほか、このライブラリを使えばクエリ言語にあまり親しみがないユーザーでもかんたんに Overpass API に触れることができます。
おわりに――一緒に地図を書きませんか
OpenStreetMap は日々全世界のユーザーが絶えずコミットし続けている巨大なプロジェクトです。
しかも、その蓄積された成果はオープンデータとして公開され自由につかうことができます^[1]。
OpenStreetMap を金銀財宝の眠る山と喩えるならば、Overpass API はそれを掘り当てるためのつるはしでしょうか。お宝探しの旅に出るときは拙作のライブラリもぜひお供に連れて行ってくれると嬉しいです。では Happy Mapping!🗺 & Mining!⛏