Data Models and Business Logic in an Isomorphic Application (React / Redux / Express / Mongo)

I recently created several isomorphic / universal projects using the React-Redux-Express-Mongoose stack.

My mongoose models contain a lot of business logic. As a very simple example (sorry 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'; }; 

All this works fine on the server, however, when these models are hydrated in the browser as simple JSON objects, then I have to re-implement the same business logic in some React or Redux components that don’t feel very clear of me. I am wondering how best to approach this.

From reading around Mongoose, there seems to be limited browser support, mainly for checking documents. I believe my main options are:

  • Move all your business logic to some of the β€œnormal” JS classes and create them in 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 business logic to some static helper functions. I will no longer write out the whole example, but essentially:

     # helpers/user.js export function isAdmin(user){ return user.role === 'admin'; } 

I believe that the difference between the above 2 is only a personal preference. But does anyone have any other thoughts on isomorphic applications and data modeling? Or saw some kind of open source example of people who solve this problem.

As an extension to the above, as regards the isomorphic function save (), for example. User.save (). Therefore, if it is called by the client, it can make a POST for the corresponding API endpoint, and if it is running on the server, it will call the Mongoose save () function.

+7
mongoose reactjs redux isomorphic-javascript
source share
1 answer

Spoiler: expect a stubborn response. There is no β€œright” way to do this.

First of all, I want to make the difference between isomorphic and universal so that you know exactly what we are talking about:

Isomorphism is the functional aspect of seamlessly switching between rendering on the client side and on the server side without losing state. Universal is a term used to emphasize the fact that a particular piece of JavaScript code can work in multiple environments.

Is there so much abstraction in a universal app?

Typically, you want a universal application to have the client and server pre-display the application by loading the same code. Although you can run the API from the same server that pre-creates the application, I would prefer a proxy server and run it in a different process.

Let me show you two different React repositories:

The famous Erikras template engine uses its universal application for sharing dependencies around the world and code between a server that pre-displays the page and the client. Although he could, he does not share validation. Validate Poll API Validate Poll Client

Wellyshen does not have an API, but it also shares its dependencies and code, although only between the server and the client. server loads routes, storage, and everything that is done by the client application. That is, to provide isomorphism.

Having said that, it is up to you whether to move the entire scan in one place. I will probably just consider this for complex verification cases, such as email authentication, on which you really can have an assistant. (this was just an example, you already have a validator for email authentication ). In some cases, it would be more convenient to rely on API validation, although this was not the best practice.

Simple checks, such as those in your examples, can easily be done without a redux-form , which I know that there is no direct way to translate it to an API. Instead, you should probably look for an express-validator on it.

One more thing, despite the fact that several very popular React templates will have an API and a client together, I try to work with two different repositories: server-side rendering of React + and API. In the long run, this will lead to cleaner code that is completely independent of the other. organizing-large-react-applications

+1
source share

All Articles