2013-02-19 8 views
5

Meine Node.js-Anwendung bietet WebSockets und RESTful Schnittstelle. Ich schrieb einen kleinen Ersatz für Backbone.synch, um mit Socket.IO als Transport zu verwenden.WebSockets plus RESTful-Schnittstelle, wie schreibt man DRY-Code in Node.js?

TROCKEN Problem: Rückrufe, die auf Client-Ereignis ausgeführt werden, enthält fast dieselbe Logik wie Rückrufe für RESTul-Pfade. Ein Beispiel Mapping zwischen Ereignissen und vom Kunden ausgesandten Daten und die entsprechenden Aktion:

+----------------+---------------------------------+--------------------+ 
| 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 | 
+----------------+---------------------------------+--------------------+ 

Beispiel (99% des duplizierten Logik/code):

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); 
    }); 
}); 

Da ich spiele mit Knoten. JS und Event-Programmierung (und JavaScript) für ein paar Tage, ich bin auf der Suche nach einem guten Rat, wie ein "Controller", wie ein Allzweck-Objekt, das den duplizierten Code leicht handhaben kann. Vielen Dank.

Antwort

1

Wenn Sie die Logik dieser beiden Funktionen wirklich mischen möchten, muss die Art und Weise, wie Ihr clientseitiger Code die Argumente an Ihre socket.on Callback-Funktion übergibt, geändert werden. Sie können es mit der wie folgt aufgebaut aktuellen Ansatz:

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); 
    } 

    }); 

} 

Aber wie Sie sehen können, irgendwann werden Sie noch die Logik wiederholen, die Sie versuchen zu vermeiden. Wenn jedoch Ihr socket Client-Code, der das Ereignis in einem Objekt mit einer "ID" -Eigenschaft an das erste Argument übergeben und ein Objekt mit einer send-Funktion für das zweite Argument übergeben wurde, könnten Sie es auf Folgendes reduzieren:

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); 

    }); 

} 

In diesem Fall müssten Sie jedoch den Code auf Ihrer Server-Seite ändern, um die Pseudo-Sendemethode zu verarbeiten (und Sie müssen diese an erster Stelle definieren, wo der Client darauf zugreifen kann). . Dies schränkt auch stark ein, was Sie in Ihren Callbacks tun können, da jede Funktion, die Sie für ein tatsächliches Request/Response-Objekt aufrufen möchten, in Ihrem Socket-Client-Code nachgeahmt werden muss. Dies verwirrt meiner Meinung nach die Lesbarkeit und Erweiterbarkeit Ihres Codes, aber es kann sicherlich erreicht werden.

+0

Während ich Ihre Bemühungen zu schätzen weiß, muss ich sagen, dass ich mit Ihrer Antwort nicht einverstanden bin. Ich weiß, welche Module sind, aber Ihre Lösung verschiebt einfach beide Rückrufe in einem separaten Modul. Etwas zu tun, um sicher zu sein, aber meine Frage war über die Logik der Kombination von ihnen (mit Problemen im Zusammenhang mit Parametern). Trotzdem danke! – Polmonino

+0

Ich habe meine Antwort aktualisiert, um zu zeigen, dass es mit Ihrer aktuellen Einrichtung keine Möglichkeit gibt, das Problem der logischen Duplizierung zu umgehen. Wenn Sie jedoch Ihren Clientcode angepasst haben, der das Socket-Ereignis ausgibt, um ein Objekt mit ähnlichen Funktionen/Eigenschaften an das Objekt app.get() zu übergeben (Request- und Response-Objekte), können Sie die Codewiederholung reduzieren. Meiner Meinung nach ist dies jedoch eine schlechte Übung, da Sie die Funktionen, die Sie mit dieser Funktion ausführen können, wirklich einschränken (ohne komplexeren Code hinzuzufügen, der für Ihre clientseitigen Socket-Informationen sichtbar ist). – Default