routes/api/users.js

/**
 * Users API routes module.
 * @module routes/api/users
 * @requires express
 * @requires gravatar
 * @requires bcrypt
 * @requires jwt
 * @requires config
 * @requires express-validator
 * @requires models/User
 * 
 * @example
 * // POST api/users
 * // Usage:
 * // 1. Add the following route in your express app
 * app.post('/api/users', async (req, res) => { ... });
 *
 * // 2. Send a POST request with user's registration information
 * // e.g., using axios:
 * const axios = require('axios');
 * const userData = {
 *   name: 'John Doe',
 *   email: 'johndoe@example.com',
 *   password: 'mypassword',
 * };
 *
 * axios.post('http://localhost:5000/api/users', userData)
 *   .then(response => {
 *     console.log(response.data); // User's JWT
 *   })
 *   .catch(error => {
 *     console.error('Error:', error);
 *   });
 */


const express = require('express');
const router = express.Router();
const gravatar = require('gravatar');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('config');
const { check, validationResult } = require('express-validator');
const normalize = require('normalize-url');

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


/**
 * @route   POST api/users
 * @desc    Register user
 * @access  Public
 * @param {Object} req - Express request object
 * @param {Object} req.body - Request body containing the user's registration information
 * @param {string} req.body.name - User's name
 * @param {string} req.body.email - User's email address
 * @param {string} req.body.password - User's password
 * @param {Object} res - Express response object
 * @returns {Object} - JSON response containing the user's JWT or an error message
 * @throws {Error} - If there's a server error
 */
router.post(
  '/',
  [
    check('name', 'Name is required').notEmpty(),
    check('email', 'Please include a valid email').isEmail(),
    check('password', 'Please enter a password with 6 or more characters').isLength({ min: 6 })
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    const { name, email, password } = req.body;

    try {
      let user = await User.findOne({ email });
      // See if user exists
      if (user) {
        return res.status(400).json({ errors: [{ msg: 'User already exists' }] });
      }

      // Get users gravatar
      const avatar = normalize(
        gravatar.url(email, {
          s: '200',
          r: 'pg',
          d: 'mm'
        }),
        { forceHttps: true }
      );

      user = new User({
        name,
        email,
        avatar,
        password
      });

      // Encrypt password
      const salt = await bcrypt.genSalt(10);

      user.password = await bcrypt.hash(password, salt);

      await user.save();

      // Return jsonwebtoken
      const payload = {
        user: {
          id: user.id
        }
      };

      jwt.sign(
        payload,
        config.get('jwtSecret'),
        { expiresIn: '5 days' },
        (err, token) => {
          if (err) throw err;
          res.json({ token });
        }
      );
    } catch (err) {
      console.error(err.message);
      res.status(500).send('Server error');
    }
  }
);

/**
 * Users API router.
 * @type {express.Router}
 */
module.exports = router;