You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

新手求Node.js Express MongoDB REST API完整教程:含路由等核心功能

Hey there! As someone who’s built several Node.js/Express/MongoDB APIs from scratch, I’ll walk you through a complete, hands-on tutorial that covers every part you mentioned—from project setup to advanced relationships and a full authentication system. Let’s dive in!


1. Project Setup & Initial Configuration

First, let’s get your project off the ground:

  • Initialize a new Node.js project: npm init -y
  • Install core dependencies: npm install express mongoose dotenv bcryptjs jsonwebtoken
  • Create a project structure like this:
    your-api/
    ├── src/
    │   ├── config/
    │   │   └── db.js
    │   ├── controllers/
    │   ├── middleware/
    │   ├── models/
    │   ├── routes/
    │   └── app.js
    └── .env
    

Connect to MongoDB

Add your MongoDB URI to .env (local or Atlas):

MONGODB_URI=mongodb://localhost:27017/your-api-db
JWT_SECRET=your-super-secret-jwt-key

Create src/config/db.js to handle the connection:

const mongoose = require('mongoose');
require('dotenv').config();

const connectDB = async () => {
  try {
    const conn = await mongoose.connect(process.env.MONGODB_URI);
    console.log(`MongoDB Connected: ${conn.connection.host}`);
  } catch (error) {
    console.error(`Connection Error: ${error.message}`);
    process.exit(1);
  }
};

module.exports = connectDB;

Initialize Express in src/app.js:

const express = require('express');
const connectDB = require('./config/db');

// Connect to database
connectDB();

const app = express();

// Middleware to parse JSON requests
app.use(express.json());

// Mount routes (we'll create these next)
app.use('/api/users', require('./routes/userRoutes'));
app.use('/api/posts', require('./routes/postRoutes'));
app.use('/api/courses', require('./routes/courseRoutes'));

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

2. Express Routes Basics

Routes define how your API responds to client requests. Use express.Router() to organize routes by resource:

Example User Routes (src/routes/userRoutes.js)

const express = require('express');
const router = express.Router();
const { registerUser, loginUser, getMe } = require('../controllers/userController');
const { protect } = require('../middleware/authMiddleware');

// Public routes
router.post('/register', registerUser);
router.post('/login', loginUser);

// Protected route (requires authentication)
router.get('/me', protect, getMe);

module.exports = router;
  • Route Parameters: Use /:id to capture dynamic values (e.g., router.get('/:id', getUserById)). Access it via req.params.id.
  • Query Strings: Access filters like /api/posts?category=tech via req.query.category.

3. Middleware Deep Dive

Middleware are functions that run between the request and response. They can modify requests, validate data, handle errors, and more.

Custom Logging Middleware

Create src/middleware/logger.js:

const logger = (req, res, next) => {
  console.log(`${req.method} ${req.protocol}://${req.get('host')}${req.originalUrl}`);
  next(); // Pass control to the next middleware/route
};

module.exports = logger;

Mount it in app.js with app.use(logger);

Error Handling Middleware

Add this to the bottom of app.js to catch all errors:

app.use((err, req, res, next) => {
  const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
  res.status(statusCode);
  res.json({
    message: err.message,
    stack: process.env.NODE_ENV === 'production' ? null : err.stack
  });
});

Authentication Middleware (Preview)

We’ll use this to protect routes later. Create src/middleware/authMiddleware.js:

const jwt = require('jsonwebtoken');
const User = require('../models/User');

const protect = async (req, res, next) => {
  let token;

  // Check for Bearer token in Authorization header
  if (req.headers.authorization?.startsWith('Bearer')) {
    try {
      token = req.headers.authorization.split(' ')[1];
      const decoded = jwt.verify(token, process.env.JWT_SECRET);
      // Attach user to request (exclude password)
      req.user = await User.findById(decoded.id).select('-password');
      next();
    } catch (error) {
      res.status(401).json({ message: 'Not authorized: Token invalid' });
    }
  }

  if (!token) {
    res.status(401).json({ message: 'Not authorized: No token' });
  }
};

module.exports = { protect };

4. Mongoose Models & Relationships

Mongoose lets you define schemas and handle MongoDB relationships. Let’s cover one-to-many and many-to-many associations.

One-to-Many: User → Posts

A user can have multiple posts, but a post belongs to one user.

Create src/models/User.js:

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

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

// Hash password before saving
userSchema.pre('save', async function(next) {
  if (!this.isModified('password')) return next();
  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
});

// Method to compare passwords
userSchema.methods.matchPassword = async function(enteredPassword) {
  return await bcrypt.compare(enteredPassword, this.password);
};

module.exports = mongoose.model('User', userSchema);

Create src/models/Post.js:

const mongoose = require('mongoose');

const postSchema = new mongoose.Schema({
  title: { type: String, required: true },
  content: { type: String, required: true },
  user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User', // Reference the User model
    required: true
  }
}, { timestamps: true });

module.exports = mongoose.model('Post', postSchema);

Query with Population

To fetch posts with their associated user data:

const getPosts = async (req, res) => {
  const posts = await Post.find().populate('user', 'name email'); // Only return name/email
  res.status(200).json(posts);
};

Many-to-Many: Users ↔ Courses

A user can enroll in multiple courses, and a course can have multiple students.

Update src/models/User.js to add a courses array:

const userSchema = new mongoose.Schema({
  // ... existing fields
  courses: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Course' }]
});

Create src/models/Course.js:

const mongoose = require('mongoose');

const courseSchema = new mongoose.Schema({
  title: { type: String, required: true },
  description: { type: String, required: true },
  students: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }]
});

module.exports = mongoose.model('Course', courseSchema);

Enroll a Student in a Course

Create a controller function to handle the bidirectional association:

const enrollStudent = async (req, res) => {
  const { courseId, userId } = req.body;

  try {
    // Add course to user's enrollment list
    await User.findByIdAndUpdate(userId, { $push: { courses: courseId } });
    // Add user to course's student list
    await Course.findByIdAndUpdate(courseId, { $push: { students: userId } });

    res.status(200).json({ message: 'Student enrolled successfully' });
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
};

5. Complete Authentication System

Let’s build a full login/register system with JWT tokens.

User Controller (src/controllers/userController.js)

const User = require('../models/User');
const jwt = require('jsonwebtoken');

// Generate JWT token
const generateToken = (id) => {
  return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: '30d' });
};

// Register a new user
const registerUser = async (req, res) => {
  const { name, email, password } = req.body;

  // Check if user already exists
  const userExists = await User.findOne({ email });
  if (userExists) {
    return res.status(400).json({ message: 'User already exists' });
  }

  // Create user
  const user = await User.create({ name, email, password });
  if (user) {
    res.status(201).json({
      _id: user._id,
      name: user.name,
      email: user.email,
      token: generateToken(user._id)
    });
  } else {
    res.status(400).json({ message: 'Invalid user data' });
  }
};

// Login user
const loginUser = async (req, res) => {
  const { email, password } = req.body;
  const user = await User.findOne({ email });

  if (user && (await user.matchPassword(password))) {
    res.json({
      _id: user._id,
      name: user.name,
      email: user.email,
      token: generateToken(user._id)
    });
  } else {
    res.status(401).json({ message: 'Invalid email or password' });
  }
};

// Get current logged-in user
const getMe = async (req, res) => {
  res.status(200).json(req.user);
};

module.exports = { registerUser, loginUser, getMe };

6. Testing Your API

Use tools like Postman or curl to test endpoints:

  • Register: POST http://localhost:5000/api/users/register with name, email, password in the request body.
  • Login: POST http://localhost:5000/api/users/login with email and password to get a token.
  • Protected Route: GET http://localhost:5000/api/users/me with a Bearer <token> header to access your user data.

内容的提问来源于stack exchange,提问作者tapos ghosh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:05:57