Express / mongoDB / mongoose

覚えておきたい

2025/02/14 -最終更新日:2025/02/22

TypeScript、Node.jsの魔法

node --loader ts-node/esm --watch index.ts

Express(以下色々覚え書きしているが、Express-generatorを使えば大丈夫)

静的ファイルはpublic

動的ファイルはviewsをデフォルトでは見に行く。

pathはファイルURL(file://)形式なのでfileURLToPathやpath.join()をつかって絶対パスを指定してあげる。

req.bodyを読む必要がある場合、デフォルトではundefined である。bodyparserまたはurlencodedする。

import path from "node:path"; 
import { fileURLToPath } from "node:url"; 
import bodyParser from "body-parser";

const __dirname = path.dirname(fileURLToPath(import.meta.url)); app.use(express.static(path.join(__dirname, "public")));
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

HTMLフォームからPATCHやDELETEをエミュレートする場合、「method-override」を使う。

HTMLフォーム送信リクエスト後にページ遷移させたい場合はres.sendではなくres.redirectを使おう。(リロードしたりするとput/patch/deleteが再実行されるため)

スキーマバリデーションに「joi」というパッケージ

Expressのミドルウェアとは?

ミドルウェアとは、リクエスト/レスポンス間で実行される関数のこと。

node.js用のhttpリクエスト/レスポンスを見ることができるミドルウェアのNPM - Morgan

app.use(morgan("tiny"));

app.METHOD()の第2引数以下にいくらでもミドルウェアのコールバック関数を与えることができる

エラーハンドリング

第三引数のnextや4つの引数を指定して(err,req,res,next)としたりする。

広く使われているカスタムエラーハンドリング↓

Expressの英語のドキュメントにしか書いていないことだが、ステータスコードはerr.statusのものらしい。

export class AppError extends Error {
 message: string;
 status: number;
 constructor(message: string, status: number) {
  super();
  this.message = message;
  this.status = status;
 }
}

app.get("/admin", (req, res) => {
 throw new AppError("管理者しかアクセスできません", 403);
});

// 非同期の場合、next()の中にエラーをあげる
// next(new AppError(''))のように
// その後のプログラムを実行させたくない場合はreturnを忘れないように
// async関数は全部try-catch文で囲う←非同期処理wrap関数を作る


// カスタムエラーハンドラ
app.use((err: any, req: Request, res: Response, next: NextFunction) => {
 const { status = 500, message = `なんかおきたっぽいな` } = err;
 res.status(status).send(message);
});

cookie,session

セット方法はres.cookie()を参照

リクエストのクッキーを読み取るにはcookie-parser(req.signedCookies)パッケージを使う

セッションを使いたい場合cookie-sessionパッケージを使う

mongoDB

show dbs

show collections

db.[collections].find()

ドキュメントの「演算子」でいろんな条件で絞り込み

mongoose

import mongoose from "mongoose";

main()
  .then(() => console.log("成功"))
  .catch((err) => console.log(err));

async function main() {
  await mongoose.connect("mongodb://127.0.0.1:27017/movieApp");
  // スキーマの指定
  const kittySchema = new mongoose.Schema({
    name: String,
    age: Number,
  });
  // コレクションに該当するものを作成↓Kittenは単数形、頭大文字。自動的にkittensコレクションが作られる
  const Kitten = mongoose.model("Kitten", kittySchema);
  // コレクションに値をいれる
  const silence = new Kitten({ name: "Silence" });
  // 保存 (new Kittenで値を入れた場合)
  await silence.save();

  // これでも値を入れれる(saveはいらない)
  await Kitten.insertMany([
    { name: "yui", age: 12 },
    { name: "tyu", age: 45 },
  ]);
}

スキーマにはいろいろな条件を与えることができる

updateはupdate()ではなくfindOneAndUpdate()に options.new=true と使う

定義したスキーマの条件と当てはまらないものを入れてもエラーになるよう、runValidatersもtrueにしておく

ミドルウェア:関数実行前後の動作 pre ⇔ post

1対多のリレーションについて

1対少数の場合、普通にスキーマで定義

1対多の場合、Populateを参照 (親に子の参照をもたせる)

1対超多数の場合、子に親の参照をもたせる