FullStackOpen Part3-a Node.js and Express メモ

Nodeを使ってバックエンドを作成
npm initコマンドを適切なフォルダで実行しプロジェクトを作成

startで実行するコードを指定すればnpm startでそのまま実行できる

{
  "name": "backend",
  "version": "0.0.1",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "Part3_backend"
  },
  "author": "Masa",
  "license": "MIT"
}

Simple Web Server

関数定義の見方
引数: データ型
: 引数は必須で、指定されたデータ型である必要がある
引数?: データ型 | 別のデータ型 | ... : ?記号が付いている引数はオプショナル(任意)で、この引数を省略することも可能

(method) ServerResponse<IncomingMessage>.writeHead(
 statusCode: number, 
 headers?: http.OutgoingHttpHeaders | http.OutgoingHttpHeader[] | undefined): http.ServerResponse<http.IncomingMessage> & {
    ...;
}

つまり
(method) オブジェクト<ジェネリクス>.関数名(必須引数: データ型, オプション引数?: データ型1 | データ型2 | undefined): 返り値

サーバーオブジェクトの作成は以下の通り

const http = require('http')

let notes =[{...}]

const app = http.createServer((request, response) => {
    response.writeHead(200, {'Content-Type': 'application/json'})
    response.end(JSON.stringify(notes))
})

const PORT =3001
app.listen(PORT)
console.log(`Server running on port ${PORT}`)

Express

Nodeの開発を楽にするライブラリ
npm install expressでインストール

以下のような感じで使う
const express = require('express')
const app = express()で定義して、app.listen(PORT, () => {})でリッスン
エンドポイントの定義はapp.getとかでやる
レスポンスはresponse.send(テキストまたはHTML)かresponse.json(オブジェクト)
自動でJSONstringifyしてくれる

const express = require('express')
const app = express()

let notes = [
  ...
]

app.get('/', (request, response) => {
  response.send('<h1>Hello World!</h1>')
})

app.get('/api/notes', (request, response) => {
  response.json(notes)
})

const PORT = 3001
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

Nodemon

Nodeアプリに変更を加えた際に自動で再起動して設定を反映してくれる
node install --save-dev nodemon

nodemonを起動するにはpackage.jsonに以下を加える

{
  // ..
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  // ..
}

そして"npm run dev"で実行

REST

Representational State Transfer
全てのリソースにはリソースの一意のURLが関連付けられる、というイメージ

一般的なイメージではこんな感じ

REST example

Fetching a single resource

Expressではコロン構文(/:id/など)を使ってルートのパラメータを定義できる
以下のような感じ

注意点
request.params.idはstring型なのでNumber型にキャストする必要あり
存在しないIDのnotesを取ろうとしたときはresponse.status(404).end()を返す
end()はデータがないときに返すもの

app.get('/api/notes/:id', (request, response) => {
    const id = Number(request.params.id)
    const note = notes.find(note => note.id === id)
    if(note){
        response.json(note)
    }else{
        response.status(404).end()
    }
})

Postman

おなじみRESTクライアント

VSCode REST Client

こちらも便利。.rest拡張子のファイルを作れば利用できる

Receiving Data

app.use(express.json())を実行することで、ポストされたデータをJSONにパースすることができる

リクエストからデータを受け取るときはreq.bodyでアクセス

Postmanを使うときはBodyをrawにしてJSONを選択

Make sure to select JSON

全体としてはこんな感じ

const generateId = () => {
  const maxId = notes.length > 0
    ? Math.max(...notes.map(n => n.id))
    : 0
  return maxId + 1
}

app.post('/api/notes', (request, response) => {
  const body = request.body

  if (!body.content) {
    return response.status(400).json({ 
      error: 'content missing' 
    })
  }

  const note = {
    content: body.content,
    important: body.important || false,
    id: generateId(),
  }

  notes = notes.concat(note)

  response.json(note)
})
Math.max(...notes.map(n => n.id))

mapでIDの配列にしているだけではmax関数を使えない
max関数は複数の引数を取るので、…を使って個別の数値に変換している

About HTTP Request Types

安全性(safety)と冪等性(idempotency)

安全性
GETリクエストがサーバーに影響を及ぼさないようにすること

冪等性
POST以外のHTTPリクエストでは、何度実行しても同じ結果であること

POSTは唯一安全でも冪等でもないリクエストである

いろんな種類のリクエストがあるが厳密に区別するものはない

Middleware

ミドルウェアとはリクエストとレスポンスのオブジェクトを処理するために使用できる機能
たとえばExpress json-parserなど(app.use(express.json())のこと)

ミドルウェアは自分でも定義できる, app.useで使用
3つパラメータを取る nextはパラメータとして渡された関数を最後に実行する

const requestLogger = (request, response, next) => {
    console.log('Method:', request.method)
    console.log('Path:', request.path)
    console.log('Body:', request.body)
    console.log('---')
    next()
}

ミドルウェアはapp.use(express.json())の後に実行すること


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