בניית API באמצעות Express¶
ספריית Express היא חבילת Node.js לבניית שרתי Web ו-API.
במקום לעבוד ישירות עם http module (שזה מסובך), Express נותן:
- ניהול Routes
- עבודה עם JSON
- Middleware
- ניהול בקשות HTTP
- קל מאוד לבנות REST API
ממש כמו fastapi אבל בjs
התקנה¶
מבנה פרויקט¶
project/
│
├── src/
│ ├── server.js
│ │
│ ├── models/
│ │ └── user.model.js
│ │
│ ├── controllers/
│ │ ├── user.controller.js
│ │ └── auth.controller.js
│ │
│ ├── routes/
│ │ ├── user.routes.js
│ │ └── auth.routes.js
│ │
│ └── middlewares/
│ ├── auth.middleware.js
│ └── error.middleware.js
│
└── .env
קובץ הmain¶
src/server.js¶
require("dotenv").config()
const express = require("express")
const mongoose = require("mongoose")
const userRoutes = require("./routes/user.routes")
const authRoutes = require("./routes/auth.routes")
const errorMiddleware = require("./middlewares/error.middleware")
const app = express()
app.use(express.json())
app.use("/api/users", userRoutes)
app.use("/api/auth", authRoutes)
app.use(errorMiddleware)
mongoose.connect(process.env.MONGO_URL)
.then(() => {
console.log("DB Connected")
app.listen(3000, () => console.log("Server running"))
})
כאן אנחנו מגדירים את כל הrouter-ים, מתחברים לmongo db, טוענים את הקובץ .env שמכיל את הuri של הmongo במקרה שלנו.
Model- MongoDB¶
models/user.model.js¶
const mongoose = require("mongoose")
const schema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
name: String,
createdAt: { type: Date, default: Date.now }
})
module.exports = mongoose.model("User", schema)
Controller¶
controllers/user.controller.js¶
const User = require("../models/user.model")
exports.getAll = async (req, res, next) => {
try {
const users = await User.find()
res.json(users)
} catch (err) {
next(err)
}
}
exports.getOne = async (req, res, next) => {
try {
const user = await User.findById(req.params.id)
if (!user) return res.sendStatus(404)
res.json(user)
} catch (err) {
next(err)
}
}
exports.create = async (req, res, next) => {
try {
const user = await User.create(req.body)
res.status(201).json(user)
} catch (err) {
next(err)
}
}
exports.update = async (req, res, next) => {
try {
const user = await User.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true }
)
res.json(user)
} catch (err) {
next(err)
}
}
exports.remove = async (req, res, next) => {
try {
await User.findByIdAndDelete(req.params.id)
res.sendStatus(204)
} catch (err) {
next(err)
}
}
Authentication Controller¶
controllers/auth.controller.js¶
const User = require("../models/user.model")
const bcrypt = require("bcrypt")
const jwt = require("jsonwebtoken")
exports.register = async (req, res, next) => {
try {
const hash = await bcrypt.hash(req.body.password, 10)
const user = await User.create({
email: req.body.email,
password: hash,
name: req.body.name
})
res.status(201).json(user)
} catch (err) {
next(err)
}
}
exports.login = async (req, res, next) => {
try {
const user = await User.findOne({ email: req.body.email })
if (!user) return res.status(401).json({ error: "Invalid" })
const ok = await bcrypt.compare(req.body.password, user.password)
if (!ok) return res.status(401).json({ error: "Invalid" })
const token = jwt.sign(
{ id: user._id },
process.env.JWT_SECRET
)
res.json({ token })
} catch (err) {
next(err)
}
}
Routes¶
routes/user.routes.js¶
const router = require("express").Router()
const ctrl = require("../controllers/user.controller")
const auth = require("../middlewares/auth.middleware")
router.get("/", auth, ctrl.getAll)
router.get("/:id", auth, ctrl.getOne)
router.post("/", ctrl.create)
router.put("/:id", auth, ctrl.update)
router.delete("/:id", auth, ctrl.remove)
module.exports = router
routes/auth.routes.js¶
const router = require("express").Router()
const ctrl = require("../controllers/auth.controller")
router.post("/register", ctrl.register)
router.post("/login", ctrl.login)
module.exports = router
Middleware- JWT¶
middlewares/auth.middleware.js¶
בexpress אנחנו יכולים להגדיר middleware.
קטע קוד שרץ בכל בקשה שקורת לapi שלנו, שמבצעת לוגיקה מסוימת.
זה יכול להיות קטע קוד שעושה לוג לכל הבקשות, ועוד.
במקרה הבא זה קטע קוד שעושה authorization (בודק אם העובר jwt token תקין)
const jwt = require("jsonwebtoken")
module.exports = (req, res, next) => {
const token = req.headers.authorization?.split(" ")[1]
if (!token) return res.sendStatus(401)
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET)
req.user = decoded
next()
} catch {
res.sendStatus(403)
}
}
Error Middleware מרכזי¶
middlewares/error.middleware.js¶
module.exports = (err, req, res, next) => {
console.error(err)
res.status(500).json({ error: "Server error" })
}
איך Express עובד- הסבר פשוט¶
כשלקוח שולח בקשה:
הזרימה:
- הבקשה נכנסת ל-Express
- הExpress עובר על middleware (למשל JSON parser)
- הExpress מוצא route מתאים
- אם יש auth middleware → רץ
- ה-Controller מופעל
- הController מדבר עם DB
- מחזירים JSON
לסיכום:
חבילת express מאפשרת לנו לכתוב api בפשטות בjs, ונהוג להשתמש בה או בספריות דומות כאשר בונים api בjs.