Création d'une API d'inscription avec Node.js, Express et MongoDB

Description

Cet article décrit comment mettre en place un serveur avec Node.js et Express, se connecter à une base de données MongoDB et créer des interfaces back-end simples. Le projet front-end utilise Vue 2 pour un système de gestion hôtelière. En lisant cet article, vous apprendrez à vous connecter à MongoDB, à exécuter des commandes de manipulation de la base de données, à gérer les requêtes cross-origin depuis le front-end et à respecter les bonnes pratiques lors de l'appel des endpoints back-end.

Présentation du projet back-end

Structure du projet back-end

Nous nous concentrons ici sur la connexoin à MongoDB et les cmomandes associées. Les autres fichiers ne sont pas détaillés.

  1. Ouvrez un terminal et exécutez mongod pour démarrer la base de données (ne fermez pas la fenêtre).
  2. Ouvrez un nouveau terminal et exécutez mongo (ne fermez pas la fenêtre).

bin/www.js

Ce fichier met en place le serveur HTTP. Il écoute sur le port 4000.

const app = require('../app');
const debug = require('debug')('mgserver:server');
const http = require('http');

function normalizePort(val) {
  const port = parseInt(val, 10);
  if (isNaN(port)) return val;
  if (port >= 0) return port;
  return false;
}

const port = normalizePort(process.env.PORT || '4000');
app.set('port', port);

const server = http.createServer(app);

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

function onError(error) {
  if (error.syscall !== 'listen') throw error;
  const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' nécessite des privilèges élevés');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' est déjà utilisé');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

function onListening() {
  const addr = server.address();
  const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
  debug('En écoute sur ' + bind);
}

db/index.js

const mongoose = require('mongoose');
mongoose.connect("mongodb://127.0.0.1:27017/Mango");

const connection = mongoose.connection;
connection.on('error', console.error.bind(console, 'Erreur de connexion :'));
connection.once('open', () => {
  console.log('Connexion à la base de données réussie');
});

const userSchema = new mongoose.Schema({
  username: { type: String },
  password: { type: String }
});
const UserModel = mongoose.model("users", userSchema);

module.exports = {
  UserModel
};

L'URI mongodb://127.0.0.1:27017/Mango utilise le protocole MongoDB, l'adresse locale (127.0.0.1), le port par défaut 27017, et la base de données nommée Mango (créée automatiquement si elle n'existe pas).

router/user/User.js

Ce fichier expose un endpoint d'inscription.

const express = require('express');
const { UserModel } = require('../../db');
const router = express.Router();

router.post('/register', async (req, res, next) => {
  try {
    const form = req.body;
    const existingUser = await UserModel.find(form);
    if (existingUser.length > 0) {
      return res.json({
        code: 0,
        message: 'Nom d\'utilisateur déjà existant'
      });
    }
    const newUser = await UserModel.create(form);
    if (newUser) {
      return res.json({
        code: 0,
        message: 'Inscription réussie'
      });
    } else {
      return res.json({
        code: 1,
        message: 'Échec de l\'inscription'
      });
    }
  } catch (err) {
    console.error(err);
    return res.json({
      code: 0,
      message: 'Erreur lors de l\'inscription'
    });
  }
});

module.exports = router;

app.js

const createError = require('http-errors');
const express = require('express');
const app = express();
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const cors = require('cors');
require("./db/index.js");

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

const userRouter = require('./router/user/User.js');
// La route de base définie ici + celle du sous-router constitue le chemin complet.
// Exemple : si l'on utilise "/api/user", l'URL complète sera "/api/user/register".
app.use( "/user", userRouter);

// Gestion 404
app.use((req, res, next) => {
  next(createError(404));
});

// Gestionnaire d'erreurs
app.use((err, req, res, next) => {
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

Projet front-end

Configuration du proxy CORS

Dans vue.config.js, nous utilisons un proxy pour éviter les problèmes de cross-origin.

devServer: {
  static: {
    directory: path.join(__dirname, 'public')
  },
  proxy: {
    '/api': {
      target: 'http://localhost:4000',
      changeOrigin: true,
      pathRewrite: { '^/api': '' },
      logLevel: 'debug'
    }
  }
}

Fichier request.js

Nous configurons Axios avec des intercepteurs pour la gestion des chargements et des erreurs.

import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import axios from 'axios';
import BASE_URL from '../../config/index';

const instance = axios.create({
  baseURL: BASE_URL,
  timeout: 5000,
  headers: {}
});

instance.interceptors.request.use(config => {
  NProgress.start();
  return config;
}, error => {
  NProgress.done();
  return Promise.reject(error);
});

instance.interceptors.response.use(response => {
  NProgress.done();
  return response;
}, error => {
  NProgress.done();
  return Promise.reject(error);
});

const get = async (url, params) => {
  const { data } = await instance.get(url, params);
  return data;
};
const post = async (url, params) => {
  const { data } = await instance.post(url, params);
  return data;
};
const setToken = () => {
  instance.defaults.headers.common['token'] = '123';
};

export { get, post, setToken };

Plugin myPlugin.js

Ce plugin mixe dans Vue les méthodes $get, $post, etc., via un mixin global.

import { get, post, setToken } from '../utils/request';

export default {
  install(Vue) {
    Vue.mixin({
      methods: {
        $get(url, params) { return get(url, params); },
        $post(url, params) { return post(url, params); },
        $setToken() { setToken(); },
        $msg_s(message, duration = 3000) {
          this.$message({ showClose: true, message, type: 'success', duration });
        },
        $msg_w(message, duration = 3000) {
          this.$message({ showClose: true, message, type: 'warning', duration });
        },
        $msg_e(message, duration = 3000) {
          this.$message({ showClose: true, message, type: 'error', duration });
        },
        $con_f(message) {
          return this.$confirm(message)
            .then(() => true)
            .catch(() => {});
        }
      }
    });
  }
};

Composant registerView.vue

Dans la page d'inscritpion, lors de la soumission du formulaire, on appelle l'endpoint /user/register via le proxy (attention : le préfixe /api est utilisé pour le proxy, pas pour la route réelle).

submitForm(formName) {
  this.$refs[formName].validate(async (valid) => {
    if (valid) {
      const res = await this.$post('/api/user/register', this.loginForm);
      // this.$router.push('/login');
    } else {
      return false;
    }
  });
}

Visualisation des utilisateurs enregistrés dans MongoDB

Ouvrir MongoDB pour voir les données

Exemple d'utilisateurs enregistrés dans la base de données

Étiquettes: Node.js Express MongoDB Mongoose Vue.js

Publié le 25 juin à 18h48