I've recently built a few isomporphic/univeral projects using the React-Redux-Express-Mongoose stack.
In my mongoose models is contained a lot of business-logic. As a very basic example (excuse my ES6):
import mongoose, {Schema} from 'mongoose';
const UserSchema = new Schema({
name: String,
password: String,
role: String
});
UserSchema.methods.canDoSomeBusinessLogic = function(){
return this.name === 'Jeff';
};
UserSchema.methods.isAdmin = function(){
return this.role === 'admin';
};
This is all great on the server, however when these models are hydrated in the browser as plain JSON objects, I then have to re-implement this same business logic in some React component or Redux reducer, which doesn't feel very clean to me. I'm wondering how best to approach this.
From reading around Mongoose, there seems to be limited browser support, mostly just for document validation. I suppose my main options are:
Move all the business logic into some "normal" JS classes, and instantiate those all over the place. For example:
# JS Class definition - classes/user.js export default class User { constructor(data = {}){ Object.assign(this,data); } canDoSomeBusinessLogic(){ return this.name === 'Jeff'; }; isAdmin(){ return this.role === 'admin'; } } # Server - api/controllers/user.js import UserClass from User.findById(1,function(err,user){ let user = new UserClass(user.toJSON(); }); # Client - reducers/User.js export default function authReducer(state = null, action) { switch (action.type) { case GET_USER: return new UserClass(action.response.data); } } # Client - containers/Page.jsx import {connect} from 'react-redux'; @connect(state => ({user: state.user})) export default class Page extends React.Component { render(){ if(this.props.user.isAdmin()){ // Some admin } } }
Move all the business logic into a some static helper functions. I won't write out the whole example again, but essentially:
# helpers/user.js export function isAdmin(user){ return user.role === 'admin'; }
I suppose the difference between the above 2 is just personal preference. But does anyone have any other thoughts about isomorphic apps and data modelling? Or have seen any open-source example of people solving this problem.
As an extension to the above, what about an isomorphic save() function e.g. User.save(). So if called on the client it could do a POST to the relevant API endpoint, and if run on the server it would call the Mongoose save() function.