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対超多数の場合、子に親の参照をもたせる