APIサーバーはどのように構築しますか?
APIサーバーはどこにでもあります---ウェブアプリケーションに接続したり更新したりするたびに、ブラウザは最新のデータを求めてリクエストを送信しています。その背後でどのように処理されているのか、また、どのように自分自身のAPIサーバーをコードできるのかを見ていきます。
APIサーバーとは何か、およびその仕組みは?
例を挙げましょう。あなたはデータベースに接続して、ソーシャルメディアサイトのユーザーが投稿したデータなどを取得する必要のあるウェブアプリケーションを持っています。ユーザーが直接データベースサーバーに接続することはできません。なぜなら、それはアプリに接続詳細を残してしまう重大なセキュリティの欠陥だからです。
解決策は、ユーザーからのリクエストを受け取り、それを解釈し、要求された情報のためにデータベースを安全にクエリする中間にサーバーを置くことです。ユーザーはデータベースを見る必要はなく、実際には、APIサーバー以外からアクセスできないようにプライベートサブネット内で実行されることがよくあります。
これにより、クライアントはHTTP/HTTPSを通じて安全にデータにアクセスできます。APIサーバーはあなたが所有し管理しているため、その接続をより簡単に安全にできます。それでも、ユーザーが自分が言う通りにサインインしていることを確認するために、何らかの認証形式が必要です。
APIサーバーは、あなたのウェブサイトで重い処理を行うためのものではありません。ほとんどの静的コンテンツには、NGINXのような従来のウェブサーバーを使用することをお勧めします。これにより、大幅にパフォーマンスが向上します。例えば、あなたはこうして提供します。
index.htmlと
bundle.jsクライアントが展開して実行するあなたのNGINXサーバーを使用しています。その後、クライアントサイドのJavaScriptアプリケーションがAPIサーバーにリクエストを行い、そこから処理されます。
任意の言語でAPIサーバーを作成できます---必要なのはHTTPリクエストを聞いて応答する能力と、データベースに接続する能力だけであり、どちらもあらゆる言語に対応した多くのライブラリがあります。このガイドでは、HTTPおよびルート処理にExpressを使用してJavaScriptとNode.JSを使用します。もう一つの人気の選択肢は、MicrosoftのC#を使用するASP.NETです。
AWSを使用している場合は、AWSのAPI Gatewayを検討することをお勧めします。完全なAPIサーバーを運営する代わりに、API Gatewayは、Lambda関数やRDSのフロントエンドとして機能する安価な管理ソリューションを提供します。
Express.JSを使用してAPIサーバーを設定する
Express.JSは、Node(サーバーサイドJavaScript)上で動作するウェブアプリケーションフレームワークです。非常に使いやすく、クライアントサイドJavaScriptアプリケーションとよく組み合わせて使用できます。
サーバー用の新しいフォルダーを作成し、実行してください。
npm initあなたの設定を行うために
package.json. App.jsを作成し、次の内容を貼り付けます。
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => res.send('Message from Express route handler: Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
これはシンプルなExpressサーバーの基本的な雛形です。サーバー自体はexpress()で作成されます。その後、ルートとそれに関連するハンドラ関数が登録されます。この場合、app.get('/', handler)は/ルートへのGETリクエストのためのハンドラ関数を登録します。他のHTTPメソッド、例えばPOSTやPUTのためのハンドラ関数もあります。
ハンドラ内では、reqオブジェクトがHTTPリクエストを表し、resがレスポンスを表します。次に、res.sendは、文字列やJSONオブジェクトのような基本データを返します。また、res.sendFileを使用することで、Expressを従来のWebサーバーとしても利用できますが、静的オブジェクトのパフォーマンスを向上させるためにはネイティブなものを使用することをお勧めします。
最初に、node App.jsを実行できますが、nodemonの方が良いです。なぜなら、基本ファイルの変更を監視し、自動で再起動してくれるからです。
npm i -g nodemon
nodemon app.js
localhost:3000にブラウザでアクセスすると、expressがリクエストに応答しているのを見ることができるはずです。
複数のハンドラ関数に加えて、多くの異なるルートをマッチさせることもできます。明示的なルーティングは簡単です---app.get('/users')は/usersに対して行われたリクエストを処理します。また、ワイルドカードや正規表現を使用してルートをマッチさせることもできます。ルーターハンドラをネストさせることも可能です。たとえば、メインアプリとは別に、通常は独自のファイルから保存されてエクスポートされるサブディレクトリ用に特定の新しいハンドラを作成することができます。例えば'/users'のようなものです。
ただし、これらはすべてまだHTTP経由で提供されているため、最初のアップグレードはHTTPSの設定になります。これは扱いやすいです。必要なのはSSLのプライベートキーと証明書だけです。もしテストだけなら、opensslを使用して自己署名証明書を生成できます。
openssl req -nodes -new -x509 -keyout server.key -out server.certChromeが動揺するときにこの証明書を手動で信頼する必要がありますが、動作します。appでlistenを呼び出すのではなく、HTTPSサーバーを設定してそれにアプリを渡し、その上でlistenします。
const express = require('express')
var https = require('https')
var fs = require('fs')
const app = express()
const port = 3000
app.get('/', (req, res) => res.send('Message from Express route handler: Hello World!'))
https.createServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert')
}, app)
.listen(port, () => console.log(`Example app listening on port ${port}!`))
データベースの接続
このステップはあなたの特定のデータベースに依存しますが、実際には特別なことではありません。あなたがすべきことは、データベース用のNode.JSドライバーをインストールし、Expressに接続情報を渡し、通常のJavaScript(またはAPIサーバーを構築するために使用している他の言語)から接続するのと同じように接続することです。
このガイドでは、Expressとよく組み合わせて使用されるJSONドキュメントデータベースであるMongoDBを使用します。Dockerをお持ちであれば、テスト用にコンテナで実行できます:
docker run -d -p 27017-27019:27017-27019 --name mongodb mongo:4.0.4MongoDB Compassを使用して接続し、管理タスクを実行することができます。
エクスプレスの側では、MongoDB NPMパッケージをインストールして接続する必要があります。
npm install mongodbデータベースが接続された後にExpressを起動したくないので、MongoClient.connect() の中にapp.listen() を移動します。
const express = require('express')
var https = require('https')
var fs = require('fs')
const MongoClient = require('mongodb').MongoClient
const app = express()
const port = 3000
app.get('/', (req, res) => res.send('Message from Express route handler: Hello World!'))
var db;
MongoClient.connect('mongodb://localhost:27017/', (err, client) => {
if (err) return console.log(err)
db = client.db('test') // whatever your database name is
https.createServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert')
}, app)
.listen(port, () => console.log(`Example app listening on port ${port}!`))
})
今、db変数と任意の標準メソッドを使用してMongoに接続できます。ただし、async/awaitを使用することを確認してください。そうしないと、未処理の約束が返されることになります。
app.get('/', async (req, res) => {
const response = await db.collection('test').find().toArray();
res.send(response)
})
これはデータベースに接続し、test コレクションの内容を返し、それをJSON配列として出力します。
Expressはこれらの機能のフロントエンドに過ぎないので、すべてのロジックをこの1つのファイルに定義する必要はありません。モジュールに分割して、Expressのルートハンドラーから呼び出す必要のあるものをインポートできます。
パフォーマンスのためのAPIリクエストのキャッシング
Expressは最速のものではありません。もし生産環境で使用する予定があるのなら、繰り返しのリクエストで高価な検索を行わずに済むように、何らかのキャッシュを実装した方が良いでしょう。
注意すべき点は、ユーザーの個人情報のように、表示するのに認証を必要とするものは絶対にキャッシュしてはいけないということです。一般的なルールとして、もしページが全員に対して同じであるなら、それを全員のためにキャッシュすることができます。PUT、DELETE、POSTメソッドは決してキャッシュしてはいけません。
これにはRedisのようなインメモリストアを使用できますが、単純なメモリキャッシュでもかなりうまく機能します。npmからmemory-cacheをインストールしてください。
npm i memory-cache次に、App.jsで、ルートの前に新しいキャッシングミドルウェアを作成します:
const cache = require('memory-cache');
let memCache = new cache.Cache();
let cacheMiddleware = (duration) => {
return (req, res, next) => {
let key = '__express__' + req.originalUrl || req.url;
let cacheContent = memCache.get(key);
if(cacheContent){
res.send( cacheContent );
return;
} else {
res.sendResponse = res.send;
res.send = (body) => {
memCache.put(key,body,duration*1000);
res.sendResponse(body);
}
next()
}
}
}
そして、キャッシュできるルートでは、このミドルウェアを主要なハンドラーの前に使用して、結果をX秒間キャッシュすることができます:
app.get('/products', cacheMiddleware(30), function(req, res){
...
});

