初めまして。Qiita初投稿になります。
Webエンジニア歴2ヶ月弱の初心者です。
##背景
Ajaxで外部APIに通信する、という課題の為に駅データ.jpを利用しました。
駅データAPIの仕様が不親切(?)で躓いたため、学びを共有しようと思いました。
何か間違いがありましたら、ぜひコメントでご指摘ください。
##駅データ.jpとは
すでに簡潔に説明されている記事があったので、引用させていただきます。
駅とか路線のマスターデータの入手方法 @kouさんより
- 無料(有料プランもあり)
- 事業者マスタ、路線マスタ、駅マスタ、接続駅マスタがCSVで提供されます
- APIでの提供も用意されています
- 商用利用やデータの改変についても制約がなく使い勝手が良さそうです
- 有料契約すると取得できる情報がちょっと詳細になります
というものです。
こちらの都道府県APIを利用して、プルダウンから選択した都道府県の沿線情報取得を試みました。
##実装してみた(失敗例)
リクエストURLはXML形式とJSON形式のものが用意されていますが、
ここではJSON形式のデータを取得して画面に表示させようと以下のように書きました。
■ リクエストURL
XML形式 : http://www.ekidata.jp/api/p/(都道府県コード).xml
JSON形式 : http://www.ekidata.jp/api/p/(都道府県コード).json
//駅データ取得
$(function(){
$('#train_search').click(function(){
//クリック時に検索結果を初期化
$('#train_result').html("");
//プルダウンから値を取得
var element = $('#place').val();
var trainUrl = 'https://www.ekidata.jp/api/p/' + element + '.json';
$.ajax({
url: trainUrl,
dataType: 'jsonp',
success: function(data, dataType) {
xml.data.line.forEach(function(value){
$('#train_result').append(value.line_cd + ':' + value.line_name + '<br>')
});
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("ng");
console.log("ng", XMLHttpRequest, textStatus, errorThrown);
}
});
})
})
##何がいけなかったのか
結論から言うと、dataTypeが誤りです。JSON形式のデータのはずが、中身を見てみると...
愛知県の出力例:http://www.ekidata.jp/api/p/23.json
if(typeof(xml)=='undefined') xml = {};
xml.data = {"line":[{"line_cd":11411,"line_name":"JR中央本線(名古屋~塩尻)"},{"line_cd":11413,"line_name":"JR飯田線(豊橋~天竜峡)"},{"line_cd":11502,"line_name":"JR東海道本線(浜松~岐阜)"},{"line_cd":11506,"line_name":"JR武豊線"},{"line_cd":11508,"line_name":"JR関西本線(名古屋~亀山)"},{"line_cd":30001,"line_name":"名鉄名古屋本線"},{"line_cd":30002,"line_name":"名鉄豊川線"},{"line_cd":30003,"line_name":"名鉄西尾線"},{"line_cd":30004,"line_name":"名鉄蒲郡線"},{"line_cd":30005,"line_name":"名鉄三河線"},{"line_cd":30006,"line_name":"名鉄豊田線"},{"line_cd":30007,"line_name":"名鉄空港線"},{"line_cd":30008,"line_name":"名鉄常滑線"},{"line_cd":30009,"line_name":"名鉄河和線"},{"line_cd":30010,"line_name":"名鉄知多新線"},{"line_cd":30011,"line_name":"名鉄築港線"},{"line_cd":30012,"line_name":"名鉄瀬戸線"},{"line_cd":30013,"line_name":"名鉄津島線"},{"line_cd":30014,"line_name":"名鉄尾西線"},{"line_cd":30015,"line_name":"名鉄犬山線"},{"line_cd":30017,"line_name":"名鉄広見線"},{"line_cd":30018,"line_name":"名鉄小牧線"},{"line_cd":31027,"line_name":"近鉄名古屋線"},{"line_cd":99509,"line_name":"あおなみ線"},{"line_cd":99510,"line_name":"東海交通事業城北線"},{"line_cd":99511,"line_name":"愛知環状鉄道線"},{"line_cd":99512,"line_name":"リニモ"},{"line_cd":99513,"line_name":"名古屋市営地下鉄東山線"},{"line_cd":99514,"line_name":"名古屋市営地下鉄名城線"},{"line_cd":99515,"line_name":"名古屋市営地下鉄名港線"},{"line_cd":99516,"line_name":"名古屋市営地下鉄鶴舞線"},{"line_cd":99517,"line_name":"名古屋市営地下鉄桜通線"},{"line_cd":99518,"line_name":"名古屋市営地下鉄上飯田線"},{"line_cd":99520,"line_name":"豊橋鉄道渥美線"},{"line_cd":99521,"line_name":"豊橋鉄道東田本線"},{"line_cd":99523,"line_name":"ゆとりーとライン"}]}
if(typeof(xml.onload)=='function') xml.onload(xml.data);
JSONファイルかと思いきや、中身がJavaScriptでした、というオチ。
しかもややこしいことに、if(typeof(xml)=='undefined') xml = {};のxml(変数名)の中身がxmlではなくJSONP...
###話は逸れますが...
変数名は適切につけてほしい!
初心者が見ると「あれ、xml.dataの中にデータが入ってるけどこれxml持ってるの???」と思うこともなくはないはず...。というかそう思って混乱しました...。
xml.dataの中にちゃんとJSON形式で入ってますね。
##再実装してみた(成功例)
//駅データ取得
$(function(){
$('#train_search').click(function(){
//クリック時に検索結果を初期化
$('#train_result').html("");
var element = $('#place').val();
var trainUrl = 'https://www.ekidata.jp/api/p/' + element + '.json';
$.ajax({
url: trainUrl,
type:'GET',
dataType: 'script', //ここを修正
timeout:1000,
success: function(data, dataType) {
xml.data.line.forEach(function(value){
$('#train_result').append(value.line_cd + ':' + value.line_name + '<br>')
});
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("ng");
console.log("ng", XMLHttpRequest, textStatus, errorThrown);
}
});
})
})
これで期待通りに動きました。めでたしめでたし。
##まとめ
APIに書いてあることが全てそのままであるとは限らないと学びました。
JSON形式って書いてあったらJSONデータそのものかと思うじゃないですか普通...。
本来の目的であったAjaxもエラーと格闘しながら学べたと思います。
ついでにJSONも。JSONPなんて存在も知らなかったです。
あと変数名大事ですね!!!!!!
##参考
最後に参考にしたページを載せておきます。助かりました。
Ajaxで外部APIに通信する方法がうまくいかない
クロスドメインで使う XMLHttpRequest と JSONP のお話