元々フロントエンドに惹かれてプログラミングを始めたこともありバックエンドには苦手意識があります。
今回の記事では少しでもバックエンドに親しむべく、普段何となく使っていた Express、そして Express が採用している API の形式である REST API について調べていきます。
API とは
API は Application Programming Interface の略です。
ソフトウェアが別のソフトウェアと通信するときの窓口を指します。
例えば React というライブラリにおいて state を管理する機能を利用するための窓口、 useState
は API であると言えます。
また他のアプリが自分のサーバーにあるデータにアクセスできるようにしたもの(または他所のサーバーにあるデータにアクセスする手段)を特に Web API と言います。
REST API とは
RESTful API とも言われます。
「REST」は Representational State Transfer の略です。
意味不明
API を設計するための手法、思想ですね。
Restful な API とは、
- 全てのリソースが一意の識別子で識別されている
- インターフェース(ユーザーがアクセスしてくるポイント)には規則がありシンプル
- エンドポイントはリソースを表現していなければならず、URI を見るだけでどのような機能を持つのかがパッと分かるようにする
- HTTP メソッド(GET, POST, PUT, PATCH, DELETE…)をその名の通りの役割で適切に使う
- HTTP ステータスコードを適切に使う
といった規則をある程度守った API のことです。以下に例を示します。
NG🙅
/getitem
/modifyitem
/deleteitem
GET /item/:id
PATCH /item/:id
DELETE /item/:id
OK🙆
GET /items/:id
PATCH /items/:id
DELETE /items/:id
POST /customers/:id/orders
上の例では
- 商品の取得
- 商品の編集
- 商品の削除
- 顧客の注文を履歴へ追加
という4つの操作を行おうとしています。
REST API での正しい実装は「OK」の方です。別の操作に対し別のエンドポイントを用意するのではなく、同じエンドポイントに対して別の HTTP メソッドを使ってアクセスします。また HTTP メソッドが動きを表しているため、URI に動詞を入れる必要はありません。
また全てのリソースは id で管理されているはずなので、特定の商品にアクセスするために id が使えます。
そして item
ではなく items
と 複数形を使うようにしましょう。
もしかしたら商品は全部で1点しかないかもしれませんが、REST API では複数形で定義することがルールとなっています。その方が「複数の中から1つを選んで操作するよ」というふうに意味が通りやすいですよね。
最後に POST の例では /customers/:id/orders
というふうに URI が階層になっています。「顧客/このID/全ての注文」という感じですね。このような書き方を ネスト といい、これも RESTful な API の特徴です。
Express とは
Node.js でサーバーを簡単に作成できるフレームワークです。
Express - Node.js web application framework
Express の設定を理解する
Express でサーバーを立てる最も簡単な例としては以下のようになります。
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
// 引用: https://expressjs.com/en/starter/hello-world.html
上のコードは公式サイトから引用しました。
Express の開発陣はセミコロンつけない派なんですね。
この状態で js ファイルを実行すれば http://localhost:3000/ でサーバーが立ち上がります。
しかしまあこの辺は設定呪文だと思っていつもほぼコピペしていました。今回はきちんと内容を見ていきます。
const express = require('express')
npm や yarn でインストール済みの express を 変数「express」としてrequire してこのファイルで使えるようにしています。
const app = express()
express のインスタンスを app
に格納しています。
今後この app で使えるメソッドを使って express のサーバーを設定していきます。
app.get('/', (req, res) => {
res.send('Hello World!')
})
-
app.get
: 第1引数の URI に対し、get メソッドでアクセスがあった場合に第2引数の関数が動く -
req
: リクエストオブジェクトが入る引数 -
res
: レスポンスオブジェクトが入る引数 -
res.send
: 引数に入っている文字列を返すメソッド
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
app
の listen
メソッドを使い、第一引数にポートを設定し、第二引数にサーバー立ち上げ時に実行したい関数を渡してサーバーを起動します。サーバーがきちんと動いていることを確かめるためコンソール出力するといいでしょう。
第一引数のポートは直書きでもいいのですが、デプロイしたり他の人の手元で動かしてもらったりすることを考えると環境変数に対応させておいた方がいいでしょう。
const express = require('express')
const app = express()
// 環境変数で起動するが、指定がなければ localhost 3000 で立ち上げる
const port = PROCESS.ENV.PORT || 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
// 変数で指定されているので様々なケースに対応できる
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
// 引用: https://expressjs.com/en/starter/hello-world.html
他の HTTP メソッドを使う
app.METHOD
の形で以下の HTTP メソッドを使えます。
checkout
copy
delete
get
head
lock
merge
mkactivity
mkcol
move
m-search
notify
options
patch
post
purge
put
report
search
subscribe
trace
unlock
unsubscribe
Express 4.x - API Reference
中でも本当によく使うのは以下でしょう。
- app.delete
- app.get
- app.patch
- app.post
- app.put
また全ての HTTP リクエストに対応する app.all
メソッドもあります。
app.all('/secret', (req, res, next) => {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
パスパラメータを渡す
パスの一部には任意の入力を受け取れるパスパラメータを設定できます。
app.get('/users/:userId/books/:bookId', (req, res) => {
res.send(req.params)
})
// 引用: https://expressjs.com/en/guide/routing.html
上の例の場合、パスは /users/:userId/books/:bookId
となっています。例えば http://localhost:3000/users/34/books/8989
というふうにアクセスしたとしましょう。
すると req オブジェクトの params = req.params
には { "userId": "34", "bookId": "8989" }
というオブジェクトが入ります。
「userId が 34 で、bookId が 8989 のリソースに対するアクセスだな」と解析できるわけです。
クエリパラメータを渡す
パスパラメータとは違い、任意の入力として渡すわけではなく URI の末尾に追加情報としてくっつけます。省略可能です。
app.get('/users/:userId/books/?sort=true', (req, res) => {
res.json(data)
})
例えば上のような使い方があるでしょう。ここでは「データを昇順にソートしてね」という条件を付与していますが、ソートは省略可能です。
他に検索やフィルタにも使えますね。Amazon のリンクにもたくさんのクエリパラメータがあるのを見つけられると思います。
ミドルウェアの使用
app.use
メソッドを使うことでミドルウェアを使用することができ、通常盤の Express では使えないたくさんの便利な機能が使えます。
自分でパスと関数を指定することもできますし、Express から公式提供されているものも使えます。
app.use('/user/:id', (req, res, next) => {
console.log('Request Type:', req.method)
next()
})
// 引用: http://expressjs.com/en/guide/using-middleware.html
app.use(express.json()) // json を解析する
まとめ
- API はソフトウェアが別のソフトウェアと通信するときの窓口
- RESTful API は以下のような規則をある程度守っている API:
- 全てのリソースが一意の識別子で識別されている
- インターフェース(ユーザーがアクセスしてくるポイント)には規則がありシンプル
- エンドポイントはリソースを表現していなければならず、URI を見るだけでどのような機能を持つのかがパッと分かるようにする
- HTTP メソッド(GET, POST, PUT, PATCH, DELETE…)をその名の通りの役割で適切に使う
- HTTP ステータスコードを適切に使う
- express は
app.METHOD
の形で多くの HTTP メソッドを使うことができ、app.listen
で起動できる - パスの一部には任意の入力を受け取れるパスパラメータを設定できる
- 任意の入力としてクエリパラメータを設定できる
- ミドルウェアを使用することで、通常盤の Express では使えないたくさんの便利な機能が使える
参考資料