A
A
alex4answ2020-09-02 17:01:45
Express.js
alex4answ, 2020-09-02 17:01:45

Service - Repository approach in express?

Good evening, I use the approach with layers - Service, Repository (I don’t know how such an organization is called correctly)

The bottom line is that the route handler should not be a big sheet with calls to the database and so on, but be simple and use the services / repositories API:

router

const router = express.Router();

router.get('/', async (req, res) => {
  const posts = await PostService.getAll(req.query.page);
  res.json({
    count: posts.count,
    results: posts.rows,
  });
});

router.post('/', async (req, res) => {
  const post = await PostService.create(req.body);
  res.json(post);
});
// и тд

post service

Очень примерно так, Сервис работает с репозиторием, в случае если тот выбросил исключение - откатывает транзакцию.

const PostRepository = require('./PostRepository');

class PostService {
  async static getAll(page) {
    const limit  = 15;
    const offset = page > 0? +page : 0;
    return await PostRepository.getAll(limit, offset);
  }

  async static create(post) {
    const transaction = db.beginTransaction();
    try {
      const newPost = await PostRepository.create(post);
       // какие-то еще действия с newPost
       transaction.commit();
    } catch(err) {
      transaction.rollBack();
      return false;
    }
    return newPost;
  }
}

module.exports = PostService;

PostRepository

Очень примерно, это слой для работы с бд, в случае ошибки выбрасывает исключение.
const Post = require('./PostModel');

class PostRepository {
  static getAll(limit, offset) {
    return Post.findAndCountAll({ limit, offset });
  }

  static create(body) {
    let result = Post.create({ title: body.title, ...});
    if(!result) {
      throw new Error('ошибка создания записи');
    } else {
      return result;
    }
  }
}

module.exports = PostRepository;


The router calls the service, it starts the transaction, and works with the repository, if the repository throws an exception, the service rolls back the transaction, if not, it successfully completes it, returning the data to the router.

Questions:
1. Is this approach redundant? (I haven’t seen this on express projects, usually everyone either creates a router or creates a maximum service)

I’m used to encapsulating methods in a class, for example PostService, but to be honest in js I don’t really understand why I do this (because I don’t use this, not I create an object, all methods are static), it’s quite possible to get by with module.exports, it’s rather just a habit and “it’s necessary”.

2. Is my encapsulation of static methods in a class redundant?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
E
Eugene, 2020-09-02
@Nc_Soft

Your Post.create({ title: body.title, ...}) will throw an exception (as I understand sequelize is used), the if(!result) check seems redundant to me.
I also aggregate static functions into a class, so you don’t need to write a bunch of module.exports. It’s
more convenient to do transactions with a callback, so you don’t need to write rollback and commit.
Taking into account all of the above, it turns out that PostRepository is not needed, the model can handle this.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question