ノード入門:API、HTTP、ES6 + JavaScriptの概要
公開: 2022-03-10Node.jsは、「ChromeのV8 JavaScriptエンジン上に構築された非同期JavaScriptランタイム」であり、「軽量で効率的なイベント駆動型の非ブロッキングI / Oモデルを使用している」と聞いたことがあるでしょう。 しかし、一部の人にとっては、それは最大の説明ではありません。
そもそもノードとは? ノードが「非同期」であるとはどういう意味ですか?それは「同期」とどのように異なりますか? とにかく「イベント駆動型」と「ノンブロッキング」の意味は何ですか。また、Nodeはアプリケーション、インターネットネットワーク、サーバーの全体像にどのように適合しますか?
Nodeの内部動作を詳しく調べ、HyperText Transfer Protocol、API、JSONについて学び、独自のBookshelf APIを構築しながら、このシリーズ全体でこれらすべての質問に答えようと試みます。 MongoDB、Express、Lodash、Mocha、およびハンドルバー。
Node.jsとは
ノードは、ブラウザーの外部で通常のJavaScript(わずかな違いはあります)を実行するための環境またはランタイムにすぎません。 これを使用して、デスクトップアプリケーション(Electronなどのフレームワークを使用)を構築したり、Webサーバーやアプリサーバーを作成したりできます。
ブロッキング/非ブロッキングおよび同期/非同期
ユーザーに関するプロパティを取得するためにデータベース呼び出しを行っているとします。 その呼び出しには時間がかかります。要求が「ブロック」されている場合は、呼び出しが完了するまでプログラムの実行がブロックされることを意味します。 この場合、スレッドをブロックしてしまうため、「同期」リクエストを行いました。
したがって、同期操作は、その操作が完了するまでプロセスまたはスレッドをブロックし、スレッドを「待機状態」のままにします。 一方、非同期操作は非ブロッキングです。 これにより、操作の完了にかかる時間や完了した結果に関係なく、スレッドの実行を続行でき、スレッドのどの部分も待機状態に陥ることはありません。
スレッドをブロックする同期呼び出しの別の例を見てみましょう。 2つのWeatherAPIの結果を比較して、温度のパーセント差を見つけるアプリケーションを構築しているとします。 ブロッキング方式で、Weather API Oneを呼び出し、結果を待ちます。 結果を取得したら、Weather API Twoを呼び出し、その結果を待ちます。 APIに慣れていなくても、この時点で心配する必要はありません。 これらについては、次のセクションで説明します。 今のところ、APIは、2台のコンピューターが相互に通信するための媒体と考えてください。

注意してください。すべての同期呼び出しが必ずしもブロックされているわけではないことを認識することが重要です。 同期操作がスレッドをブロックしたり待機状態を引き起こしたりせずに完了できる場合、それは非ブロックでした。 ほとんどの場合、同期呼び出しはブロックされ、完了するまでにかかる時間は、APIのサーバーの速度、エンドユーザーのインターネット接続のダウンロード速度などのさまざまな要因によって異なります。
上の画像の場合、APIOneから最初の結果を取得するのにかなりの時間がかかりました。 その後、APITwoからの応答を取得するまで同じくらい待つ必要がありました。 両方の応答を待っている間、ユーザーはアプリケーションがハングすることに気付くでしょう— UIは文字通りロックされます—そしてそれはユーザーエクスペリエンスに悪いでしょう。
ノンブロッキングコールの場合、次のようになります。

実行がどれだけ速く完了したかがはっきりとわかります。 API1を待ってからAPI2を待つのではなく、両方が同時に完了するのを待って、結果をほぼ50%速く達成することができます。 API Oneを呼び出してその応答を待ち始めたら、API Twoも呼び出して、Oneと同時に応答を待ち始めたことに注意してください。
この時点で、より具体的で具体的な例に移る前に、簡単にするために、 「同期」という用語は一般に「同期」に短縮され、 「非同期」という用語は一般に「非同期」に短縮されることに注意してください。 メソッド/関数名で使用されているこの表記が表示されます。
コールバック関数
「呼び出しを非同期で処理できる場合、その呼び出しがいつ終了し、応答があるかをどのようにして知ることができますか?」と疑問に思われるかもしれません。 一般に、非同期メソッドに引数としてコールバック関数を渡します。そのメソッドは、後で応答を使用してその関数を「コールバック」します。 ここではES5関数を使用していますが、後でES6標準に更新します。
function asyncAddFunction(a, b, callback) { callback(a + b); //This callback is the one passed in to the function call below. } asyncAddFunction(2, 4, function(sum) { //Here we have the sum, 2 + 4 = 6. });
このような関数は、関数(コールバック)を引数として取るため、「高階関数」と呼ばれます。 あるいは、コールバック関数は引数としてエラーオブジェクトと応答オブジェクトを受け取り、非同期関数が完了したときにそれらを提示する場合があります。 これについては、後でExpressで確認します。 asyncAddFunction(...)
を呼び出すと、メソッド定義からコールバックパラメーターのコールバック関数が提供されていることがわかります。 この関数は無名関数(名前はありません)であり、式の構文を使用して記述されています。 一方、メソッド定義は関数ステートメントです。 実際には名前(「asyncAddFunction」)があるため、匿名ではありません。
メソッド定義では、「コールバック」という名前を指定しているため、混乱を招く場合があります。 ただし、 asyncAddFunction(...)
に3番目のパラメーターとして渡された無名関数は名前を認識しないため、匿名のままです。 また、後でその関数を名前で実行することはできません。非同期呼び出し関数を再度実行して、関数を起動する必要があります。
同期呼び出しの例として、Node.jsのreadFileSync(...)
メソッドを使用できます。 繰り返しになりますが、後でES6 +に移行します。
var fs = require('fs'); var data = fs.readFileSync('/example.txt'); // The thread will be blocked here until complete.
これを非同期で行う場合は、非同期操作が完了したときに起動するコールバック関数を渡します。
var fs = require('fs'); var data = fs.readFile('/example.txt', function(err, data) { //Move on, this will fire when ready. if(err) return console.log('Error: ', err); console.log('Data: ', data); // Assume var data is defined above. }); // Keep executing below, don't wait on the data.
これまでにそのように使用されたreturn
を見たことがない場合は、関数の実行を停止するように言っているだけなので、エラーオブジェクトが定義されている場合はデータオブジェクトを出力しません。 logステートメントをelse
句でラップすることもできます。
asyncAddFunction(...)
のように、 fs.readFile(...)
関数の背後にあるコードは次のようになります。
function readFile(path, callback) { // Behind the scenes code to read a file stream. // The data variable is defined up here. callback(undefined, data); //Or, callback(err, undefined); }
非同期関数呼び出しの最後の実装を見てみましょう。 これは、コールバック関数が後で実行されるという考えを固めるのに役立ち、典型的なNode.jsプログラムの実行を理解するのに役立ちます。
setTimeout(function() { // ... }, 1000);
setTimeout(...)
メソッドは、最初のパラメーターのコールバック関数を受け取ります。このコールバック関数は、2番目の引数として指定されたミリ秒数が発生した後に発生します。
より複雑な例を見てみましょう。
console.log('Initiated program.'); setTimeout(function() { console.log('3000 ms (3 sec) have passed.'); }, 3000); setTimeout(function() { console.log('0 ms (0 sec) have passed.'); }, 0); setTimeout(function() { console.log('1000 ms (1 sec) has passed.'); }, 1000); console.log('Terminated program');
私たちが受け取る出力は次のとおりです。
Initiated program. Terminated program. 0 ms (0 sec) have passed. 1000 ms (1 sec) has passed. 3000 ms (3 sec) have passed.
最初のログステートメントが期待どおりに実行されていることがわかります。 瞬時に、最後のログステートメントが画面に出力されます。これは、2番目のsetTimeout(...)
の後に0秒が経過する前に発生します。 その後すぐに、2番目、3番目、および1番目のsetTimeout(...)
メソッドが実行されます。
Node.jsが非ブロッキングでない場合は、最初のログステートメントが表示され、3秒待って次のステートメントが表示され、すぐに3番目のステートメントが表示されます(0秒のsetTimeout(...)
。その後、もう1つ待機する必要があります。 2番目に最後の2つのログステートメントを確認します。Nodeの非ブロッキング性により、すべてのタイマーは、入力された順序ではなく、プログラムが実行された瞬間からカウントダウンを開始します。NodeAPIを調べると、ノードが内部でどのように機能するかについての詳細は、コールスタックとイベントループを参照してください。
コールバック関数が表示されたからといって、必ずしもコードに非同期呼び出しがあるとは限らないことに注意してください。 サーバーの呼び出しなど、操作の完了には時間がかかると想定しているため、上記の「async」でasyncAddFunction(…)
メソッドを呼び出しました。 実際には、2つの数値を加算するプロセスは非同期ではないため、実際には、スレッドを実際にブロックしない方法でコールバック関数を使用する例になります。
コールバックの約束
JavaScriptでは、特に複数のネストされたコールバックでは、コールバックがすぐに乱雑になる可能性があります。 関数への引数としてコールバックを渡すことはよく知っていますが、Promisesを使用すると、関数から返されたオブジェクトにコールバックをタックまたはアタッチできます。 これにより、複数の非同期呼び出しをよりエレガントな方法で処理できるようになります。
例として、API呼び出しを行っていて、「 makeAPICall(...)
」という一意の名前ではない関数がURLとコールバックを受け取るとします。
私たちの関数makeAPICall(...)
は、次のように定義されます。
function makeAPICall(path, callback) { // Attempt to make API call to path argument. // ... callback(undefined, res); // Or, callback(err, undefined); depending upon the API's response. }
そして、私たちはそれを次のように呼びます:
makeAPICall('/example', function(err1, res1) { if(err1) return console.log('Error: ', err1); // ... });
最初の応答を使用して別のAPI呼び出しを行う場合は、両方のコールバックをネストする必要があります。 res1
オブジェクトから2番目のAPI呼び出しのパスにuserName
プロパティを挿入する必要があるとします。 私たちは持っているでしょう:
makeAPICall('/example', function(err1, res1) { if(err1) return console.log('Error: ', err1); makeAPICall('/newExample/' + res1.userName, function(err2, res2) { if(err2) return console.log('Error: ', err2); console.log(res2); }); });
注:文字列の連結ではなくres1.userName
プロパティを挿入するES6 +メソッドは、「テンプレート文字列」を使用することです。 そうすれば、文字列を引用符( '
、または"
)でカプセル化するのではなく、キーボードのEscキーの下にあるバッククォート( `
)を使用します。次に、表記${}
を使用してJS式を内部に埋め込みます。最後に、以前のパスは/newExample/${res.UserName}
で、バッククォートで囲まれています。
コールバックをネストするこの方法は、すぐに非常にエレガントでなくなる可能性があることは明らかです。いわゆる「JavaScript PyramidofDoom」です。 コールバックではなくpromiseを使用している場合は、最初の例のコードを次のようにリファクタリングできます。
makeAPICall('/example').then(function(res) { // Success callback. // ... }, function(err) { // Failure callback. console.log('Error:', err); });
then()
関数の最初の引数は成功コールバックであり、2番目の引数は失敗コールバックです。 または、 .then()
の2番目の引数を失い、代わりに.catch()
を呼び出すこともできます。 .then()
の引数はオプションであり、 .catch()
の呼び出しは.then(successCallback, null)
と同等です。
.catch()
を使用すると、次のようになります。
makeAPICall('/example').then(function(res) { // Success callback. // ... }).catch(function(err) { // Failure Callback console.log('Error: ', err); });
読みやすくするためにこれを再構築することもできます。
makeAPICall('/example') .then(function(res) { // ... }) .catch(function(err) { console.log('Error: ', err); });
.then()
呼び出しを関数に追加して、それが機能することを期待することはできないことに注意することが重要です。 呼び出している関数は、実際にpromiseを返す必要があります。これは、非同期操作が完了したときに.then()
を起動するpromiseです。 この場合、 makeAPICall(...)
がそれを実行し、完了時にthen()
ブロックまたはcatch()
ブロックのいずれかを起動します。
makeAPICall(...)
がPromiseを返すようにするには、関数を変数に割り当てます。この関数はPromiseコンストラクターです。 約束は履行または拒否されます。履行された場合は、約束に関連するアクションが正常に完了したことを意味し、拒否された場合はその逆を意味します。 約束が履行または拒否されると、それは解決したと言い、それが解決するのを待っている間、おそらく非同期呼び出し中に、約束は保留中であると言います。
Promiseコンストラクターは、1つのコールバック関数を引数として受け取ります。これは2つのパラメーター( resolve
とreject
)を受け取ります。これらのパラメーターは、後で呼び出して、 .then()
の成功コールバックまたは.then()
失敗のいずれかを起動します。コールバック、または提供されている場合は.catch()
。
これがどのように見えるかの例を次に示します。
var examplePromise = new Promise(function(resolve, reject) { // Do whatever we are going to do and then make the appropiate call below: resolve('Happy!'); // — Everything worked. reject('Sad!'); // — We noticed that something went wrong. }):
次に、次を使用できます。
examplePromise.then(/* Both callback functions in here */); // Or, the success callback in .then() and the failure callback in .catch().
ただし、 examplePromise
は引数を取ることができないことに注意してください。 そのようなものは目的を破るので、代わりに約束を返すことができます。
function makeAPICall(path) { return new Promise(function(resolve, reject) { // Make our async API call here. if (/* All is good */) return resolve(res); //res is the response, would be defined above. else return reject(err); //err is error, would be defined above. }); }
Promiseは、「Promise Chaining」の概念を使用して、コードの構造を改善し、その後、優雅さを向上させるために本当に輝いています。 これにより、 .then()
句内に新しいPromiseを返すことができるため、その後に2番目の.then()
をアタッチして、2番目のPromiseから適切なコールバックを起動できます。
上記のマルチAPIURL呼び出しをPromisesでリファクタリングすると、次のようになります。
makeAPICall('/example').then(function(res) { // First response callback. Fires on success to '/example' call. return makeAPICall(`/newExample/${res.UserName}`); // Returning new call allows for Promise Chaining. }, function(err) { // First failure callback. Fires if there is a failure calling with '/example'. console.log('Error:', err); }).then(function(res) { // Second response callback. Fires on success to returned '/newExample/...' call. console.log(res); }, function(err) { // Second failure callback. Fire if there is a failure calling with '/newExample/...' console.log('Error:', err); });
最初にmakeAPICall('/example')
を呼び出すことに注意してください。 それは約束を返すので、 .then()
を添付します。 そのthen()
内で、 makeAPICall(...)
への新しい呼び出しを返します。これは、前に見たように、それ自体でpromiseを返し、最初の後に新しい.then()
をチェーンできるようにします。
上記のように、読みやすくするためにこれを再構築し、ジェネリックcatch()
all句の失敗コールバックを削除できます。 そうすれば、DRY Principle(Do n't Repeat Yourself)に従うことができ、エラー処理を1回だけ実装する必要があります。
makeAPICall('/example') .then(function(res) { // Like earlier, fires with success and response from '/example'. return makeAPICall(`/newExample/${res.UserName}`); // Returning here lets us chain on a new .then(). }) .then(function(res) { // Like earlier, fires with success and response from '/newExample'. console.log(res); }) .catch(function(err) { // Generic catch all method. Fires if there is an err with either earlier call. console.log('Error: ', err); });
.then()
の成功と失敗のコールバックは、 .then()
が対応する個々のPromiseのステータスに対してのみ起動することに注意してください。 ただし、 catch
ブロックは、 .then()
のいずれかで発生するエラーをキャッチします。
ES6 Const vs. Let
すべての例を通して、ES5関数と古いvar
キーワードを使用しています。 現在でも数百万行のコードがこれらのES5メソッドを使用して実行されていますが、現在のES6 +標準に更新すると便利であり、上記のコードの一部をリファクタリングします。 const
から始めて、 let
。
var
キーワードを使用して変数を宣言することに慣れているかもしれません。
var pi = 3.14;
ES6 +標準を使用すると、どちらかを作成できます
let pi = 3.14;
また
const pi = 3.14;
ここで、 const
は「定数」を意味します—後で再割り当てできない値です。 (オブジェクトのプロパティを除いて、これについてはすぐに説明します。また、 const
と宣言された変数は不変ではなく、変数への参照のみが不変です。)
古いJavaScriptでは、 if
、 while
、 {}
などのスコープをブロックします。 for
などはvar
にまったく影響を与えませんでした。これは、JavaやC ++などのより静的に型指定された言語とはまったく異なります。 つまり、 var
のスコープは、囲んでいる関数全体です。これは、グローバル(関数の外部に配置されている場合)またはローカル(関数内に配置されている場合)の場合があります。 これを示すために、次の例を参照してください。
function myFunction() { var num = 5; console.log(num); // 5 console.log('--'); for(var i = 0; i < 10; i++) { var num = i; console.log(num); //num becomes 0 — 9 } console.log('--'); console.log(num); // 9 console.log(i); // 10 } myFunction();
出力:
5 --- 0 1 2 3 ... 7 8 9 --- 9 10
ここで注意すべき重要な点は、 for
スコープ内で新しいvar num
を定義すると、forの外側と上のvar num
に直接影響することfor
。 これは、 var
のスコープが常に囲んでいる関数のスコープであり、ブロックではないためです。
繰り返しになりますが、デフォルトでは、 for()
内のvar i
はデフォルトでmyFunction
のスコープになっているため、ループの外側でi
にアクセスして10を取得できます。
変数に値を割り当てるという点では、 let
はvar
と同等であり、 let
にブロックスコープがあるだけなので、上記のvar
で発生した異常は発生しません。
function myFunction() { let num = 5; console.log(num); // 5 for(let i = 0; i < 10; i++) { let num = i; console.log('--'); console.log(num); // num becomes 0 — 9 } console.log('--'); console.log(num); // 5 console.log(i); // undefined, ReferenceError }
const
キーワードを見ると、再割り当てしようとするとエラーが発生することがわかります。
const c = 299792458; // Fact: The constant "c" is the speed of light in a vacuum in meters per second. c = 10; // TypeError: Assignment to constant variable.
const
変数をオブジェクトに割り当てると、物事は興味深いものになります。
const myObject = { name: 'Jane Doe' }; // This is illegal: TypeError: Assignment to constant variable. myObject = { name: 'John Doe' }; // This is legal. console.log(myObject.name) -> John Doe myObject.name = 'John Doe';
ご覧のとおり、 const
オブジェクトに割り当てられたオブジェクトへのメモリ内の参照のみが不変であり、値自体は不変ではありません。
ES6アロー機能
次のような関数を作成することに慣れているかもしれません。
function printHelloWorld() { console.log('Hello, World!'); }
矢印関数を使用すると、次のようになります。
const printHelloWorld = () => { console.log('Hello, World!'); };
数値の2乗を返す単純な関数があるとします。
const squareNumber = (x) => { return x * x; } squareNumber(5); // We can call an arrow function like an ES5 functions. Returns 25.
ES5関数の場合と同様に、括弧付きの引数を取り、通常のreturnステートメントを使用でき、他の関数と同じように関数を呼び出すことができます。
関数が引数をとらない場合は括弧が必要ですが(上記のprintHelloWorld()
の場合のように)、括弧が1つしかない場合は括弧を削除できるため、以前のsquareNumber()
メソッド定義は次のように書き直すことができます。
const squareNumber = x => { // Notice we have dropped the parentheses for we only take in one argument. return x * x; }
単一の引数を括弧で囲むことを選択するかどうかは個人的な好みの問題であり、開発者が両方の方法を使用するのを目にする可能性があります。
最後に、上記のsquareNumber(...)
のように、暗黙的に1つの式のみを返したい場合は、returnステートメントをメソッドのシグネチャに合わせることができます。
const squareNumber = x => x * x;
あれは、
const test = (a, b, c) => expression
と同じです
const test = (a, b, c) => { return expression }
上記の省略形を使用して暗黙的にオブジェクトを返す場合、物事があいまいになることに注意してください。 オブジェクトをカプセル化するために必要な角かっこが関数本体ではないとJavaScriptが信じないのはなぜですか? これを回避するために、オブジェクトの角かっこをかっこで囲みます。 これにより、JavaScriptは、実際にオブジェクトを返していることを明示的に通知します。これは、本体を定義しているだけではありません。
const test = () => ({ pi: 3.14 }); // Spaces between brackets are a formality to make the code look cleaner.
ES6関数の概念を固めるために、以前のコードの一部をリファクタリングして、両方の表記の違いを比較できるようにします。
asyncAddFunction(...)
は、上から、次の場所からリファクタリングできます。
function asyncAddFunction(a, b, callback){ callback(a + b); }
に:
const aysncAddFunction = (a, b, callback) => { callback(a + b); };
またはに:
const aysncAddFunction = (a, b, callback) => callback(a + b); // This will return callback(a + b).
関数を呼び出すときに、コールバック用に矢印関数を渡すことができます。
asyncAddFunction(10, 12, sum => { // No parentheses because we only take one argument. console.log(sum); }
このメソッドがコードの可読性をどのように改善するかは明らかです。 1つのケースだけを示すために、上記の古いES5 Promiseベースの例を取り上げ、矢印関数を使用するようにリファクタリングすることができます。
makeAPICall('/example') .then(res => makeAPICall(`/newExample/${res.UserName}`)) .then(res => console.log(res)) .catch(err => console.log('Error: ', err));
さて、矢印機能に関するいくつかの警告があります。 1つは、 this
キーワードをバインドしないことです。 次のオブジェクトがあるとします。
const Person = { name: 'John Doe', greeting: () => { console.log(`Hi. My name is ${this.name}.`); } }
Person.greeting()
を呼び出すと、「こんにちは。 私の名前はJohnDoeです。」 代わりに、次のようになります。 私の名前は未定義です。」 これは、矢印関数にはthis
がないため、矢印関数内でthis
を使用しようとすると、デフォルトで囲んでいるスコープのthis
になり、 Person
オブジェクトの囲んでいるスコープはwindow
、ブラウザ、またはmodule.exports
inノード。
これを証明するために、同じオブジェクトを再度使用し、グローバルthis
のname
プロパティを「JaneDoe」のようなものに設定すると、矢印関数のthis.name
は「JaneDoe」を返します。これは、グローバルthis
がスコープを囲むか、 Person
オブジェクトの親です。
this.name = 'Jane Doe'; const Person = { name: 'John Doe', greeting: () => { console.log(`Hi. My name is ${this.name}.`); } } Person.greeting(); // Hi. My name is Jane Doe
これは「LexicalScoping」として知られており、いわゆる「Short Syntax」を使用して回避できます。これは、オブジェクトをリファクタリングするためにコロンと矢印を失う場所です。
const Person = { name: 'John Doe', greeting() { console.log(`Hi. My name is ${this.name}.`); } } Person.greeting() //Hi. My name is John Doe.
ES6クラス
JavaScriptはクラスをサポートしていませんが、上記のようなオブジェクトでいつでもクラスをエミュレートできます。 EcmaScript 6は、 class
とnew
キーワードを使用したクラスのサポートを提供します。
class Person { constructor(name) { this.name = name; } greeting() { console.log(`Hi. My name is ${this.name}.`); } } const person = new Person('John'); person.greeting(); // Hi. My name is John.
new
キーワードを使用すると、コンストラクター関数が自動的に呼び出されます。このキーワードに引数を渡して、オブジェクトを最初に設定できます。 これは、Java、C ++、C#などの静的に型付けされたオブジェクト指向プログラミング言語の経験がある読者なら誰でも知っているはずです。
OOPの概念についてあまり詳しく説明しなくても、そのような別のパラダイムは「継承」です。これは、あるクラスが別のクラスから継承できるようにすることです。 たとえば、 Car
と呼ばれるクラスは非常に一般的で、すべての車が必要とする「stop」、「start」などのメソッドが含まれます。 したがって、 SportsCar
と呼ばれるクラスのサブセットは、 Car
から基本的な操作を継承し、カスタムが必要なものをすべてオーバーライドする可能性があります。 このようなクラスは次のように表すことができます。
class Car { constructor(licensePlateNumber) { this.licensePlateNumber = licensePlateNumber; } start() {} stop() {} getLicensePlate() { return this.licensePlateNumber; } // … } class SportsCar extends Car { constructor(engineRevCount, licensePlateNumber) { super(licensePlateNumber); // Pass licensePlateNumber up to the parent class. this.engineRevCount = engineRevCount; } start() { super.start(); } stop() { super.stop(); } getLicensePlate() { return super.getLicensePlate(); } getEngineRevCount() { return this.engineRevCount; } }
super
キーワードを使用すると、親クラスまたはsuperクラスからプロパティとメソッドにアクセスできることがはっきりとわかります。
JavaScriptイベント
イベントは、あなたが応答する能力を持っている発生するアクションです。 アプリケーションのログインフォームを作成しているとします。 ユーザーが「送信」ボタンを押すと、コード内の「イベントハンドラー」(通常は関数)を介してそのイベントに反応できます。 この関数がイベントハンドラーとして定義されている場合、「イベントハンドラーを登録している」と言います。 送信ボタンクリックのイベントハンドラーは、ユーザーから提供された入力のフォーマットをチェックし、SQLインジェクションやクロスサイトスクリプティングなどの攻撃を防ぐためにサニタイズします(クライアント側のコードは考慮されないことに注意してください)。安全です。常にサーバー上のデータをサニタイズします(ブラウザからのデータは絶対に信用しないでください)。次に、そのユーザー名とパスワードの組み合わせがデータベース内に存在するかどうかを確認して、ユーザーを認証し、トークンを提供します。
これはノードに関する記事なので、ノードイベントモデルに焦点を当てます。
Nodeのevents
モジュールを使用して、特定のイベントを発行して反応することができます。 イベントを発行するオブジェクトはすべて、 EventEmitter
クラスのインスタンスです。
エミットemit()
メソッドを呼び出すことでイベントを発行でき、 on()
メソッドを介してそのイベントをリッスンします。どちらもEventEmitter
クラスを介して公開されます。
const EventEmitter = require('events'); const myEmitter = new EventEmitter();
myEmitter
がEventEmitter
クラスのインスタンスになったので、 emit()
とon()
アクセスできます。
const EventEmitter = require('events'); const myEmitter = new EventEmitter(); myEmitter.on('someEvent', () => { console.log('The "someEvent" event was fired (emitted)'); }); myEmitter.emit('someEvent'); // This will call the callback function above.
myEmitter.on()
の2番目のパラメーターは、イベントが発行されたときに起動するコールバック関数です。これはイベントハンドラーです。 最初のパラメーターはイベントの名前です。これは任意の名前にすることができますが、キャメルケースの命名規則をお勧めします。
さらに、イベントハンドラーは、イベントが発行されたときに渡される任意の数の引数を取ることができます。
const EventEmitter = require('events'); const myEmitter = new EventEmitter(); myEmitter.on('someEvent', (data) => { console.log(`The "someEvent" event was fired (emitted) with data: ${data}`); }); myEmitter.emit('someEvent', 'This is the data payload');
継承を使用することで、 emit()
)メソッドとon()
メソッドを「EventEmitter」から任意のクラスに公開できます。 これは、Node.jsクラスを作成し、 extends
reservedキーワードを使用して、 EventEmitter
で使用可能なプロパティを継承することによって行われます。
const EventEmitter = require('events'); class MyEmitter extends EventEmitter { // This is my class. I can emit events from a MyEmitter object. }
車の船体のジャイロスコープ、加速度計、および圧力計からデータを受信する車両衝突通知プログラムを構築しているとします。 車両がオブジェクトと衝突すると、それらの外部センサーがクラッシュを検出し、 collide(...)
関数を実行して、集約されたセンサーデータを優れたJavaScriptオブジェクトとして渡します。 この関数はcollision
イベントを発行し、ベンダーにクラッシュを通知します。
const EventEmitter = require('events'); class Vehicle extends EventEmitter { collide(collisionStatistics) { this.emit('collision', collisionStatistics) } } const myVehicle = new Vehicle(); myVehicle.on('collision', collisionStatistics => { console.log('WARNING! Vehicle Impact Detected: ', collisionStatistics); notifyVendor(collisionStatistics); }); myVehicle.collide({ ... });
これは、クラスの衝突関数内のイベントハンドラー内にコードを配置するだけの複雑な例ですが、それでもノードイベントモデルがどのように機能するかを示しています。 一部のチュートリアルでは、オブジェクトがイベントを発行できるようにするutil.inherits()
メソッドが示されていることに注意してください。 これはES6クラスを優先して非推奨になり、 extends
されました。

ノードパッケージマネージャー
NodeとJavaScriptを使用してプログラミングする場合、 npm
について聞くのは非常に一般的です。 Npmはまさにそれを行うパッケージマネージャーです—JavaScriptの一般的な問題を解決するサードパーティのパッケージのダウンロードを許可します。 Yarn、Npx、Grunt、Bowerなどの他のソリューションも存在しますが、このセクションでは、 npm
と、それを使用した単純なコマンドラインインターフェイス(CLI)を介してアプリケーションの依存関係をインストールする方法にのみ焦点を当てます。
npm
だけで簡単に始めましょう。 NpmJSホームページにアクセスして、NPMから入手できるすべてのパッケージを表示します。 NPMパッケージに依存する新しいプロジェクトを開始するときは、プロジェクトのルートディレクトリにあるターミナルからnpm init
を実行する必要があります。 package.json
ファイルを作成するために使用される一連の質問が表示されます。 このファイルには、すべての依存関係(アプリケーションが機能に依存するモジュール、スクリプト)、テストの実行、プロジェクトのビルド、開発サーバーの起動などを行うための事前定義されたターミナルコマンドが格納されます。
パッケージをインストールするには、 npm install [package-name] --save
実行するだけです。 save
フラグは、パッケージとそのバージョンがpackage.json
ファイルに記録されていることを確認します。 npm
バージョン5以降、依存関係はデフォルトで保存されるため、 --save
は省略できます。 また、インストールしたパッケージのコードを含む新しいnode_modules
フォルダーもあります。 これは、 npm i [package-name]
に短縮することもできます。 役立つメモとして、 node_modules
フォルダーはサイズが大きいため、GitHubリポジトリに含めないでください。 GitHub(またはその他のバージョン管理システム)からリポジトリのクローンを作成するときは、必ずコマンドnpm install
を実行して、 package.json
ファイルで定義されているすべてのパッケージを取得し、 node_modules
ディレクトリを自動的に作成してください。 特定のバージョンでパッケージをインストールすることもできます。たとえば、 npm i [package-name]@1.10.1 --save
。
パッケージの削除は、パッケージのインストールと似ています: npm remove [package-name]
。
パッケージをグローバルにインストールすることもできます。 このパッケージは、作業中のプロジェクトだけでなく、すべてのプロジェクトで利用できます。 これは、 npm i [package-name]
後に-g
フラグを付けて行います。 これは、GoogleFirebaseやHerokuなどのCLIで一般的に使用されます。 この方法は簡単ですが、パッケージをグローバルにインストールすることは一般的に悪い習慣と見なされます。パッケージはpackage.json
ファイルに保存されておらず、別の開発者がプロジェクトを使用しようとすると、 npm install
。
APIとJSON
APIはプログラミングの非常に一般的なパラダイムであり、開発者としてのキャリアを始めたばかりの場合でも、APIとその使用法、特にWebおよびモバイル開発では、APIとその使用法が頻繁に登場する可能性があります。
APIはアプリケーションプログラミングインターフェイスであり、基本的には2つの分離されたシステムが相互に通信するための方法です。 より専門的に言えば、APIを使用すると、システムまたはコンピュータープログラム(通常はサーバー)が要求を受信し、適切な応答を(ホストとも呼ばれるクライアントに)送信できます。
天気予報アプリケーションを作成しているとします。 ユーザーの住所を緯度と経度にジオコーディングする方法と、その特定の場所の現在または予測される天気を取得する方法が必要です。
開発者は、住所をジオコーディングしたり、すべての都市に気象観測所を配置したりするためのインフラストラクチャを配置するのではなく、アプリの構築と収益化に集中したいと考えています。
Luckily for you, companies like Google and OpenWeatherMap have already put that infrastructure in place, you just need a way to talk to it — that is where the API comes in. While, as of now, we have developed a very abstract and ambiguous definition of the API, bear with me. We'll be getting to tangible examples soon.
Now, it costs money for companies to develop, maintain, and secure that aforementioned infrastructure, and so it is common for corporations to sell you access to their API. This is done with that is known as an API key, a unique alphanumeric identifier associating you, the developer, with the API. Every time you ask the API to send you data, you pass along your API key. The server can then authenticate you and keep track of how many API calls you are making, and you will be charged appropriately. The API key also permits Rate-Limiting or API Call Throttling (a method of throttling the number of API calls in a certain timeframe as to not overwhelm the server, preventing DOS attacks — Denial of Service). Most companies, however, will provide a free quota, giving you, as an example, 25,000 free API calls a day before charging you.
Up to this point, we have established that an API is a method by which two computer programs can communicate with each other. If a server is storing data, such as a website, and your browser makes a request to download the code for that site, that was the API in action.
Let us look at a more tangible example, and then we'll look at a more real-world, technical one. Suppose you are eating out at a restaurant for dinner. You are equivalent to the client, sitting at the table, and the chef in the back is equivalent to the server.
Since you will never directly talk to the chef, there is no way for him/her to receive your request (for what order you would like to make) or for him/her to provide you with your meal once you order it. We need someone in the middle. In this case, it's the waiter, analogous to the API. The API provides a medium with which you (the client) may talk to the server (the chef), as well as a set of rules for how that communication should be made (the menu — one meal is allowed two sides, etc.)
Now, how do you actually talk to the API (the waiter)? You might speak English, but the chef might speak Spanish. Is the waiter expected to know both languages to translate? What if a third person comes in who only speaks Mandarin? では、どうしますか? Well, all clients and servers have to agree to speak a common language, and in computer programming, that language is JSON, pronounced JAY-sun, and it stands for JavaScript Object Notation.
At this point, we don't quite know what JSON looks like. It's not a computer programming language, it's just, well, a language, like English or Spanish, that everyone (everyone being computers) understands on a guaranteed basis. It's guaranteed because it's a standard, notably RFC 8259 , the JavaScript Object Notation (JSON) Data Interchange Format by the Internet Engineering Task Force (IETF).
Even without formal knowledge of what JSON actually is and what it looks like (we'll see in an upcoming article in this series), we can go ahead introduce a technical example operating on the Internet today that employs APIs and JSON. APIs and JSON are not just something you can choose to use, it's not equivalent to one out of a thousand JavaScript frameworks you can pick to do the same thing. It is THE standard for data exchange on the web.
Suppose you are building a travel website that compares prices for aircraft, rental car, and hotel ticket prices. Let us walk through, step-by-step, on a high level, how we would build such an application. Of course, we need our User Interface, the front-end, but that is out of scope for this article.
We want to provide our users with the lowest price booking method. Well, that means we need to somehow attain all possible booking prices, and then compare all of the elements in that set (perhaps we store them in an array) to find the smallest element (known as the infimum in mathematics.)
How will we get this data? Well, suppose all of the booking sites have a database full of prices. Those sites will provide an API, which exposes the data in those databases for use by you. You will call each API for each site to attain all possible booking prices, store them in your own array, find the lowest or minimum element of that array, and then provide the price and booking link to your user. We'll ask the API to query its database for the price in JSON, and it will respond with said price in JSON to us. We can then use, or parse, that accordingly. We have to parse it because APIs will return JSON as a string, not the actual JavaScript data type of JSON. This might not make sense now, and that's okay. We'll be covering it more in a future article.
Also, note that just because something is called an API does not necessarily mean it operates on the web and sends and receives JSON. The Java API, for example, is just the list of classes, packages, and interfaces that are part of the Java Development Kit (JDK), providing programming functionality to the programmer.
わかった。 We know we can talk to a program running on a server by way of an Application Programming Interface, and we know that the common language with which we do this is known as JSON. But in the web development and networking world, everything has a protocol. What do we actually do to make an API call, and what does that look like code-wise? That's where HTTP Requests enter the picture, the HyperText Transfer Protocol, defining how messages are formatted and transmitted across the Internet. Once we have an understanding of HTTP (and HTTP verbs, you'll see that in the next section), we can look into actual JavaScript frameworks and methods (like fetch()
) offered by the JavaScript API (similar to the Java API), that actually allow us to make API calls.
HTTP And HTTP Requests
HTTP is the HyperText Transfer Protocol. It is the underlying protocol that determines how messages are formatted as they are transmitted and received across the web. Let's think about what happens when, for example, you attempt to load the home page of Smashing Magazine in your web browser.
You type the website URL (Uniform Resource Locator) in the URL bar, where the DNS server (Domain Name Server, out of scope for this article) resolves the URL into the appropriate IP Address. The browser makes a request, called a GET Request, to the Web Server to, well, GET the underlying HTML behind the site. The Web Server will respond with a message such as “OK”, and then will go ahead and send the HTML down to the browser where it will be parsed and rendered accordingly.
ここで注意すべきことがいくつかあります。 First, the GET Request, and then the “OK” response. Suppose you have a specific database, and you want to write an API to expose that database to your users. Suppose the database contains books the user wants to read (as it will in a future article in this series). Then there are four fundamental operations your user may want to perform on this database, that is, Create a record, Read a record, Update a record, or Delete a record, known collectively as CRUD operations.
Let's look at the Read operation for a moment. Without incorrectly assimilating or conflating the notion of a web server and a database, that Read operation is very similar to your web browser attempting to get the site from the server, just as to read a record is to get the record from the database.
これはHTTPリクエストと呼ばれます。 データを取得するためにどこかのサーバーにリクエストを送信しているため、リクエストには適切な名前が付けられています。大文字と小文字はそのようなリクエストを表す標準的な方法です。
CRUDの作成部分はどうですか? さて、HTTPリクエストについて話すとき、それはPOSTリクエストとして知られています。 ソーシャルメディアプラットフォームにメッセージを投稿するのと同じように、データベースに新しいレコードを投稿することもできます。
CRUDの更新により、リソースを更新するためにPUTまたはPATCHリクエストのいずれかを使用できます。 HTTPのPUTは、新しいレコードを作成するか、古いレコードを更新/置換します。
これをもう少し詳しく見てから、PATCHについて説明します。
APIは通常、URL内の特定のルートにHTTPリクエストを送信することで機能します。 ユーザーのブックリストを含むDBと通信するためのAPIを作成しているとします。 そうすれば、URL .../books
でそれらの本を表示できる可能性があります。 .../books
へのPOSTリクエストは、 .../books
ルートで定義したプロパティ(ID、タイトル、ISBN、作成者、公開データなど)を使用して新しい本を作成します。 現在.../books
にすべての本を保存している基礎となるデータ構造が何であるかは関係ありません。 APIがそのエンドポイント(ルートを介してアクセスされる)を公開してデータを操作することに注意してください。 前の文が重要でした。POSTリクエストは...books/
ルートに新しい本を作成します。 したがって、PUTとPOSTの違いは、PUTは、そのような本が存在しない場合は(POSTと同様に)新しい本を作成するか、前述のデータ構造内に本がすでに存在する場合は既存の本を置き換えることです。
各本に次のプロパティがあるとします:id、title、ISBN、author、hasRead(ブール値)。
次に、前に見たように、新しい本を追加するために、 .../books
にPOSTリクエストを行います。 書籍を完全に更新または交換する場合は、 .../books/id
にPUTリクエストを送信します。ここで、 id
は交換する書籍のIDです。
PUTは既存の本を完全に置き換えますが、PATCHは特定の本に関係する何かを更新し、おそらく上記で定義したhasRead
ブールプロパティを変更します。したがって、新しいデータを送信する…/books/id
に対してPATCHリクエストを行います。
現在、これの意味を理解するのは難しいかもしれません。これまでのところ、理論的にはすべてを確立していますが、実際にHTTPリクエストを行う具体的なコードは見ていません。 ただし、この記事でGETを取り上げ、残りを今後の記事で取り上げて、すぐにそれについて説明します。
最後の基本的なCRUD操作が1つあり、それはDeleteと呼ばれます。 ご想像のとおり、このようなHTTPリクエストの名前は「DELETE」であり、PATCHとほぼ同じように機能するため、ルートで本のIDを指定する必要があります。
これまでのところ、ルートはHTTPリクエストを行う特定のURLであり、エンドポイントはAPIが提供する関数であり、公開するデータに対して何かを行うことを学びました。 つまり、エンドポイントはルートのもう一方の端にあるプログラミング言語関数であり、指定したHTTPリクエストを実行します。 また、APIに対して行うリクエストを実際に指定する、POST、GET、PUT、PATCH、DELETEなどの用語(HTTP動詞と呼ばれる)が存在することも学びました。 JSONと同様に、これらのHTTP要求メソッドは、インターネット技術特別調査委員会(IETF)によって定義されたインターネット標準であり、特にRFC 7231、セクション4:要求メソッド、およびRFC 5789、セクション2:パッチメソッドです。RFCはの略語です。コメントを求める。
したがって、渡されたIDがパラメータとして知られているURL .../books/id
に対してGETリクエストを行う場合があります。 .../books
にPOST、PUT、またはPATCHリクエストを送信してリソースを作成するか、 .../books/id
にリソースを変更/置換/更新することができます。 また、 .../books/id
にDELETEリクエストを送信して、特定の本を削除することもできます。
HTTPリクエストメソッドの完全なリストはここにあります。
HTTPリクエストを行った後、応答を受け取ることに注意することも重要です。 具体的な応答は、APIの構築方法によって決まりますが、常にステータスコードを受け取る必要があります。 以前、WebブラウザがWebサーバーからHTMLを要求すると、「OK」と応答することを説明しました。 これは、HTTPステータスコード、より具体的にはHTTP 200OKとして知られています。 ステータスコードは、エンドポイントで指定された操作またはアクション(すべての作業を実行する関数であることを忘れないでください)がどのように完了したかを指定するだけです。 HTTPステータスコードはサーバーから返送されます。404NotFound(リソースまたはファイルが見つかりませんでした。これは.../books/id
にGETリクエストを行うようなものです)など、よく知っているものがたくさんあります。そのような.../books/id
が存在しないID。)
HTTPステータスコードの完全なリストはここにあります。
MongoDB
MongoDBは、Firebase Real-timeDatabaseに似た非リレーショナルのNoSQLデータベースです。 MongoDB NativeDriverやMongooseなどのNodeパッケージを介してデータベースと通信します。
MongoDBでは、データはJSONに格納されます。これは、MySQL、PostgreSQL、SQLiteなどのリレーショナルデータベースとはまったく異なります。 どちらもデータベースと呼ばれ、SQLテーブルはコレクションと呼ばれ、SQLテーブル行はドキュメントと呼ばれ、SQLテーブル列はフィールドと呼ばれます。
最初のBookshelfAPIを作成するときに、このシリーズの今後の記事でMongoDBデータベースを使用します。 上記の基本的なCRUD操作は、MongoDBデータベースで実行できます。
MongoDBドキュメントを読んで、Atlasクラスター上にライブデータベースを作成し、MongoDBネイティブドライバーを使用してCRUD操作を行う方法を学ぶことをお勧めします。 このシリーズの次の記事では、ローカルデータベースとクラウド本番データベースを設定する方法を学習します。
コマンドラインノードアプリケーションの構築
アプリケーションを構築するとき、多くの作成者が記事の冒頭でコードベース全体をダンプし、その後各行を説明しようとするのを目にするでしょう。 このテキストでは、別のアプローチを取ります。 コードを1行ずつ説明し、アプリを構築していきます。 モジュール性やパフォーマンスについて心配することはありません。コードベースを個別のファイルに分割することも、DRYの原則に従わないことも、コードを再利用可能にすることもしません。 ただ学ぶときは、できるだけシンプルにするのが便利なので、ここでのアプローチです。
私たちが構築しているものについて明確にしましょう。 ユーザー入力は気にしないので、Yargsのようなパッケージは使用しません。 また、独自のAPIを構築することもありません。 これについては、このシリーズの後半の記事で、Express Web ApplicationFrameworkを使用するときに説明します。 ほとんどのチュートリアルがそうであるように、私はNode.jsをExpressとAPIの力と混同しないようにこのアプローチを取ります。 むしろ、サードパーティのJavaScriptライブラリを利用する外部APIからデータを呼び出したり受信したりするための(多くの)1つのメソッドを提供します。 呼び出すAPIはWeatherAPIであり、Nodeからアクセスして、出力を端末にダンプします。おそらく、「プリティプリンティング」と呼ばれるフォーマットを使用します。 APIの設定方法やAPIキーの取得方法など、プロセス全体について説明します。この手順では、2019年1月の時点で正しい結果が得られます。
このプロジェクトではOpenWeatherMapAPIを使用するため、開始するには、OpenWeatherMapサインアップページに移動し、フォームを使用してアカウントを作成します。 ログインしたら、ダッシュボードページ(ここにあります)で[APIキー]メニュー項目を見つけます。 アカウントを作成したばかりの場合は、APIキーの名前を選択して、[生成]をクリックする必要があります。 新しいAPIキーが機能し、アカウントに関連付けられるまでに少なくとも2時間かかる場合があります。
アプリケーションの構築を開始する前に、APIドキュメントにアクセスして、APIキーのフォーマット方法を学習します。 このプロジェクトでは、その場所の気象情報を取得するために、郵便番号と国コードを指定します。
ドキュメントから、これを行う方法は次のURLを提供することであることがわかります。
api.openweathermap.org/data/2.5/weather?zip={zip code},{country code}
データを入力できる場所:
api.openweathermap.org/data/2.5/weather?zip=94040,us
ここで、このAPIから関連データを実際に取得する前に、新しいAPIキーをクエリパラメーターとして提供する必要があります。
api.openweathermap.org/data/2.5/weather?zip=94040,us&appid={YOUR_API_KEY}
今のところ、そのURLをWebブラウザーの新しいタブにコピーし、 {YOUR_API_KEY}
プレースホルダーを以前にアカウントに登録したときに取得したAPIキーに置き換えます。
表示されるテキストは実際にはJSONであり、前述のようにWebで合意された言語です。
これをさらに詳しく調べるには、GoogleChromeでCtrl + Shift + Iを押してChromeデベロッパーツールを開き、[ネットワーク]タブに移動します。 現在、ここにはデータがないはずです。
![空のChrome開発ツールの[ネットワーク]タブ](/uploads/article/1692/iZz5GQiB8w8sgJpD.png)
ネットワークデータを実際に監視するには、ページをリロードし、タブに有用な情報が表示されるのを確認します。 下の画像に示されているように、最初のリンクをクリックします。
![ポピュレートされたChrome開発ツールの[ネットワーク]タブ](/uploads/article/1692/MZ9NGmKGgG9cRv7n.png)
そのリンクをクリックすると、ヘッダーなどのHTTP固有の情報を実際に表示できます。 ヘッダーはAPIからの応答で送信されます(場合によっては、独自のヘッダーをAPIに送信することもできます。また、独自のカスタムヘッダー(多くの場合、接頭辞x-
)を作成して、独自のAPIを構築するときに送り返すこともできます。 )、クライアントまたはサーバーのいずれかが必要とする可能性のある追加情報が含まれているだけです。
この場合、APIに対してHTTP GETリクエストを行い、HTTPステータス200OKで応答したことがわかります。 また、「応答ヘッダー」セクションにリストされているように、返送されたデータがJSONであったこともわかります。

プレビュータブを押すと、実際にJSONをJavaScriptオブジェクトとして表示できます。 ブラウザに表示されるテキストバージョンは文字列です。JSONは常に文字列としてWeb上で送受信されるためです。 そのため、コード内のJSONを解析して、より読みやすい形式(この場合(ほとんどすべての場合))のJavaScriptオブジェクトに変換する必要があります。
GoogleChrome拡張機能の「JSONビュー」を使用してこれを自動的に行うこともできます。
アプリケーションの構築を開始するには、ターミナルを開いて新しいルートディレクトリを作成し、そこにcd
します。 内部に入ったら、新しいapp.js
ファイルを作成し、 npm init
を実行してデフォルト設定でpackage.json
ファイルを生成してから、Visual StudioCodeを開きます。
mkdir command-line-weather-app && cd command-line-weather-app touch app.js npm init code .
その後、Axiosをダウンロードし、 package.json
ファイルに追加されていることを確認し、 node_modules
フォルダーが正常に作成されたことを確認します。
ブラウザで、URLバーに適切なURLを手動で入力することにより、手動でGETリクエストを行ったことがわかります。 Axiosは、Node内でそれを実行できるようにするものです。
これ以降、次のコードはすべてapp.js
ファイル内に配置され、各スニペットが次々に配置されます。
最初に行うことは、以前にインストールしたAxiosパッケージを必要とすることです。
const axios = require('axios');
これでAxiosにアクセスできるようになり、 axios
定数を介して関連するHTTPリクエストを作成できるようになりました。
通常、API呼び出しは動的になります。この場合、URLにさまざまな郵便番号と国コードを挿入する必要があります。 そこで、URLの各部分に定数変数を作成し、それらをES6テンプレート文字列と組み合わせます。 まず、APIキーだけでなく、決して変更されないURLの部分があります。
const API_URL = 'https://api.openweathermap.org/data/2.5/weather?zip='; const API_KEY = 'Your API Key Here';
郵便番号と国コードも割り当てます。 ユーザー入力を期待しておらず、データをハードコーディングしているので、これらも定数にしますが、多くの場合、 let
を使用する方が便利です。
const LOCATION_ZIP_CODE = '90001'; const COUNTRY_CODE = 'us';
次に、これらの変数を1つのURLにまとめて、Axiosを使用して次のGETリクエストを行う必要があります。
const ENTIRE_API_URL = `${API_URL}${LOCATION_ZIP_CODE},${COUNTRY_CODE}&appid=${API_KEY}`;
これまでのapp.js
ファイルの内容は次のとおりです。
const axios = require('axios'); // API specific settings. const API_URL = 'https://api.openweathermap.org/data/2.5/weather?zip='; const API_KEY = 'Your API Key Here'; const LOCATION_ZIP_CODE = '90001'; const COUNTRY_CODE = 'us'; const ENTIRE_API_URL = `${API_URL}${LOCATION_ZIP_CODE},${COUNTRY_CODE}&appid=${API_KEY}`;
あとは、実際にaxios
を使用してそのURLにGETリクエストを送信するだけです。 そのために、 axios
が提供するget(url)
メソッドを使用します。
axios.get(ENTIRE_API_URL)
axios.get(...)
は実際にはPromiseを返し、successコールバック関数は応答引数を取ります。これにより、APIからの応答にアクセスできるようになります。これはブラウザーで見たものと同じです。 エラーをキャッチするために.catch()
句も追加します。
axios.get(ENTIRE_API_URL) .then(response => console.log(response)) .catch(error => console.log('Error', error));
ターミナルでnode app.js
を使用してこのコードを実行すると、返される完全な応答を確認できます。 ただし、その郵便番号の温度を確認したいだけだとします。そうすると、応答内のそのデータのほとんどは役に立ちません。 Axiosは、実際には、応答のプロパティであるデータオブジェクトのAPIから応答を返します。 つまり、サーバーからの応答は実際にはresponse.data
にあるので、代わりにコールバック関数console.log(response.data)
に出力してみましょう。
さて、Webサーバーは常にJSONを文字列として処理すると言いましたが、それは事実です。 ただし、 response.data
はすでにオブジェクトであることに気付くかもしれません( console.log(typeof response.data)
を実行すると明らかです)— JSON.parse()
で解析する必要はありませんでした。 これは、Axiosが舞台裏ですでにこれを処理しているためです。
console.log(response.data)
の実行からのターミナルでの出力は、 console.log(JSON.stringify(response.data, undefined, 2))
を実行することにより、フォーマット(「きれいに印刷」)できます。 JSON.stringify()
は、JSONオブジェクトを文字列に変換し、オブジェクト、フィルター、および印刷時にインデントする文字数を取り込みます。 これが提供する応答を見ることができます:
{ "coord": { "lon": -118.24, "lat": 33.97 }, "weather": [ { "id": 800, "main": "Clear", "description": "clear sky", "icon": "01d" } ], "base": "stations", "main": { "temp": 288.21, "pressure": 1022, "humidity": 15, "temp_min": 286.15, "temp_max": 289.75 }, "visibility": 16093, "wind": { "speed": 2.1, "deg": 110 }, "clouds": { "all": 1 }, "dt": 1546459080, "sys": { "type": 1, "id": 4361, "message": 0.0072, "country": "US", "sunrise": 1546441120, "sunset": 1546476978 }, "id": 420003677, "name": "Lynwood", "cod": 200 }
これで、探している温度がresponse.data
オブジェクトのmain
プロパティにあることがわかります。したがって、 response.data.main.temp
を呼び出すことでアクセスできます。 これまでのアプリケーションのコードを見てみましょう。
const axios = require('axios'); // API specific settings. const API_URL = 'https://api.openweathermap.org/data/2.5/weather?zip='; const API_KEY = 'Your API Key Here'; const LOCATION_ZIP_CODE = '90001'; const COUNTRY_CODE = 'us'; const ENTIRE_API_URL = `${API_URL}${LOCATION_ZIP_CODE},${COUNTRY_CODE}&appid=${API_KEY}`; axios.get(ENTIRE_API_URL) .then(response => console.log(response.data.main.temp)) .catch(error => console.log('Error', error));
返される温度は実際にはケルビンです。これは、物理学、化学、熱力学で一般的に使用される温度スケールです。これは、すべての内部のすべての熱運動が発生する温度である「絶対零度」ポイントを提供するためです。粒子が止まります。 以下の式を使用して、これを華氏または摂氏に変換する必要があります。
F = K * 9 / 5-459.67
C = K-273.15
成功コールバックを更新して、この変換で新しいデータを出力してみましょう。 また、ユーザーエクスペリエンスの目的で、適切な文を追加します。
axios.get(ENTIRE_API_URL) .then(response => { // Getting the current temperature and the city from the response object. const kelvinTemperature = response.data.main.temp; const cityName = response.data.name; const countryName = response.data.sys.country; // Making K to F and K to C conversions. const fahrenheitTemperature = (kelvinTemperature * 9/5) — 459.67; const celciusTemperature = kelvinTemperature — 273.15; // Building the final message. const message = ( `Right now, in \ ${cityName}, ${countryName} the current temperature is \ ${fahrenheitTemperature.toFixed(2)} deg F or \ ${celciusTemperature.toFixed(2)} deg C.`.replace(/\s+/g, ' ') ); console.log(message); }) .catch(error => console.log('Error', error));
message
変数を囲む括弧は必須ではありません。ReactでJSXを操作する場合と同様に、見栄えがよくなります。 バックスラッシュは、テンプレート文字列による改行のフォーマットを停止し、 replace()
Stringプロトタイプメソッドは、正規表現(RegEx)を使用して空白を取り除きます。 toFixed()
Numberプロトタイプメソッドは、floatを特定の小数点以下の桁数(この場合は2桁)に丸めます。
これで、最終的なapp.js
は次のようになります。
const axios = require('axios'); // API specific settings. const API_URL = 'https://api.openweathermap.org/data/2.5/weather?zip='; const API_KEY = 'Your API Key Here'; const LOCATION_ZIP_CODE = '90001'; const COUNTRY_CODE = 'us'; const ENTIRE_API_URL = `${API_URL}${LOCATION_ZIP_CODE},${COUNTRY_CODE}&appid=${API_KEY}`; axios.get(ENTIRE_API_URL) .then(response => { // Getting the current temperature and the city from the response object. const kelvinTemperature = response.data.main.temp; const cityName = response.data.name; const countryName = response.data.sys.country; // Making K to F and K to C conversions. const fahrenheitTemperature = (kelvinTemperature * 9/5) — 459.67; const celciusTemperature = kelvinTemperature — 273.15; // Building the final message. const message = ( `Right now, in \ ${cityName}, ${countryName} the current temperature is \ ${fahrenheitTemperature.toFixed(2)} deg F or \ ${celciusTemperature.toFixed(2)} deg C.`.replace(/\s+/g, ' ') ); console.log(message); }) .catch(error => console.log('Error', error));
結論
この記事では、同期リクエストと非同期リクエストの違いから、コールバック関数、新しいES6機能、イベント、パッケージマネージャー、API、JSON、ハイパーテキスト転送プロトコル、非リレーショナルデータベースまで、Nodeがどのように機能するかについて多くのことを学びました。 、そして私たちは、その新しく発見された知識のほとんどを利用して、独自のコマンドラインアプリケーションを構築しました。
このシリーズの今後の記事では、コールスタック、イベントループ、ノードAPIについて詳しく見ていき、クロスオリジンリソースシェアリング(CORS)について説明し、フルを構築します。データベース、エンドポイント、ユーザー認証、トークン、サーバー側のテンプレートレンダリングなどを利用したスタックブックシェルフAPI。
ここから、独自のNodeアプリケーションの構築を開始し、Nodeのドキュメントを読み、興味深いAPIまたはNode Moduleを見つけて、自分で実装します。 世界はあなたのカキであり、あなたは地球上で最大の知識のネットワークであるインターネットにあなたの指先でアクセスできます。 あなたの利点にそれを使用してください。
SmashingMagの詳細:
- RESTAPIの理解と使用
- 正規表現の記述方法を変更する新しいJavaScript機能
- Node.jsを高速に保つ:高性能のNode.jsサーバーを作成するためのツール、テクニック、ヒント
- Web SpeechAPIとNode.jsを使用したシンプルなAIチャットボットの構築