Reputation: 3466
I am trying to make an scalable RESTful project using Express and Mongoose libraries.
For now, I developed an example in CodeSandbox where I only have an User model, an User repository, an User controller and an User Route. But if I have to repeat all the CRUD operations for more than one model, I guess I have to avoid writing the code again for each model.
This is my current code:
const mongoose = require("mongoose");
const bcrypt = require("mongoose-bcrypt");
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
password: {
type: String,
bcrypt: true
}
});
userSchema.plugin(bcrypt);
module.exports = mongoose.model("User", userSchema);
const User = require("../models/User");
class UserRepository {
constructor(model) {
this.model = model;
}
create(object) {
return this.model.create(object);
}
get() {
return this.model.find().exec();
}
}
module.exports = new UserRepository(User);
const UserRepository = require("../repositories/user");
function createUser(req, res) {
const user = req.body;
UserRepository.create(user)
.then(response => res.json(response))
.catch(err => res.status(500).json(err));
}
function getUsers(req, res) {
UserRepository.get()
.then(response => res.json(response))
.catch(err => res.status(500).json(err));
}
module.exports = { createUser, getUsers };
const express = require("express");
const UserController = require("../controllers/users");
const router = express.Router();
router.get("/", UserController.getUsers);
router.post("/", UserController.createUser);
module.exports = router;
I think I need to "create" an agnostic solution for each model, which are the only stuff is changing.
So I have created a Default Repository with the following code:
class DefaultRepository {
constructor(model) {
this.model = model;
}
create(object) {
return this.model.create(object);
}
get() {
return this.model.find().exec();
}
}
module.exports = DefaultRepository;
Then I added the code in my User repository:
class DefaultRepository {
constructor(model) {
this.model = model;
}
create(object) {
return this.model.create(object);
}
get() {
return this.model.find().exec();
}
}
module.exports = DefaultRepository;
Then I created a Default Controller that would add the logic function to the repositories:
class DefaultController {
constructor(repository) {
console.log(this);
this.repository = repository;
}
create(req, res) {
const user = req.body;
this.repository
.create(user)
.then(response => res.json(response))
.catch(err => res.status(500).json(err));
}
get(req, res) {
this.repository
.get()
.then(response => res.json(response))
.catch(err => res.status(500).json(err));
}
}
module.exports = DefaultController;
And the User Controller:
const UserRepository = require("../repositories/user");
const DefaultController = require("./default");
class UserController extends DefaultController {
// additional logic
}
module.exports = new UserController(UserRepository);
And finally I added this to the User route:
const express = require("express");
const UserController = require("../controllers/users");
const router = express.Router();
router.get("/", UserController.get);
router.post("/", UserController.create);
module.exports = router;
But of course, this does not work as expected. In fact, it does not work at all. I get a TypeError: Cannot read property 'repository' of undefined
. But maybe I am wrong with my whole perspective and this is not a solution for an scalable application or maybe it shouldn't be scalable for this size, in case it is, what am I doing wrong?
This is the non-working Sandbox.
Upvotes: 0
Views: 267
Reputation: 1914
The problem is that you are calling the User.* methods implicitly, which does not bind the 'this' state to the methods, you just have to adapt it or stop calling it implicitly
Look the difference
Before:
router.get("/", UserController.get);
router.post("/", UserController.create);
After:
router.get("/", UserController.get.bind(UserController));
router.post("/", UserController.create.bind(UserController)));
Or you call it like this
router.get("/", (req, res, next) =>
UserController.get(req, res)
)
Upvotes: 2