2013-02-19 2 views
5

Приложение My Node.js предоставляет как WebSockets, так и RESTful. Я написал небольшую замену для Backbone.synch для использования с Socket.IO в качестве транспорта.Интерфейс WebSockets plus RESTful, как написать DRY-код в Node.js?

DRY problem: обратные вызовы, выполненные по клиенту, содержат почти ту же логику, что и обратные вызовы для путей RESTul. Пример отображения между событиями и данными, испускаемых клиентом, и соответствующее действие:

+----------------+---------------------------------+--------------------+ 
| event emitted | data emitted     | RESTful URL  | 
+----------------+---------------------------------+--------------------+ 
|  read:users | empty string     | GET /users  | 
|  read:users | id of the model     | GET /users/:id | 
| create:users | full model as JSON    | POST /users  | 
| destroy:users | id of the model     | DELETE /users/:id | 
| update:users | full model as JSON (with id) | PUT /users/:id | 
| patch:users | partial model as JSON (with id) | PUT /users/:id | 
+----------------+---------------------------------+--------------------+ 

Пример (99% дублированного логики/код):

var UserModel = require('./models/user'); // Mongoose model 

// Express path 
app.get('/users/:id?', function (req, res)) { 
    var query = !id ? {} : { _id: id }; 

    UserModel.find(query, function (err, doc) { 
     return err ? res.send(404, null) : res.send(200, doc); 
    }); 
}; 

// SocketIO listening to the read:users event 
socket.on('read:users', function(id, cb) { 
    var query = !id ? {} : { _id: id } 

    UserModel.find(query, function (err, doc) { 
     return err ? cb(err.message, null) : cb(null, doc); 
    }); 
}); 

Потому что я играл с узлом. JS и программирование событий (и JavaScript) в течение нескольких дней, я ищу хороший совет о том, как дизайн «контроллер», как объект общего назначения, который может легко обрабатывать дублированный код. Благодарю.

ответ

1

Если вы действительно хотите смешать логику этих двух функций, то способ, которым ваш код на стороне клиента передает аргументы вашей функции обратного вызова socket.on, должен быть изменен. Вы можете подойти к нему с током настроить так:

var veryGenericCallback = function(p1, p2) { 
    // Note: Not sure what to name the arguments because they are wildly different 
    // in your two different cases. 

    var query = typeof p1 === "object" : {} : { _id: p1 }; 

    UserModel.find(query, function (err, doc) { 
    var result; 

    if (typeof p2 === "function") { 
     return err ? p2(err.message, null) : p2(null, doc); 
    } else { 
     return err ? p2.send(404, null) : p2.send(200, dox); 
    } 

    }); 

} 

Но как вы можете видеть, в какой-то момент вам все равно придется повторять логику, что вы пытаетесь избежать. Однако, если ваш код клиента socket, который испускает событие, переданное в объекте с свойством «id» для первого аргумента, и передал объект с функцией send для вашего второго аргумента, вы можете уменьшить его до этого:

var veryGenericCallback = function(info, action) { 

    var query = info.id ? { _id: info.id } : {}; 

    UserModel.find(query, function (err, doc) { 

    return err ? action.send(404, null) : action.send(200, doc); 

    }); 

} 

Однако в этом случае вам нужно будет изменить код на своей серверной стороне, чтобы обрабатывать все, что есть в вашем методе псевдо-отправки (и вам нужно будет определить, что в первую очередь где-то клиент имеет доступ к нему) , Это также сильно ограничивает то, что вы можете делать в своих обратных вызовах, так как любая функция, которую вы хотите вызвать на реальном объекте Request/Response, должна быть имитирована в коде клиента сокета. На мой взгляд, это путает читабельность и расширяемость вашего кода, но это, безусловно, может быть достигнуто.

+0

Хотя я ценю ваши усилия, я должен сказать, что я не согласен с вашим ответом. Я знаю, какие модули есть, но ваше решение просто перемещает оба обратных вызова в отдельный модуль. Что-то делать наверняка, но мой вопрос касался логики их объединения (с проблемами, связанными с параметрами). В любом случае спасибо! – Polmonino

+0

Я обновил свой ответ, чтобы продемонстрировать, что с вашей текущей настройкой не существует способа обойти проблему дублирования логики. Однако, если вы скорректировали свой клиентский код, который испускает событие сокета для передачи объекту со схожими функциями/свойствами к тому, что получено в вызове app.get() (объекты Request and Response), вы можете уменьшить повторение кода. Однако, по моему личному мнению, я считаю, что это плохая практика, так как вы действительно ограничиваете то, что можете сделать с этой функцией (без добавления более сложного кода, видимого для вашей информации на стороне клиента). – Default

Смежные вопросы