Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

NodeJS Discussion :

Express 4 : séparation MVC


Sujet :

NodeJS

  1. #1
    Nouveau membre du Club
    Express 4 : séparation MVC
    Bonjour, je tente de me mettre à Node.js à travers le framework Express 4, mais en plus de la découverte d'un nouvel environnement j'ai des lacunes en javascript.

    Il existe un générateur d’applications pour Express qui - s'il propose une base pour l'architecture d'une app - ne propose pas de découpage MVC : il sépare seulement les vues du reste de l'application entreposé dans un dossier "routes". Je cherche donc à désolidariser la logique métier du contrôleur.

    J'y suis presque, mais je bloque sur un point. Voilà où j'en suis pour le fichier dédié aux requêtes :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // models/articles.js
     
    const db = require('../database')
    const getArticle = (req, res, next) => db.one('SELECT * FROM article WHERE id = $1', req.params.id)
      .then(data => {
        res.render('article', data) // -> je cherche à déplacer cette ligne dans le fichier "controllers/article.js"
      })
      .catch(error => {
        next()
      })
    module.exports = { getArticle: getArticle }


    Et mon fichier contrôleur pour les articles :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // controllers/articles.js
     
    const express = require('express')
    const router = express.Router()
    const { getArticle } = require('../models/article')
    router.get('/article/:id([0-9]{1,7})', (req, res, next) => { // ex: '/article/1'
      getArticle(req, res, next)
      // <- c'est ici que je voudrais intégrer res.render(), à la place de la fonction getArticle(), mais je ne sais comment
    })
    module.exports = router


    Merci pour vos éventuelles suggestions.

  2. #2
    Futur Membre du Club
    Salut Olivier, je vais essayer de répondre à ta question.
    Effectivement tu y est presque!

    Voici une piste :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    // models/articles.js
     
    const db = require('../database');
    const getArticle = async (id) => await db.one('SELECT * FROM article WHERE id = $1', id);
    module.exports = { getArticle: getArticle };


    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    // controllers/articles.js
     
    const express = require('express');
    const router = express.Router();
    const { getArticle } = require('../models/article');
     
    router.get('/article/:id([0-9]{1,7})', async (req, res, next) => { // ex: '/article/1'
      const article = await getArticle(req.params.id).catch(err => err);
      if(article instanceof Error) {
        return res.render('error', data);
      }
      res.render('article', data);
    })
    module.exports = router


    J'ai pas tester mais je pense que cela peut te mette sur la piste.

    Je te conseil de check la doc mdn ici pour la definition et utilisation de tes module JS que je n'ai pas modifié pour pas t'embrouiller:
    https://developer.mozilla.org/fr/doc.../Guide/Modules

    et aussi la doc des Promises et async function:
    https://developer.mozilla.org/fr/doc...lobaux/Promise
    https://developer.mozilla.org/fr/doc...async_function

    Redemande si jamais
    Bon courage.

  3. #3
    Nouveau membre du Club
    Un grand merci !
    Alors là... un grand grand merci à toi FazioNico ! Je pense que sans toi je n'y serais pas arrivé. Non seulement tu m'as mis sur la voie mais, au passage, j'ai appris plein de trucs. En m'inspirant de ton code j'ai résolu mon problème. J'avoue que je ne croyais plus trop à une aide sur ce forum car en regardant l'historique du forum node.js je le trouvais assez désertique au final... mais tu es passé par là "et la lumière fut" !

    Je poste ma solution, pour la postérité, mais surtout en gratitude à tous ceux qui donnent de leur temps pour aider les autres sur ce forum :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // controllers/article.js
    'use strict'
     
    const express = require('express')
    const router = express.Router()
    const { getArticle } = require('../models/article')
     
    router.get('/article/:id([0-9]{1,7})', async (req, res, next) => { // @example '/article/1'
      const data = await getArticle(req.params.id)
        .then(data => {
          res.render('article', data) // si des données correspondent à la requête on envoie à la vue "article"
        })
        .catch(error => {
          next() // indispensable si la requête échoue, la demande sera traitée plus loin en erreur 404
        })
    })
     
    module.exports = router

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // models/article.js
    'use strict'
     
    const settings = require('./../settings')
    const db = require('../database')
     
    const getArticle = async (id) => await db.one('SELECT * FROM article WHERE id = $1', id)
        .then(data => {
          data.title = data.name + ' | ' + settings.siteName // un p'tit ajout au passage pour montrer ce qui justifie ici un then/catch, ici pour la balise title, ce pourrait être encore le traitement d'une date au bon format
          return data
        })
        .catch(error => { // cette partie n'est utile que si l'on cherche à traiter l'erreur
          console.log(error)
          return data
        })
     
    module.exports = {getArticle : getArticle}


    Bien entendu s'il existe une solution plus concise ou optimisée je suis preneur : pour éviter les 2 return sur le modèle j'ai tenté d'en mettre un seul dans un .finally() mais a priori je n'ai pas compris le concept...