
xhackの勉強会「JavaScriptと無料APIを駆使してウェブアプリ開発ハンズオン」に参加してきた話
こんにちは。
りゅーそうです。
プログラミングを勉強して半年くらいになるものです。前回xhackの勉強会についてのnoteを書かせていただきました。
なので、もう「独学」は卒業ですね。JavaScript(以下JS)の基本について学んだことをまとめたので、ぜひこちらもご覧になってください。
実は同日、xhackの勉強会にもう1つ参加しておりました!
xhackの勉強会を半日。引きこもりにとっては、なかなか大変なものがありましたが、その分実りの多い勉強会になりましたので、またアウトプットもかねてレポートさせていただきます。
以下、イベントのリンクです(同勉強会は終了したようですが、おすすめの勉強会があるそうなので、そちらも最後に紹介させていただきます)。
ちなみに僕はxhackの回し者ではありません。笑
勉強会のゴール
以下のようにぐるなびの無料APIを使って、サービスを作成します。なお、すべて、JSで書きます。フレームワークなどは一切使いません!
なお、この勉強会はJSのみを使ってAPIの操作を行っていくのでサーバーサイド言語などは一切使いませんでした。
ですので、サービス全体を作るというよりはJSによるデータ送信の基礎、WebAPIの使い方を学ぶというのが目的です。
それだけに、今回の勉強会はWebAPI,JSONによるデータ送信を中心にとても実りの多いものになったので、学んだことをまとめていこうと思います!
WebAPIの前に
(JSなんか余裕だわ。WebAPIだけの話をみたいんじゃという方は読み飛ばしてください。)
今回の勉強会はJSについてはある程度知っているという前提でしたが、JSの基礎・DOM操作についても確認してくださいました!
では、みていきましょう!
1.ボタンをクリックすると、画像が表示されるイベントを発生させる。
<コード>
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>X-HACK 動画検索</title>
</head>
<body>
<!-- ボタン -->
<a class="button" onclick="addCardItem()">追加</a>
<!-- リスト -->
<div id="main-block"></div>
<script>
// 親要素を取得
const mainBlock = document.getElementById("main-block");
console.log(mainBlock);
// DOMを動的に生成している
function addCardItem() {
let node = document.createElement("div");
node.innerHTML = `<img src="https://grapee.jp/wp-content/uploads/32187_main2.jpg" alt="">`;
let pnode = document.createElement("p");
pnode.innerHTML = "追加要素";
mainBlock.appendChild(node);
mainBlock.appendChild(pnode);
}
</script>
</body>
</html>
<実行結果>
(追加ボタンを押すと、画像と文字が展開される動作をします)
コードでは、bodyにbuttonとdiv要素が用意されています。
scriptの中身をみていきます。
const mainBlock = document.getElementById("main-block");
documentとは「HTML」のことです。(前の記事にも書かせていただきましたね。)
console.logで出力してみます。macだと command + option + J ですね!
このように出力されているのがわかります。HTML要素がJSによって取得できていますね。
consoleで動作を確認する手法もよく使われるので、マスターしたいところです!
このようにHTMLをJSでDOM操作をすると表現することがあります(まあ用語については気にすることはないそうです。でもドットインストールとかで急にDOMとか出てくるとビビりますよね。僕もビビりました。笑)
HTMLはJSで表現することができるのですね!
では、次のコードです。
let node = document.createElement("div");
node.innerHTML = `<img src="https://grapee.jp/wp-content/uploads/32187_main2.jpg" alt="">`;
1行目はそのまま日本語訳すると、「HTML文書に(div)要素を追加してください」となります。そして、それを変数nodeに格納しています。
2行目のinnerHTMLとはHTMLの要素を取得、設定するメソッドです。(この場合はimg要素を変数nodeのdiv要素の中に追加しています。)
このようにMDNで調べる癖をつけておくと良いそうです。
ちなみ、MDNはなるべく英語で読むようにすると良いそうです。情報をキャッチアップするためには英語のドキュメントを読むのが必須だからです。(僕も日本語で読んじゃってますが、日本語で読んで内容を理解した後に英語で読み直したりするとだんだんと抵抗が減っていくらしいです。頑張りましょう。笑)
mainBlock.appendChild(node);
最後にこちらのコードです。
appendChild? MDNで調べましょうね〜。
親要素の末尾に子要素を追加するメソッドです。
この場合は「mainBlock」というdiv要素にnodeという要素(先ほど設定したdiv要素です。)を追加しています。
ちなみに mainBlock.appendChild(node); にある「 . 」とは一体何でしょうか?
「mainBlock」という関数に、「appendChild」というオブジェクトを渡しているという意味でしたね。
consoleのElementタグでみてみます。
HTMLを一切書いていないのに、img,p要素が追加されていることがわかります!
このようにHTMLはJavaScriptで操作できます!(分かると楽しい!)
2.1度ボタンを押すと、複数の画像が展開するイベントを発生させる。
<コード>
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>X-HACK 動画検索</title>
</head>
<body>
<!-- ボタン -->
<a class="button" onclick="addCardItem()">追加</a>
<!-- リスト -->
<div id="main-block"></div>
<script>
// 親要素を取得
const mainBlock = document.getElementById("main-block");
// JSONの代わりにデータをオブジェクトで定義
let data = [
{
image: "https://grapee.jp/wp-content/uploads/32187_main2.jpg",
description: "猫の画像1です"
},
{
image: "https://grapee.jp/wp-content/uploads/32187_main2.jpg",
description: "猫の画像2です"
},
{
image: "https://grapee.jp/wp-content/uploads/32187_main2.jpg",
description: "猫の画像3です"
}
]
// DOMを動的に生成している
function addCardItem() {
for (var i=0; i < data.length; i++) {
let element = data[i];
var node = document.createElement("div");
node.innerHTML = `<img src="${element.image}" alt=""><p>${element.description}</p>`;
mainBlock.appendChild(node);
}
}
</script>
</body>
</html>
<実行結果>
(追加ボタンを押すと3つの猫の画像と文章が展開されます。)
(猫かわいい。。。。。)
JSONでのデータ送信を行う前に、オブジェクトで複数データの送信ができるようになりましょうのコーナーです。
コードをみていきます。1と違うのはオブジェクトにデータを格納していることですね。
// JSONの代わりにデータをオブジェクトで定義
let data = [
{
image: "https://grapee.jp/wp-content/uploads/32187_main2.jpg",
description: "猫の画像1です"
},
{
image: "https://grapee.jp/wp-content/uploads/32187_main2.jpg",
description: "猫の画像2です"
},
{
image: "https://grapee.jp/wp-content/uploads/32187_main2.jpg",
description: "猫の画像3です"
}
]
それをfor文の中で呼び出しています。
function addCardItem() {
for (var i=0; i < data.length; i++) {
let element = data[i];
var node = document.createElement("div");
node.innerHTML = `<img src="${element.image}" alt=""><p>${element.description}</p>`;
mainBlock.appendChild(node);
}
}
dataオブジェクトを変数elementに格納 → innerHTMLに式展開を用いて埋め込んでいます。(データの呼び出し方も要チェックです)
基本はこれまで!いよいよWebAPIの登場です!!!
WebAPIとはなにか?
勉強会でも紹介されていたこちらのQiitaが参考になりました。(全駆け出しエンジニアが読むべき内容)
要約すると、
API = プログラムの関数(alertなど)のことと考えて良い。
APIは「Application Program Interface」の略で簡単に説明すると、どのアプリーケーションでも共通で使える機能を提供する仕組みです。
by SoftBank スマートフォン サービス開発支援サイト
だそうです。事前に機能を決めておいて、動作を簡潔にする仕組みのことと理解しておけば良いのでしょうか。
alert('こんにちは、りゅーそうです');
こうするだけで、アラートが表示されます。
詳しくはわかりませんが、alertというAPIがなければ、きっと画面を消したり、写したり、文章を表示させたりといったコードをいちいち書かなければいけないんでしょうね。APIありがとう。
HTTPなどのWeb技術の機能を用いて、作られたものをWebAPIと言うそうです。
HTTP?は?という方は同じくxhackのとよももさんのツイートがとても参考になります。
とよももの #超ざっくり解説シリーズ 第1弾 「HTTP通信とは」です!
— とよもも🍑 ハングリーエンジニア × スピーチ (@momokotoyopet) June 28, 2019
ちょっとだけパワーアップさせて再投稿!
WEBエンジニアを目指すなら必須の知識「HTTP通信(HTTPリクエストとレスポンス)をざっくり知ってみよう#xhack勉強会
(1/3) pic.twitter.com/t0lyyt8djJ
ありがたいです。素晴らしい時代だ。。。。このHTTP通信などをさっとやってくれるのがWebAPIというわけだ!(スッキリ)
このリクエストはURLで行うらしい。
https://twitter.com/home
こういうやつね。
Amazonとか、twitterとかはこのWebAPIを広めることでサービスを拡大させていったという歴史もあるらしい。(Amazonの商品とかをめちゃくちゃ売ってるアフィリエイターとかいるよね)
ぐるなびAPIを使ってみる
では実際にWebAPIを使ってみます。今回はぐるなびが無償で提供しているAPIを使います。
使い方
1.ぐるなびAPIを取得する
2.メールアドレスでAPI keyが送られてくる
3.ぐるなびAPIテストツールを使ってみる
どんなデータを返してくれるか試してみる。
このようにして、URLでリクエストを送るわけですね。
https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=7b421a28335dd5fe0d35a34055e0c566&freeword=焼肉
このようにfreeword = 焼肉 で送信した場合
{
"@attributes": {
"api_version": "v3"
},
"total_hit_count": 38105,
"hit_per_page": 10,
"page_offset": 1,
"rest": [
{
"@attributes": {
"order": 0
},
"id": "gcu5401",
"update_date": "2019-08-01T08:23:35+09:00",
"name": "焼肉×和食 日本焼肉 はせ川",
"name_kana": "ヤキニクワショクニホンヤキニクハセガワ",
"latitude": "35.671334",
"longitude": "139.761656",
"category": "焼肉と日本料理の融合",
"url": "https://r.gnavi.co.jp/1w6gcem50000/?ak=n0uJrVpDZkuM1RHLHPYzUweNy%2Bm4vo4KOmibQjsMfZ0%3D",
"url_mobile": "http://mobile.gnavi.co.jp/shop/gcu5401/?ak=n0uJrVpDZkuM1RHLHPYzUweNy%2Bm4vo4KOmibQjsMfZ0%3D",
"coupon_url": {
"pc": "",
"mobile": ""
},
"image_url": {
"shop_image1": "https://uds.gnst.jp/rest/img/1w6gcem50000/t_0n78.jpg",
"shop_image2": "https://uds.gnst.jp/rest/img/1w6gcem50000/t_0n64.jpg",
"qrcode": "https://c-r.gnst.jp/tool/qr/?id=gcu5401&q=6"
},
"address": "〒104-0061 東京都中央区銀座6-4-6 646ビル2F",
"tel": "050-3463-2284",
"tel_sub": "03-6264-5177",
"fax": "03-6264-5199",
"opentime": "月~金 ディナー:17:00~24:00(L.O.23:00)\n土・日・祝 ランチ:11:30~16:00、ディナー:16:00~24:00(L.O.23:00)",
"holiday": "不定休日あり",
"access": {
"line": "地下鉄日比谷線",
"station": "銀座駅",
"station_exit": "C2番出口",
"walk": "3",
"note": ""
},
"parking_lots": "",
"pr": {
"pr_short": "[焼肉×日本料理]焼肉の常識を打ち破る新スタイル 極上の黒毛和牛を和風に味わう新感覚の焼肉 肉・和食・野菜・飲料のプロフェッショナルが集結 完全個室:2~20名様まで",
"pr_long": "従来の焼肉の常識を打ち破り、新スタイルの焼肉を提案する『日本焼肉 はせ川』\nプロフェッショナルが集結して起こる化学反応で「新しい発見」と「感動」が生まれる…\n\n■日本焼肉という新発見\n肉のプロフェッショナルが厳選した極上の黒毛和牛を、\n醤油や味噌ベースのたれ、藻塩で食す“優しい味わい”の新スタイル焼肉\n■職人技が紡ぐ日本料理\n焼肉に加え、野菜、魚介など、一つ一つ選びぬかれた食材を使用し丁寧に作られた和食。\nソムリエが厳選したお酒を片手に、至福の時間をお過ごしください。\n■趣のある和空間\n7室ある完全個室は2~20名様まで幅広く対応\n壁には土壁を用い、器は陶芸アーティスト「内田鋼一」の作品を使用した上質な空間\n■和洋問わず充実したお飲物\nマネージャー兼ソムリエ「柴田宏史」が厳選に厳選を重ねた日本酒・ワインが豊富に揃う"
},
こんな感じのデータを返してくれたと思います。これをレスポンスといい、このデータ形式のことを「JSON」と言います。
JSONとは
データフォーマットにはCSV,XML,JSONなどがあるそうです。その中でもJSONはよく使われるデータフォーマットだそうです。
では、JSONを書いてみましょう。
obj = {
"name": "りゅーそう",
"age": 24,
"pets": {
"dog": "haru",
"cat": ["ryu", "sou", {}]
}
}
obj.pets.cat[1]
ブラウザ上でコードを簡単に実行して、試せるツール「w3schools」
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<script>
obj = {
"name": "りゅーそう",
"age": 24,
"pets": {
"dog": "haru",
"cat": ["ryu", "sou", {}]
}
}
alert(obj.name)
</script>
</body>
</html>
JSONを整形してくれるツール
便利ですね。
Ajax処理
いよいよWebAPIを用いて実装です。
まずは、焼肉と入力するとデータを表示する単純なものを実装します(単純と言いながら、苦戦した)
<コード>
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>X-HACK 動画検索</title>
</head>
<body>
<!-- 検索フォーム -->
<div class="row">
<div class="small-2 large-2 columns">検索ワード</div>
<div class="small-4 large-4 columns">
<input id="search-id" class="" type="text" placeholder="検索ワードを入力してください" />
</div>
<div class="small-6 large-4 columns">
<a class="button" onclick="loadUrl()">検索</a></div>
</div>
<!-- リスト -->
<div id="main-block" class="row small-up-1 medium-up-2 large-up-3">
</div>
<script>
// 本来はサーバー側で処理してユーザーからは見えないようにする
const API_KEY = "ここに取得したAPIkeyを入力します"; // apikeyを入力 注意:gitにapikeyを上げないように!!
const mainBlock = document.getElementById("main-block");
function loadUrl() {
while (mainBlock.firstChild) mainBlock.removeChild(mainBlock.firstChild);
let searchText = document.getElementById("search-id").value;
// URLの生成 本来はサーバー側で処理すべき(apikeyがユーザーに見えてしまうので)
let _url = `https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=${API_KEY}&freeword=焼肉`;
// Ajax(XMLHttpRequest)処理
// APIを実行して結果のJSONデータを加工している
let xhttp = new XMLHttpRequest();
// 通信が終わった時の処理
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200)
{
let res = JSON.parse(xhttp.responseText);
var hitcount = res.total_hit_count;
for (let index = 0; index < res.rest.length; index++) {
let element = res.rest[index];
let node = document.createElement("div");
node.innerHTML = element.name;
let img = document.createElement("img");
img.src = element.image_url.shop_image1;
let anker = document.createElement("a");
anker.href = element.url;
anker.innerHTML = element.url;
node.appendChild(img);
node.appendChild(anker);
mainBlock.appendChild(node);
}
}
};
// データ取得開始
xhttp.open("GET", _url, true);
xhttp.send();
}
</script>
</body>
</html>
bodyに検索フォームとデータを入れるための空のlist要素作られています。検索フォーム内で、loadUrl()というイベントを発生させています。
では、scriptの中のコードをみていきましょう。
// 本来はサーバー側で処理してユーザーからは見えないようにする
const API_KEY = "ここに取得したAPIkeyを入力します"; // apikeyを入力 注意:gitにapikeyを上げないように!!
const mainBlock = document.getElementById("main-block");
まずは定数API_KEYに先ほど取得したぐるなびAPIkeyをコピペします。
※このAPIkeyをGitにあげたり、公開してしまうとAPIが悪用されてしまう危険性があるので、公開しないようにとのことです。本来はAPIkeyはサーバーサイドで取り扱います。
先ほどイベントに設定した関数 loadUrl() の中をみていきましょう。
let searchText = document.getElementById("search-id").value;
// URLの生成 本来はサーバー側で処理すべき(apikeyがユーザーに見えてしまうので)
let _url = `https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=${API_KEY}&freeword=焼肉`;
search-idというidを持ったinputダグに入力されたvalue(値)をsearchTextに格納しています。
_url にぐるなびのテストツールで使ったURLを格納しています。(リクエスト)今回は焼肉をfreewordに設定しています。先ほどの※にも気をつけてください。
let xhttp = new XMLHttpRequest();
ついにAjax(XMLhttpRequest)通信を実装します。
まずは上記の通り、XMLhttpRequestを初期化し、xhttpに格納します。
Ajax通信についてはググってください。
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200)
{
let res = JSON.parse(xhttp.responseText);
var hitcount = res.total_hit_count;
for (let index = 0; index < res.rest.length; index++) {
let element = res.rest[index];
let node = document.createElement("div");
node.innerHTML = element.name;
let img = document.createElement("img");
img.src = element.image_url.shop_image1;
let anker = document.createElement("a");
anker.href = element.url;
anker.innerHTML = element.url;
node.appendChild(img);
node.appendChild(anker);
mainBlock.appendChild(node);
}
}
};
まずは1行目から、
xhttp.onreadystatechange
MDNでググります。
XMLHttpRequest.onreadystatechange プロパティは、 readystatechange イベントが発火するたびに、つまり XMLHttpRequest の readyState が変化するたびに呼び出されるイベントハンドラーを保持します。
だそうです。
if (this.readyState == 4 && this.status == 200)
???????????
readyStateは以下のことを示すそうです。
0 = uninitialized
1 = loading
2 = loaded
3 = interactive
4 = complete
(参考URL https://www.javadrive.jp/ajax/http/index2.html「Lets プログラミング」)
なので、「4は文書の読み込みが成功した」という意味ですね。
次にstatusですが、有名なステータスコードがありますね。
200:成功
400:リクエストが不正
500:サーバのエラー
参考URL https://qiita.com/busyoumono99/items/9b5ffd35dd521bafce47 「Qiita -WebAPIの説明-」
404番なんかはみたことがあります。
let res = JSON.parse(xhttp.responseText);
今回の勉強会の重要ポイントです。
まずはxhttp(XMLhttpRequest通信を格納した変数でしたね)にresponseTextというオブジェクトを渡しています。
ですが与えられたデータがJSONのままなので、変換する必要があります。JSON文字列を引数に取り、それに対する JavaScript オブジェクトを返すメソッドがJSON.parseです
ここまでできたら、あとはfor文の中で、欲しいデータを探して、DOM操作をして表示させるだけですね!(わからない場合はWebAPIの前にを確認。)
ちなみにfor文の中のrestとは
{
"@attributes": {
"api_version": "v3"
},
"total_hit_count": 38107,
"hit_per_page": 10,
"page_offset": 1,
"rest": [
{
"@attributes": {
"order": 0
},
"id": "gcu5401",
"update_date": "2019-08-01T08:23:35+09:00",
"name": "焼肉×和食 日本焼肉 はせ川",
"name_kana": "ヤキニクワショクニホンヤキニクハセガワ",
"latitude": "35.671334",
"longitude": "139.761656",
"category": "焼肉と日本料理の融合",
"url": "https://r.gnavi.co.jp/1w6gcem50000/?ak=n0uJrVpDZkuM1RHLHPYzUweNy%2Bm4vo4KOmibQjsMfZ0%3D",
"url_mobile": "http://mobile.gnavi.co.jp/shop/gcu5401/?
JSONデータのrestですね!欲しいデータをfor文の中で取得してるわけです。テストツール、サイトでどんなデータがあるのか、確認してみましょう。
これでとりあえず以上になります。
おつかれさまでした。(自分に向けて)
完成品
CSSを整えて、freewordに入力したデータを設定すると以下のようなものが完成します。
note投稿用成果物 pic.twitter.com/Z4T80yZRnp
— りゅーそう🌐エンジニア(を目指してる人) (@ryusou_mtkh) August 1, 2019
すごい!!!(語彙力)
まとめ
今回の勉強会で学んだこと
・JSのDOM操作、オブジェクトの書き方について
・JSONについて
・WebAPIについて
・Ajax通信の実装について
数時間で、JSの基礎からAjax通信のことについて、手を動かしながら学べる勉強会控え目に言って、最高だと思います。
勉強会ではそれぞれ自分で考えてコードを書きながら進めていくスタイルだったので、とても楽しかったです!
xhackさん本当にありがとうございました!
しかし、今回の成果物はAPIkeyが公開されてしまっているため、GitHubにあげたり、公開することができません。
そこで、なんと、、、、サーバーサイド言語であるRubyでAPIサーバーを構築するとても楽しそうな勉強会を開催するそうです。(以下リンクです)
めちゃくちゃ楽しそう。。。僕はしばらくRubyやってないので、断念しますが。。。
負けじとNodeとかを使って、今回勉強したことを生かして、何か簡単なサービスを作ろうかと思っております!
学んでも、アウトプットしないと意味ないですしね!
ということで、今回もだらだらと長文になってしまいましたが、ここまでお付き合いしてくださった方本当にありがとうございました。
何か誤っている点などございましたら、ご教授してくださるとありがたいです。
ではでは!りゅーそうでした!