明日から本気出す開発日記

2016/10/31 fc2ブログより引っ越しました。更新はまた明日から本気だす

Node.js OpenStreetMap

Sencha Touch & Node.jsからOpenStreetMapのAPIを実行する

2016/10/31

以前Apache Flex(Adobe Flex)からOSMのAPIを実行する記事を投稿しました。
OSMエディタを作成する最低要件として、
・地図の表示
・HTTPリクエスト(POST、PUT、DELETE)が出来る
という2つの要件を満たせば作ることが可能です。

ということで、
Sencha TouchからOSMのAPIを実行してみます。
まず、地図の表示にはLeafletを使います。
Sencha Touch用のコンポーネントはこちら。
https://market.sencha.com/extensions/ext-ux-leafletmap

同様に、OpenLayersのコンポーネントもありますが、お好みでどちらかを使えば良いでしょう。
https://market.sencha.com/extensions/ext-ux-openlayersmap

ちなみにLeafletでは、getMap().getCenter()で画面中央の緯度・経度を取得できます。

次はHTTPリクエストです。
早速問題発生です。Sencha Touchではクロスドメインのリクエストを送ることが出来ません。
ブラウザ上で動かすのではなく、PhoneGap(Cordova)を使ってアプリにパッケージするか、
あるいは外部とのやりとりはサーバサイドに任せれば回避できるみたいです。

Flexでもクロスドメインのリクエストは出来ませんが、crossdomain.xmlファイルが相手サーバに置いてあれば通信できます。また、OSMサーバにはcrossdomain.xmlファイルが置いてあります。
(Flex製のエディタであるPotlatchに対応するためだと思われます。)

PhoneGapを使おうかと思ったのですが、僕のApple開発者ライセンスが切れてしまっているのと、Androidを使うにしてもデバッグが面倒なので今回はNode.jsでサーバを立ててそちらからリクエストを送ってみます。
もちろんPhoneGapを使えばSencha Touchからも送れるはずです。

まず、OSMのユーザIDとパスワードをBase64エンコードした上で送り、Basic認証を通さなくてはいけません。

Bufferクラスを使ってエンコードすれば良いみたいです。
http://programmer-jobs.blogspot.jp/2013/03/nodejsbase64.html

OSMのAPIを実行するときは、基本的にXML形式のデータをやりとりします。
チェンジセット番号を取得するだけのAPIであれば、XMLはベタ書きで構いません。
(チェンジセット作成時のリクエストは毎回同じ内容なので・・・)

ということで、XMLを定義します。

var xmldata ='<osm version="0.6" generator="OSM Sencha Editer" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">'
    +'<changeset>'
    +'<tag k="created_by" v="OSM Sencha Editer"/>'
    +'<tag k="comment" v="API v0.6 test"/>'
    +'</changeset>'
    +'</osm>';

で、リクエストにはrequestモジュールを使ってみます。
requestモジュールではPUTリクエストも送れるっぽいんですが、今回はPOSTで送ってリクエストヘッダをPUTに偽装しました。

Node.jsからチェンジセットを作成するコードは以下のようになります。

require("request");

var xmldata ='<osm version="0.6" generator="OSM Sencha Editer" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">'
    +'<changeset>'
    +'<tag k="created_by" v="OSM Sencha Editer"/>'
    +'<tag k="comment" v="API v0.6 test"/>'
    +'</changeset>'
    +'</osm>';

// OSMのユーザID、パスワードをBase64エンコード
var hoge = new Buffer(UserID+":"+Password, 'base64')

var options = {
    url: 'http://api.openstreetmap.org/api/0.6/changeset/create',
    method: 'POST'
    headers: {
        'X-HTTP-Method-Override': 'PUT',
        'Content-Type': 'text/xml',
        'Authorization': 'Basic ' + hoge.toString()
    },
    form: {'data': xmldata}
};

request(options, function (error, response, body) {
    if (!error && response.statusCode == 200) {
        // チェンジセットの番号が返ってくる
        console.log(body)
    }
});

あとはSencha Touch側で画面中央の緯度経度を取得して、その場所に何の地物を追加するか入力させ、XMLを組み立てて上の例と同様にAPIサーバにリクエストを送れば地物が追加できます。

-Node.js, OpenStreetMap