このサイトは、特にやりたいこともなく無気力に生きる汚い中年おじさんデザイナー佐藤文彦のポートフォリオサイトです。
応援よろしくお願いします。

ExpressとMongoDBでAPIサーバーを作る

2022/10/22

普段はフロントエンドをやることが多い(というかフロントしかできない)ので、node.jsを利用してバックエンド環境も準備してみます。

前提

  • サーバーにExpressを利用
  • DBにMongoDBを利用
  • typescriptを利用
  • Dockerは利用しない

ファイル構成

とりあえずこんな感じ。

.
├── index.ts
├── node_modules
├── package-lock.json
├── package.json
├── src
    └── models
└── tsconfig.json

バックエンドサーバーを用意

バックエンドサーバー用のExpressをインストール。

npm i express

ファイルを保存時にサーバーを自動で再起動してくれるNodemonをインストール。

npm i nodemon

↑に合わせて、package.jsonはサーバー立ち上げ用にscriptsだけ変更。

{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon index.ts" // ←これ
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  ...

}

ローカルサーバーを立ち上げ

Expressを利用してローカルサーバーを立ち上げます。

index.tsに追加。

import express from 'express'
const app = express()
const PORT = 5050 // ポートはお好みで

app.listen(PORT, () => {
  console.log('ローカルサーバー起動中')
})

サーバーと立ち上げてみる。

$ npm run start
[nodemon] starting `ts-node index.ts`
サーバー起動中

サーバーが立ち上がっているか確認したい場合は、以下のようにルーティングを追加して確認してみます。

import express from 'express'
const app = express()
const PORT = 5050 // ポートはお好みで

// localhost:5050をブラウザで確認してみる
app.get('/',(req,res) => {
    res.send('OK')
})

app.listen(PORT, () => {
  console.log('ローカルサーバー起動中')
})

DBを用意する

データベースにはMongoDBを利用します。
MongoDBのページから「無料で始める」のボタンを押して、signupします。

DBを用意する

signupが完了したら、「New Project」から新規プロジェクトを作成します。

DBを用意する
DBを用意する
DBを用意する

プロジェクトを作成したらデータベースも作成します。

DBを用意する

無料で使いたいので、「FREE」を選択します。 Providerは「AWS」を選択、Regionは「Tokyo」を選択します。

DBを用意する

プロジェクトへの認証方法を設定します。

ユーザー名とパスワードで認証するようにします。

DBを用意する

接続環境を設定します。 とりあえずどこからでも接続できるようにするには0.0.0.0としておきます。
接続IPを絞りたいなら、「Add My Current IP Address」を押すと、現在のIPが設定されます。

DBを用意する

DBにデータを登録する

用意したMongoDBにデータを登録する準備をします。

DBの操作にはmongooseを利用します。

インストールする。

npm i mongoose

DBに接続する

公式ドキュメントはこちら

mongoose.connect(接続先パス)でDBに接続します。

接続先のURLは以下の手順で確認できます。

「Connect」ボタンを押します。

DBを用意する

「Connect your application」ボタンを押します。

DBを用意する

接続先パスが表示される。passwordはDBを作成した際のものを利用します。

DBを用意する

import express from 'express'
import mongoose from 'mongoose'

const app = express()
const PORT = 5050

// DB接続
try {
    mongoose.connect('mongodb+srv://hogehoge:hogehoge@cluster0.wxiritf.mongodb.net/?retryWrites=true&w=majority')
} catch (error) {
    console.log(error)
}

DBのURLは直接コードに記載すると問題があるので、envファイルに定義します。

dotenvを利用するためにライブラリをインストール。

npm i -D dotdenv

.envファイルを作成。パスを定義する。

MONGODB_URL="mongodb+srv://hogehoge:hogehoge@cluster0.wxiritf.mongodb.net/?retryWrites=true&w=majority"

envファイルからprocess.env.MONGODB_URLでパスを読み込む。

import express from 'express'
import mongoose from 'mongoose'

const app = express()
const PORT = 5050

// DB接続
try {
  mongoose.connect(process.env.MONGODB_URL!)
} catch (error) {
  console.log(error)
}

ユーザー登録用のAPIを作成する

  1. ユーザーがEメールとパスワードを入力(クライアント)
  2. 1の登録内容をバリデーションチェック(APIサーバー)
  3. 同じEメールのユーザーがいないかの重複チェック(APIサーバー)
  4. パスワードの暗号化(APIサーバー)
  5. がEメールとパスワードをDBに保存(APIサーバー)
  6. JWTをクライアントに返却する(APIサーバー)

スキーマーを作成する

スキーマーとは、どのようなデータを格納するかの定義です。
ドキュメントを参考にスキーマを作成していきます。

スキーマのデータはsrc/modelsに作成していきます。

試しにUserモデルを作成してみます。

src/models/user.tsに追加。

import mongoose from 'mongoose'

const userSchema = new mongoose.Schema({
  username: {
    type: String,
    required:true,
    unique: true,
  },
  password: {
    type:String,
    required: true,
  }
})

// スキーマからモデルを生成する
// 外部から呼び出せるようexportする
export const User = mongoose.model('User',userSchema)

ユーザー登録用のAPIを作成する。
作成したUserスキーマを利用してDBに登録する。

index.tsに追加。

省略...
app.post('register',(req: express.Request, res: express.Response) => {
  try {
    // ユーザーの新規作成
    const user = await User.create(req.body)
    return res.status(200).json({user})
  } catch (error) {
    return res.status(500).json(error)
  }
})

パスワードを暗号化して登録する

crypto-jsを利用してパスワードを暗号化します。

npm i -D crypto-js

こちらのドキュメントに沿って進めます。

第一引数に暗号化する文字列。第二引数に任意のランダムな文字列をシークレットキー(秘密鍵)として設定します。
シークレットキーは第三者からみられないように環境変数化したほうがよいです。

// Encrypt
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123');

こんな感じになります。

省略...
app.post('register',(req: express.Request, res: express.Response) => {
  try {
    const password = req.body.password
    req.body.password = cryptoJs.AES.encrypt(password, process.env.SECRET_KEY!)
    // ユーザーの新規作成
    const user = await User.create(req.body)
    return res.status(200).json({user})
  } catch (error) {
    return res.status(500).json(error)
  }
})

JWTを発行する

クライアントに返却するJWTを発行するようにします。

jsonwebtokenを利用します。

npm i -D jsonwebtoken

こちらのドキュメントに沿って進めます。

こちらも第二引数のシークレットキーはenvファイルに環境変数として設定します。

jwt.sign(payload, secretOrPrivateKey, [options, callback])

こんな感じになります。

省略...
app.post('register',(req: express.Request, res: express.Response) => {
  try {
    const password = req.body.password
    req.body.password = cryptoJs.AES.encrypt(password, process.env.SECRET_KEY!)
    // ユーザーの新規作成
    const user = await User.create(req.body)
    // JWTの発行
    const token = JWT.sign({id: user._id}, process.env.TOKEN_SECRET_KEY!, {expiresIn: '24h'}) 
    // tokenもレスポンスに含める
    return res.status(200).json({user, token})
  } catch (error) {
    return res.status(500).json(error)
  }
})

その他

カテゴリ

新規記事