見出し画像

【データの集め方講座】Node.jsでAPIからデータを取得-コードの解説多め-

はじめに


ご高覧いただきありがとうございます.
ソフトウェアエンジニアのKitaharaです.
本日は先日紹介したNode.jsでAPIにリクエストを送り情報を取得する方法を解説します.

Node.jsでデータを取得するメリット


モダンなフロントエンドからリクエストを送れる

Node.jsを使うモチベーションとしてはReact.jsVue.jsといったモダンなフロントエンドからリクエストを送ることにあります.

React.jsやVue.jsといったユーザーインターフェースを構築するJavaScriptライブラリが近年盛り上がりを見せています.

有名どころだとFacebookやNetFlix, Uber, Teslaといった会社が利用しています. プログラマの方ですと, Progateで勉強したことがある方もいると思いますが, ProgateもReact.jsで書かれています.

ReactやVueはJavaScriptで出来ているのでリクエストを送るときも通常はJavaScriptを使います. 以上のことが, JavaScriptでリクエストを送るモチベーションに繋がります.

補足:ReactやVueに興味がある方

ReactやVueの素晴らしさに関しましては他のエンジニアの方が既に議論し尽くしていると思うので本記事では省略します.

興味がある方はまず公式ライブラリから素晴らしさを体験することをお勧めします.


非同期の関数を使います


今回はaxios(アクシオス)というライブラリの関数axios()を使うのですが, 非同期処理を使うため解説を載せておきます.
(知っている方は読み飛ばしていただいて結構です)

非同期処理とは

ある処理の終了を待たずに次の処理をすることです.
言葉にすると難しいので具体例を見てみることにします.

非同期処理を理解する例としてよく食べ物屋さんが挙げられます.
ラーメン屋さんで友人とラーメンを注文する場面を思い浮かべてください.

私「豚骨ラーメン下さい」
お店の方「豚骨一丁!」
友人「味噌ラーメン下さい」
お店の方「味噌一丁!」

(5分後)

お店の方「豚骨お待ち同様!」
お店の方「味噌お待ち同様!」

このお店の方のタスクの処理の仕方が非同期処理です.
比較のために同期処理の場合のラーメン屋さんも見てみましょう

私「豚骨ラーメン下さい」
お店の方「豚骨一丁!」

(5分後)

お店の方「豚骨お待ち同様!」
友人「味噌ラーメン下さい」
お店の方「味噌一丁!」

(5分後)

お店の方「味噌お待ち同様!」

何となく伝わりましたでしょうか?

同期処理のラーメン屋さんではタスクを前から順番の処理したのに対して非同期処理のラーメン屋さんでは時間のかかるタスク(ラーメンの調理)を後回ししていることがわかります.


処理をするのを待ちたいこともある

先ほどのラーメン屋さんでは非同期処理を使うことによって効率的に商売をすることができていました. 一方で非同期処理を同期的に使いたいことがあります. こちらも例を見てみましょう.

結婚指輪を渡す男性を思い浮かべてください.

男性「付き合って3年の彼女にプロポーズするぞ!」
男性「指輪と花束を買ってデートに誘おう!」

これを非同期処理で行おうとすると以下のようなことが起こりえます

男性「指輪と花束を買うタスクは時間がかかるから予約を先に行おう」
男性「彼女をデートに誘おう」
男性「彼女からOKもらえた!」

デート当日

宝石店の方「大変申し訳ありませんが, 船便の影響で納期が遅れそうです」
男性「そうですか, 承知しました(どうしよう!これじゃプロポーズできないぞ!)

この場合は指輪が届くのを待つというタスクを後回しにしてしまったので当日に指輪がないという事態になってしまいました.

このようなことはプログラミングでも起こりえる話です. 例えば, のちの処理に使う変数を定義している部分が非同期処理であったために変数が参照エラーになってしまうといったことが起こる可能性があります.

今回使うJavaScriptのリクエストの処理も非同期の関数です.
すなわち, 結果が得られるまで待つという動作がないとリクエストの結果が格納される変数の参照エラーが起こります.

これを回避するために「非同期の処理が終わるまで待つ」方法がJavaScriptには存在しています. それではコードを見ていきましょう.


コードを見てみる

下記のコードを見てください. 今回は先ほどの「非同期処理が終わるまで待つ」方法を使ってNote APIという非公式のAPIから情報を取得しています

const axios = require('axios'); 

(async () => { 
    try { 
        const target_user = 'kitahara_note'
        const url_ = 'https://note.com/api/v2/creators/'+target_user+'/contents?kind=note&page=1'
        const response = await axios({
            method: 'get',
            url: url_
        });
        console.log(response.status); 
        console.log(response.statusText);
        const contents = response.data.data.contents;
        console.log(contents[0].name)
        console.log(contents[0].likeCount)
        console.log(contents[0].noteUrl)
    } catch (error) { 
        console.log(error); 
    } 
})();

出力は以下のようになります.

200
OK
【データの集め方講座】Pythonで株式情報を収集しMySQLに保存
14
https://note.com/kitahara_note/n/nfa667a2d3dfa

初めて見る人にとっては少し厳ついコードかもしれません.

初学者にとって難しい理由はいくつかあります

  • 即時関数を使っている

  • Promiseという概念が暗黙的に使われている

  • Promiseを理解したうえでasync(エイシンク)とawaitを使う必要がある

つまづきポイント1: 即時関数

一つ目の即時関数から解説します.

test.js

(
    () => {
        console.log('Hello');
    }
)();

Tearminal

$ node test.js
Hello

このようにJavaScriptは無名関数を()で囲ったうえで関数のように書くとその場で実行される関数を作ることができます. 最後の();の部分は以下のshowHello();の();に当たります.

const showHello = () => {
    console.log('Hello');
}
showHello();

つまづきポイント2: 見えないPromise

二つ目はPromiseという概念を知らないといけないということです.
asyncという概念はPromiseの延長線上にあり, Promiseを知らないと理解することは難しいです. 初心者にとって難しい点はコード上にPromiseの文がかかれないことがあることです.

例えば, 今回のコードのaxios関数はPromiseを返しますが, Promiseの文はコード上に現れません.

const axios = require('axios'); 

(async () => { 
    try { 
        const target_user = 'kitahara_note'
        const url_ = 'https://note.com/api/v2/creators/'+target_user+'/contents?kind=note&page=1'
        const response = await axios({
            method: 'get',
            url: url_
        }); // Promiseを返す関数
    } catch (error) { 
        console.log(error); 
    } 
})();

先ほどから出ているPromiseとは何でしょうか?

PromiseはJavaScriptにおいて「非同期処理を待つ処理」を実装するものです. 以下のコードを見てください.

const showName = (name) => {
    return (
        new Promise((resolve, reject) => {
            // ここに非同期の処理を書く
            if (typeof name === 'string') {
                resolve(name);
            } else {
                reject('type of name should be string');
            }
        })
    )
}
showName('Kitahara')
    .then((result) => {console.log(result)})
    .catch((error) => {console.log(error)})

まず, 関数がreturnではなく, resolveとrejectを返していることに注意します.
これは目的の処理ができた場合にresolve()をreturnの代わりに書き, 想定外のことが起こった際にrejectを書くようにします.

すると, 「関数が実行された後」に実行結果がfullfill(成功)だった場合は.thenが実行され, errorだった場合には.catchが実行されます.

上記の場合.thenが実行されて result(関数内のresolveの中身) が出力されます.

つまづきポイント3: async & await

上記のPromiseがあればすべて解決しそうに一見見えますが, 可読性に問題があります. 例えば, 先ほどの.thenの中身が非同期でさらに.thenが積み重なったらどうなるでしょうか?

一つなら何とかなるかもしれませんが, 複数だと読みにくくなってしまいます. この問題をasyncとawaitを使うと簡単にすることができます.

const showName = (name) => {
    return (
        new Promise((resolve, reject) => {
            if (typeof name == 'string') {
                resolve(name);
            } else {
                reject('type of name should be string');
            }
        })
    )
}
(
    async () => {
        try {
            const name = await showName('Kitahara')
            console.log(name) // awaitするため正常に実行される
            const error_variable = await showName(39)
            console.log(name) // catchされるため実行されない
        } catch(error) {
            console.log(error);
        }

    }
)();

awaitと書くと関数の実行を非同期にすることができます.
成功するとconstで定義したオブジェクトにresolve()の引数が入り, 失敗するとcatchの方に処理が行きます. 出力結果は以下のようになります.

Kitahara
type of name should be string

ここまで来れれば最初のコードを理解できると思います

Node.jsでAPIを叩く方法

というわけでaxiosを使うと一発でデータを取得することができます.
JavaScriptの性質上, 初学者の方は読むことに苦労したかもしれませんが, 経験を積んでいくにつれて徐々に読みやすくなっていくと思います!

const axios = require('axios'); 

(async () => { 
    try { 
        const target_user = 'kitahara_note'
        const url_ = 'https://note.com/api/v2/creators/'+target_user+'/contents?kind=note&page=1'
        const response = await axios({
            method: 'get',
            url: url_
        });
        console.log(response.status); 
        console.log(response.statusText);
        const contents = response.data.data.contents;
        console.log(contents[0].name)
        console.log(contents[0].likeCount)
        console.log(contents[0].noteUrl)
    } catch (error) { 
        console.log(error); 
    } 
})();

おわりに


今回はNode.jsを使ってAPIからデータを収集する方法を解説しました!
参考になったという方はぜひハートボタンを押していってください!

モチベーションが上がります!

記事内で不明な点等ございましたら気軽にご連絡ください.

Twitter: @kitahara_dev
email: kitahara.main1@gmail.com

===> Pythonを使ったAPIから情報を取得する方法も解説しています!

参考文献



この記事が気に入ったらサポートをしてみませんか?