ぐるなびAPIを使ってJavaScript(jQuery)で動作するシングルページアプリケーションを作ってみました。

ご存じの方もいらっしゃると思いますが、ぐるなびというレストランの検索サイトでは、レストラン検索などができるAPIを公開しています。(ぐるなびWeb サービス for Developers)

APIの勉強がしたいと思っていろいろ調べていたところ、このAPIにたどり着きました。解説ページの作りが非常によく、サンプルコードもわかりやすかったので、このAPIを使わせていただくことにしました。

都道府県別カフェ検索アプリを作る。

ぐるなびに登録されているカフェを都道府県ごとに検索できるごく簡単なWebアプリケーションを作ったのでデモページとコードを公開してみます。

上記デモURLにアクセスすると、東京都のカフェ一覧が表示されます。クリックするとぐるなびの店舗紹介にリンクします。

「さらに表示する」ボタンをクリックすると次の10件のデータを取得して表示します。

都道府県を「変更する」ボタンをクリックすると、文字通り都道府県が切り替わって、条件にマッチしたデータを取得して表示します。

JavaScript(jQuery)

JavaScript初学者が作った学習用のコードのため、間違いや非効率なコードが含まれている可能性があります。ご了承ください。ご指摘、ご助言いただけますと非常にありがたいです!コメント欄をご利用ください。
//masonryも併用しています
jQuery(function() {

(function(){

	/**************************************************************************************
	 * 変数定義
	 **************************************************************************************/

	// masonry 初期設定
	var $container = jQuery('.grid'); //wrapper要素指定
	var $inner = '.grid-item'; //inner要素指定

	// API
	var api_key = '********************************'; //アクセスキー
	var hit_per_page_num = 10; //一度に表示する件数
	var offset_page_num = 1; //初期ページ
	var pref_name_ini = 13; //都道府県初期設定 (PREF13=東京都)
	var pref_name_key = 'PREF' + pref_name_ini; //都道府県名キー作成

	// API URL
	var url_rest = 'http://api.gnavi.co.jp/RestSearchAPI/20150630/?callback=?'; //レストラン検索API
	var url_pref = 'http://api.gnavi.co.jp/master/PrefSearchAPI/20150630/?callback=?'; //エリアマスタ取得API

	//API 基本パラメータ
	var params = {
		keyid: api_key,
		format: 'json'
	};

	// API 店舗データ取得用パラメータ設定
	var params_shop = jQuery.extend({ }, params);
	params_shop.pref = pref_name_key; //都道府県設定
	params_shop.freeword = 'コーヒー,カフェ,珈琲,喫茶,喫茶店'; //キーワード設定
	params_shop.hit_per_page = hit_per_page_num;
	params_shop.offset_page = offset_page_num; //ページ数

	// API 店舗データ数判定
	var resultLooplength = 0;



	/**************************************************************************************
	 * masonry データ配置処理
	 **************************************************************************************/

	var preLoad = function(){
		$container.imagesLoaded(function(){
			$container.masonry({
				itemSelector: $inner, //タイトル状に配置する要素のclassの指定
				isFitWidth: true, //親要素の幅に合わせてタイル状のコンテンツ数を自動調整
				isAnimated: false //伸縮時のアニメーションの設定
			});
		});
	};



	/**************************************************************************************
	 * API 店舗データ 出力
	 **************************************************************************************/


	//API 店舗データ出力
	var resultLoop = function(result){

		for ( var i in result.rest ){

			var elm = {
				name: result.rest[i].name, //店舗名取得
				shop_image1: result.rest[i].image_url.shop_image1, //画像取得
				url: result.rest[i].url, //ぐるなび店舗詳細ページURL取得
				address:result.rest[i].address //店舗住所取得
			}
			
			var img_url = elm.shop_image1.toString();
			//変数img_urlは、APIで画像が登録されていない場合のif文の条件分岐の値として使います。
			//店舗によっては画像が登録されておらず、[object Object]というデータが返されます。
			//[object Object]は、調べたところオブジェクトの型を表現しているようですが、よくわかりませんでした。
			//toString()メソッドを使って文字列に変換すると同値演算ができるようになったので、
			//最善では無いと思いますが、ひとまずこのような変数を作りました。

			if(img_url === '[object Object]'){
				preLoad();
				jQuery('.result').append('
  • ' + elm.name + '
    ' + elm.address + '
  • '); } else { var img_li = '' + '
    '; preLoad(); jQuery('.result').append('
  • ' + img_li + elm.name + '
    ' + elm.address + '
  • '); } resultLooplength++; if( resultLooplength >= result.total_hit_count ){ jQuery('.btn--more-load').after('

    全データを表示しました。

    ').addClass('none'); resultLooplength = 0; } } params_shop.offset_page++; }; //API 取得件数を表示 var resultNum = function(result){ if ( result.total_hit_count > 0 ) { jQuery('.total').html( result.total_hit_count + '件のお店が見つかりました。\n' ); } else { jQuery('.total').html( 'お店が見つかりませんでした。' ); } }; /************************************************************************************** * API 都道府県データ 出力 **************************************************************************************/ // API 地域名初期表示 var farstPrefTitle = function(result){ var pref_title = result.pref[pref_name_ini - 1].pref_name; jQuery('.pref_title').html(pref_title); }; //現在の地域名を更新 var changePrefTitle = function(val,result){ jQuery('.pref_title').html(val); }; //API 都道府県データをselect要素として生成する var resultPref = function(result){ for ( var i in result.pref ){ var name = result.pref[i].pref_name; var code = result.pref[i].pref_code; jQuery("[name = pref_name]").append( '' ); } }; /************************************************************************************** * APIデータ取得/イベント実行 **************************************************************************************/ //ページがロードされたら jQuery(window).one('load', function(){ //店舗データを取得し表示する jQuery.getJSON(url_rest, params_shop, function(result){ //店舗件数を表示 resultNum(result); //店舗データ表示 resultLoop(result); //ページ数を更新 offset_page_num++; }) //都道府県データを取得し表示/セットする jQuery.getJSON(url_pref, params, function(result){ farstPrefTitle(result); resultPref(result); }) }); //指定要素がクリックされたら次のデータを取得し表示する jQuery('.btn--more-load').on('click', function(){ //APIデータを取得 jQuery.getJSON(url_rest, params_shop, function(result){ //店舗データ表示 resultLoop(result); //masonryを再配置 $container.masonry('reloadItems'); }) }); //指定要素がクリックされたら都道府県を変更して店舗データを再取得し表示する jQuery('[name = pref_btn]').on('click', function(){ //店舗データ数判定を初期化する resultLooplength = 0; //「全データ取得済み」表示を削除する jQuery('.vew-end').remove(); //データ取得ボタンを再表示する jQuery('.btn--more-load').removeClass('none'); //で選択されている要素(都道府県名)を取得 var selectPref_name = jQuery('[name = pref_name] option:selected').text(); //商品データ一覧を初期化 $container.empty(); //ページ数を初期化 params_shop.offset_page = 1; //都道府県パラメータを都道府県データ取得API用オブジェクトにセット params_shop.pref = pref_val; //現在の地域名を更新 changePrefTitle(selectPref_name); //APIデータを取得 jQuery.getJSON(url_rest, params_shop, function(result){ //店舗件数を表示 resultNum(result); //店舗データ表示 resultLoop(result); //masonryを再配置 $container.masonry('reloadItems'); }) }); }).call(this); });

    html

    
    <!DOCTYPE html>
    <html lang="ja">
    <head>
    	<meta charset="UTF-8">
    	<meta name="viewport" content="width=device-width" />
    	<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
    	<link href="style.css" rel="stylesheet">
    	<script src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
    	<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/4.1.0/imagesloaded.pkgd.min.js'></script>
    	<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/masonry/4.0.0/masonry.pkgd.min.js'></script>
    	<script type='text/javascript' src='js/gnavi_api.js'></script>
    	<script type='text/javascript' src='js/custom.js'></script>
    </head>
    
    <body>
    
    	<article class="wrap">
    
    		<header class="header">
    			<div class="inner">
    				<h1>都道府県別カフェ検索<br />(ぐるなびAPIサンプルコード)</h1>
    				<h2 class="pref_title"></h2>
    				<p><span class="total"></span></p>
    				<div class="pref_search">
    					<h3>都道府県変更</h3>
    					<select name="pref_name"></select>
    					<button type="button" name="pref_btn">変更する</button>
    				</div>
    				<p class="text">このサイトはぐるなびAPIを使って作ったSPAのサンプルサイトです。ぐるなびに掲載されているカフェを、都道府県ごとに表示させる機能を提供します。</p>
    				<div>
    					<a href="http://www.gnavi.co.jp/"> 
    						<img src="http://apicache.gnavi.co.jp/image/rest/b/api_155_20.gif" width="155" height="20" border="0" alt="グルメ情報検索サイト ぐるなび">
    					</a>
    				</div>
    			</div>
    		</header>
    		<div class="main-content">
    			<section>
    				<ul class="ul result grid"></ul>
    				<input type="button" class="btn--more-load" value="さらに表示する" />
    			</section>
    		</div>
    
    		<footer>
    			<div class="container">
    			</div>
    		</footer>
    		<div class="go-to-top"><a class="go-to-top_body" href="#">▲<br />もどる</a></div>
    
    	</article>
    
    </body>
    </html>
    

    ※CSSは割愛します。

    雑感

    イベントの実行が煩雑になってしまったので、もっとすっきりわかりやすくできたらいいと思いました。デザインパターンを勉強すると良い気がします。

    addEventListenerの使い方を覚えるといいのかな?時間を取って調べて行きたいですね。MVCフレームワークも覚えられたらいいですね。

    あと、APIの仕様で残念なことが一つありました。それは、店舗の画像を表示させるパラメーターが2種類しかなく、しかもどんな画像なのか事前にわからない仕様だったこと。

    当初のイメージでは、コーヒーそのものまたは室内の様子がわかる写真を並べて写真で魅せるデザインにしたかったのですが、ロゴや犬の写真が出てくることもあって(笑)、コントロールできなさそうでした。

    食べ物、飲み物、店内、外観、それらをキーワードで指定、とかできたらなお良いですね。

    コメントをどうぞ!