Node.js & express - глобальные модули и лучшие практики для структуры приложения

Я создаю приложение node.js, которое является REST api, используя экспресс и мангуст для моего mongodb. Теперь у меня есть конечные точки CRUD, но мне было просто интересно две вещи.

  • Как я могу расширить этот путь маршрутов, в частности, как мне делиться модулями между маршрутами. Я хочу, чтобы каждый из моих маршрутов попал в новый файл, но, очевидно, только одно соединение с базой данных, как вы можете видеть, я включил mongoose в верхней части people.js.

  • Должен ли я записывать схему модели 3 раза в моих people.js? Первая схема определяет модель, затем я перечисляю все vars в функциях createPerson и updatePerson. Это похоже на то, как я сделал php/mysql CRUD обратно в день LOL. Для функции обновления я попытался написать цикл, чтобы перебрать "p", чтобы автоматически определять, какие поля обновлять, но безрезультатно. Любые советы или предложения были бы замечательными.

Кроме того, мне бы хотелось, чтобы любые мнения о приложении в целом были новы для node, трудно понять, что то, как вы делаете что-то, является самой эффективной или "лучшей" практикой. Спасибо!

app.js

// Node Modules
var express     = require('express');
    app         = express();
    app.port    = 3000;



// Routes
var people      = require('./routes/people');

/*
var locations   = require('./routes/locations');
var menus       = require('./routes/menus');
var products    = require('./routes/products');
*/


// Node Configure
app.configure(function(){
  app.use(express.bodyParser());
  app.use(app.router);
});



// Start the server on port 3000
app.listen(app.port);



/*********
ENDPOINTS 
*********/

// People
app.get('/people', people.allPeople); // Return all people
app.post('/people', people.createPerson); // Create A Person
app.get('/people/:id', people.personById); // Return person by id
app.put('/people/:id', people.updatePerson); // Update a person by id
app.delete('/people/:id', people.deletePerson); // Delete a person by id

console.log('Server started on port ' + app.port);

people.js

//Database
var mongoose = require("mongoose");
mongoose.connect('mongodb://Shans-MacBook-Pro.local/lantern/');


// Schema
var Schema = mongoose.Schema;  
var Person = new Schema({  
    first_name: String,
    last_name: String,
    address: {
        unit: Number,
        address: String,
        zipcode: String,
        city: String,
        region: String,
        country: String
    },
    image: String, 
    job_title: String,
    created_at: { type: Date, default: Date.now },
    active_until: { type: Date, default: null },
    hourly_wage: Number,
    store_id: Number, // Inheirit store info
    employee_number: Number

});
var PersonModel = mongoose.model('Person', Person);  


// Return all people
exports.allPeople = function(req, res){
    return PersonModel.find(function (err, person) {
      if (!err) {
        return res.send(person);
      } else {
        return res.send(err);
      }
    });
}


// Create A Person
exports.createPerson = function(req, res){
    var person = new PersonModel({
        first_name: req.body.first_name,
        last_name: req.body.last_name,
        address: {
            unit: req.body.address.unit,
            address: req.body.address.address,
            zipcode: req.body.address.zipcode,
            city: req.body.address.city,
            region: req.body.address.region,
            country: req.body.address.country
        },
        image: req.body.image,
        job_title: req.body.job_title,
        hourly_wage: req.body.hourly_wage,
        store_id: req.body.location,
        employee_number: req.body.employee_number
    });

    person.save(function (err) {
        if (!err) {
            return res.send(person);
        } else {
            console.log(err);
            return res.send(404, { error: "Person was not created." });
        }
    });

    return res.send(person);
}


// Return person by id
exports.personById = function (req, res){
  return PersonModel.findById(req.params.id, function (err, person) {
    if (!err) {
        return res.send(person);
    } else {
        console.log(err);
        return res.send(404, { error: "That person doesn't exist." });
    }
  });
}


// Delete a person by id
exports.deletePerson = function (req, res){
  return PersonModel.findById(req.params.id, function (err, person) {
    return person.remove(function (err) {
      if (!err) {
          return res.send(person.id + " deleted");
      } else {
          console.log(err);
          return res.send(404, { error: "Person was not deleted." });
      }
    });
  });
}



// Update a person by id
exports.updatePerson = function(req, res){
    return PersonModel.findById(req.params.id, function(err, p){        
        if(!p){
            return res.send(err)
        } else {
            p.first_name = req.body.first_name;
            p.last_name = req.body.last_name;
            p.address.unit = req.body.address.unit;
            p.address.address = req.body.address.address;
            p.address.zipcode = req.body.address.zipcode;
            p.address.city = req.body.address.city;
            p.address.region = req.body.address.region;
            p.address.country = req.body.address.country;
            p.image = req.body.image;
            p.job_title = req.body.job_title;
            p.hourly_wage = req.body.hourly_wage;
            p.store_id = req.body.location;
            p.employee_number = req.body.employee_number;

            p.save(function(err){
                if(!err){
                    return res.send(p);
                } else {
                    console.log(err);
                    return res.send(404, { error: "Person was not updated." });
                }
            });
        }
    });
}

Ответы

Ответ 1

Я использовал другой подход. Не сказать, что это лучшее, но позвольте мне объяснить.

  • Каждая схема (и модель) находится в собственном файле (модуле)
  • Каждая группа маршрутов для определенного ресурса REST находится в собственном файле (модуле)
  • Каждому модулю маршрута просто require нужна модель Mongoose (всего 1)
  • Основной файл (точка входа приложения) всего require всех модулей маршрута для их регистрации.
  • Монгольское соединение находится в корневом файле и передается как параметр для того, что ему нужно.

У меня есть два подпапки под моим корнем приложения - routes и schemas.

Преимущества такого подхода заключаются в следующем:

  • Вы только пишете схему один раз.
  • Вы не загрязняете свой основной файл приложения регистрацией маршрута для 4-5 маршрутов на ресурс REST (CRUD)
  • Определяется только соединение DB после

Вот как выглядит конкретный файл схемы:

Файл:/schemas/theaterSchema.js

module.exports = function(db) {
        return db.model('Theater', TheaterSchema());
}

function TheaterSchema () {
        var Schema = require('mongoose').Schema;

        return new Schema({
            title: { type: String, required: true },
            description: { type: String, required: true },
            address: { type: String, required: true },
            latitude: { type: Number, required: false },
            longitude: { type: Number, required: false },
            phone: { type: String, required: false }
    });
}

Вот как выглядит набор маршрутов для определенного ресурса:

Файл:/routes/theaters.js

module.exports = function (app, options) {

    var mongoose = options.mongoose;
    var Schema = options.mongoose.Schema;
    var db = options.db;

    var TheaterModel = require('../schemas/theaterSchema')(db);

    app.get('/api/theaters', function (req, res) {
            var qSkip = req.query.skip;
            var qTake = req.query.take;
            var qSort = req.query.sort;
            var qFilter = req.query.filter;
            return TheaterModel.find().sort(qSort).skip(qSkip).limit(qTake)
            .exec(function (err, theaters) {
                    // more code
            });
    });

    app.post('/api/theaters', function (req, res) {
      var theater;

      theater.save(function (err) {
        // more code
      });
      return res.send(theater);
    });

    app.get('/api/theaters/:id', function (req, res) {
      return TheaterModel.findById(req.params.id, function (err, theater) {
        // more code
      });
    });

    app.put('/api/theaters/:id', function (req, res) {
      return TheaterModel.findById(req.params.id, function (err, theater) {
        // more code
      });
    });

    app.delete('/api/theaters/:id', function (req, res) {
      return TheaterModel.findById(req.params.id, function (err, theater) {
        return theater.remove(function (err) {
          // more code
        });
      });
    });
};

И вот файл корневого приложения, который инициализировал соединение и регистрирует все маршруты:

Файл: app.js

var application_root = __dirname,
        express = require('express'),
        path = require('path'),
        mongoose = require('mongoose'),
        http = require('http');

var app = express();

var dbProduction = mongoose.createConnection('mongodb://here_insert_the_mongo_connection_string');

app.configure(function () {
        app.use(express.bodyParser());
        app.use(express.methodOverride());
        app.use(app.router);
        app.use(express.static(path.join(application_root, "public")));
        app.use('/images/tmb', express.static(path.join(application_root, "images/tmb")));
        app.use('/images/plays', express.static(path.join(application_root, "images/plays")));
        app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.get('/api', function (req, res) {
        res.send('API is running');
});

var theatersApi = require('./routes/theaters')(app, { 'mongoose': mongoose, 'db': dbProduction });
// more code

app.listen(4242);

Надеюсь, это было полезно.

Ответ 2

Я нашел сообщение StackOverflow очень полезным:

Структура файла проекта Mongoose и NodeJS

Трюк заключается в том, чтобы поместить вашу схему в каталог models. Затем в любом маршруте вы можете require('../models').whatever.

Кроме того, я обычно запускаю db-соединение mongoose в app.js и запускаю только сервер Express после завершения соединения:

mongoose.connect('mongodb://localhost/whateverdb')
mongoose.connection.on('error', function(err) {
  console.log("Error while connecting to MongoDB:  " + err);
  process.exit();
});
mongoose.connection.on('connected', function(err) {
  console.log('mongoose is now connected');
  // start app here
  http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
  });

});