Node.jsでAPI連携する方法
Node.jsにおけるAPI連携の例を解説します。
概要
Node.jsは、JavaScriptランタイムで、APIとの連携によく使用されます。APIとの連携を実現するためには、リクエストの送信やレスポンスの処理が必要となります。
ここでは、以下バージョンを使用した、Node.jsでAPIとの連携を行う方法を説明します。
nodejs v19.7.0
また、今回作成するコードは全て、GitHubに掲載しています。
フロントエンドからAPIを実行する方法
フロントエンドでAPIを使用することは一般的なシナリオで、JavaScriptのFetch APIを使うと簡単に実装できます。Fetch APIはブラウザがネイティブで提供するAPIで、非同期HTTP(Ajax)リクエストを行うことができます。
以下の例では、Node.jsで作成した/usersエンドポイントにPOSTリクエストを送信し、新しいユーザーを作成します。
index.html
<!DOCTYPE html>
<html>
<body>
<!-- ボタンを追加 -->
<button onclick="createUser()">Create User</button>
<script>
async function createUser() {
const response = await fetch('http://localhost:3000/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John', age: 25 })
});
if (!response.ok) {
const message = await response.text();
throw new Error(`An error has occurred: ${message}`);
}
const user = await response.json();
console.log(user);
}
</script>
</body>
</html>
解説
このソースコードは、ユーザーを作成するためのHTMLページを生成します。
- HTMLドキュメントの定義とボタンの追加:
<!DOCTYPE html>
<html>
<body>
<!-- ボタンを追加 -->
<button onclick="createUser()">Create User</button>
この部分では、HTML文書の基本的な構造を定義し、ユーザーを作成するためのボタンを追加しています。ボタンがクリックされるとcreateUser
関数が実行されます。
createUser
関数の定義:
<script>
async function createUser() {
const response = await fetch('http://localhost:3000/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John', age: 25 })
});
この部分で非同期関数createUser
を定義しています。この関数は、fetch
APIを使用して、指定したURL(この場合はhttp://localhost:3000/users
)に対してPOSTリクエストを送信します。リクエストボディには、作成するユーザーの情報をJSON形式で指定します。
- エラーハンドリング:
if (!response.ok) {
const message = await response.text();
throw new Error(`An error has occurred: ${message}`);
}
response.ok
プロパティは、レスポンスが成功したかどうか(HTTPステータスコードが200~299の範囲かどうか)を判断します。成功していない場合、エラーメッセージを生成してエラーをスローします。
- レスポンスの処理とログ出力:
const user = await response.json();
response.json()
メソッドを使用して、レスポンスボディをJSONとして解析します。
server.js
// モジュールをインポートします
const http = require("http");
const url = require("url");
const fs = require("fs");
const path = require("path");
// ユーザーを保存するための仮のデータストア
let users = [];
// HTMLページのパスを設定します
const indexFilePath = path.join(__dirname, "index.html");
// リクエストハンドラを作成します
const requestHandler = (req, res) => {
const { pathname } = url.parse(req.url);
switch (pathname) {
case "/":
fs.readFile(indexFilePath, (err, data) => {
if (err) {
res.writeHead(500);
res.end(`Error loading ${indexFilePath}`);
} else {
res.setHeader("Content-Type", "text/html");
res.end(data);
}
});
break;
case "/users":
if (req.method === "GET") {
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(users));
} else if (req.method === "POST") {
let body = "";
req.on("data", (chunk) => {
body += chunk.toString();
});
req.on("end", () => {
const user = JSON.parse(body);
users.push(user);
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(user));
});
}
break;
default:
res.writeHead(404);
res.end(`404 - Page not found!`);
}
};
// サーバーを作成して起動します
const server = http.createServer(requestHandler);
server.listen(8000, () => {
console.log("Server is running on port 8000");
});
解説
- モジュールをインポートする
const http = require("http");
const url = require("url");
const fs = require("fs");
const path = require("path");
これらの行は、HTTPサーバーを作成するための http
モジュール、URLを解析するための url
モジュール、ファイルシステム操作を行うための fs
モジュール、パス操作を行うための path
モジュールをインポートしています。
- ユーザーを保存するための仮のデータストアを作成する
let users = [];
この行は、作成されたユーザーを保存するための配列を作成しています。
- HTMLページのパスを設定する
const indexFilePath = path.join(__dirname, "index.html");
この行は、HTMLファイルのパスを設定しています。__dirname
は現在のモジュールファイルのディレクトリへのパスを指します。
- リクエストハンドラを作成する
const requestHandler = (req, res) => {
// ...
};
この関数は、サーバーに送信された全てのHTTPリクエストを処理します。リクエストオブジェクト (req
) とレスポンスオブジェクト (res
) の二つの引数を取ります。
- ルートURL (
"/"
) へのリクエストを処理する
case "/":
fs.readFile(indexFilePath, (err, data) => {
// ...
});
break;
ルートURLへのリクエストがあった場合、HTMLファイルを読み込み、その内容をレスポンスとして返します。
- “/users” へのGETおよびPOSTリクエストを処理する
case "/users":
if (req.method === "GET") {
// ...
} else if (req.method === "POST") {
// ...
}
break;
“/users” へのGETリクエストがあった場合、保存されている全てのユーザーを返します。POSTリクエストがあった場合、新たにユーザーを作成します。
- 他のURLへのリクエストを処理する
default:
res.writeHead(404);
res.end(`404 - Page not found!`);
ルートURLや “/users” 以外のURLへのリクエストがあった場合、HTTPステータスコード404とエラーメッセージを返します。
- HTTPサーバーを作成して起動する
const server = http.createServer(requestHandler);
server.listen(8000, () => {
console.log("Server is running on port 8000");
});
最後に、作成したリクエストハンドラを引数にして http.createServer()
メソッドを呼び出し、サーバーを作成します。次に listen()
メソッドを呼び出し、サーバーがポート8000でリッスンを開始するようにします。サーバーが起動したら、コンソールにメッセージを出力します。
最終的に以下のようなディレクトリ構成になります。
integration
├── index.html
├── server.js
ここまで完成したら、以下のコマンドを実行してサーバーを起動します。
node server.js
実行が完了したら、ブラウザでhttp://localhost:3000
にアクセスしてみましょう。
ボタンをクリックすると、ユーザーが作成されます。
ユーザーが作成された、http://localhost:3000/users
にアクセスすると、作成されたユーザーの一覧が表示されます。
テスト
## ユーザーの取得
curl -X GET http://localhost:3000/users
# ユーザーの作成
curl -X POST -H "Content-Type: application/json" -d '{"id":"1","name":"John Doe"}' http://localhost:3000/users
外部APIへのリクエストを送信する
外部APIへのリクエストを送信するためには、通常、HTTPクライアントライブラリが使用されます。ここでは、その一つであるaxios
を使用します。まず、npmを使ってaxios
をインストールします。
npm install axios
external.js
const http = require('http');
const axios = require('axios');
const requestHandler = async (req, res) => {
if (req.url === '/data' && req.method === 'GET') {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(response.data));
} catch (error) {
res.writeHead(500);
res.end(JSON.stringify({ message: 'Error occurred' }));
}
} else {
res.writeHead(404);
res.end('Not found');
}
};
const server = http.createServer(requestHandler);
server.listen(3000, () => {
console.log('Server is running on port 3000');
});
解説
– モジュールをインポートします:
const http = require('http');
const axios = require('axios');
http
はNode.js内蔵のHTTPサーバーモジュールで、axios
はPromiseベースのHTTPクライアントライブラリです。
- リクエストハンドラー関数を定義します:
const requestHandler = async (req, res) => {
if (req.url === '/data' && req.method === 'GET') {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(response.data));
} catch (error) {
res.writeHead(500);
res.end(JSON.stringify({ message: 'Error occurred' }));
}
} else {
res.writeHead(404);
res.end('Not found');
}
};
この関数は、リクエストURLとメソッドをチェックし、それに応じたレスポンスを返します。具体的には、’/data’へのGETリクエストが来た場合に、axiosを使って外部APIからデータを取得し、そのデータをJSON形式でレスポンスとして返します。
- HTTPサーバーを作成します:
const server = http.createServer(requestHandler);
http.createServer
メソッドを使用して、上で定義したリクエストハンドラー関数requestHandler
を使用するHTTPサーバーを作成します。
- サーバーを起動します:
server.listen(3000, () => {
console.log('Server is running on port 3000');
});
server.listen
メソッドを使用して、サーバーを起動し、ポート3000でリクエストを待ち受けます。サーバーが起動したら、“Server is running on port 3000"というメッセージがコンソールに表示されます。
テスト
curl http://localhost:3000/data
まとめ
Expressフレームワークを使用せず、プレーンなNode.jsのみでHTTPサーバーを作成しました。リクエストをハンドリングするためのロジックはrequestHandler
関数内に定義されています。
http
とaxios
モジュールをインポートします。http
はNode.js内蔵のHTTPサーバーモジュール、axios
はPromiseベースのHTTPクライアントライブラリです。リクエストハンドラー関数
requestHandler
を定義します。この関数では、リクエストURLとメソッドをチェックし、それに応じたレスポンスを返します。具体的には、’/data’へのGETリクエストが来た場合に、axiosを使って外部APIからデータを取得し、そのデータをJSON形式でレスポンスとして返します。http.createServer
メソッドを使用して、このリクエストハンドラーを用いるHTTPサーバーを作成します。server.listen
メソッドを使用して、サーバーを起動し、ポート3000でリクエストを待ち受けます。サーバーが起動したら、“Server is running on port 3000"というメッセージがコンソールに表示されます。
このように、プレーンなNode.jsでもHTTPサーバーの基本的な動作を実装することができます。ただし、ルーティングやエラーハンドリングなどの複雑な動作を実装する場合は、Expressのようなフレームワークの利用を検討するとよいでしょう。