DEV Community

Cover image for Decouple your express applications using the amazing express-decorator-router
Marcos Henrique
Marcos Henrique

Posted on • Updated on

Decouple your express applications using the amazing express-decorator-router

Sick of that bunch of route files for our beloved express?

Looking for a way to use middleware and inject dependencies succinctly and clearly?

Looking for that package that will help you test your projects by decoupling intelligently?

Your problems end here and now, I present to you the package whose premise doesn't need transpilation, and can be used with koa, express or any package following express API.

You who want to escape from transpilation and are a hipster who likes the good old vanilla JS.

This package is intended to avoid unnecessary creation of two files where one contains the route definition and the other has the function that handles the route request/response processes, leaving simpler maintenance and more scalable code.

With only 32kb minified (source: bundlephobia), being able to inject the dependencies in a "manual" way or with the extremely tough tool awilix

Cool dude! But, how do I use it in practice?

Without Awilix

First let's talk about the root mode 👨‍💻👩‍💻

Registering your controllers with that mastery 🧐

The useControllers method uses two parameters, the first is the routing mechanism and the second is a glob expression that has the responsibility of finding all controllers that match the pattern of the expression.

server.js

const express = require('express')
const { resolve } = require('path')
const { useControllers } = require('express-decorator-router')

const app = express()
const router = express.Router()

app.use(express.json())

app.use('/api', useControllers({
    controllerExpression: `${resolve('src')}/**/controller.js`,
    router
}))

app.listen(3000, () => console.log('🔮 magic happens on port 3000'))
Enter fullscreen mode Exit fullscreen mode

The controller function returns a high order function where the decorator definition is made by associating a decorator with a class method as seen in the example above.

controller.js

const {
    get,
    put,
    del,
    post,
    controller
} = require('express-decorator-router')

class UserController {

    getUsers(ctx) {
        return ctx.response.json({ message: 'get all users' })
    }

    postUser(ctx) {
        const { user } = ctx.response.body
        return ctx.response.json({ message: `create user with name ${user}` })
    }

    putUser(ctx) {
        const { id } = ctx.request.params
        const { user } = ctx.request.body
        return ctx.response.json({ message: `update user with name ${user} with id ${id}` })
    }

    deleteUser(ctx) {
        const { id } = ctx.request.params
        return ctx.response.json({ message: `delete user with id ${id}` })
    }
}

module.exports = controller('/users')(UserController, {
    getUsers: get(),
    postUser: post(),
    putUser: put('/:id'),
    deleteUser: del('/:id')
})
Enter fullscreen mode Exit fullscreen mode

With Awilix

Awilix has a pretty simple API (but with many possible ways to invoke it). At minimum, you need to do 3 things:

  • Create a container
  • Register some modules in it
  • Resolve and use!

To make your life easier it already comes as an internal dependency so you will not need to install the same.

Now let's take a look at how it becomes even simpler to decouple your application with it.

Registering your controllers is even easier 🤩

server.js

const express = require('express')
const { resolve } = require('path')
const userService = require('./users/service')
const { useAwilixControllers, awilix, scopePerRequest } = require('express-decorator-router')

const app = express()
const router = express.Router()
const container = awilix.createContainer()

container.register({
    userService: awilix.asValue(userService).scoped()
})

app.use(express.json())
app.use(scopePerRequest(container))

app.use('/api/user', useAwilixControllers({
    controllerExpression: `${resolve('src')}/**/controller.js`,
    router
}))

app.listen(3200, () => console.log('🔮 magic happens on port 3200'))
Enter fullscreen mode Exit fullscreen mode

controller.js

const {get, controller, inject } = require('express-decorator-router')

const getUsers = (req, res) => {
    const { userService } = req
    return res.json(userService.getUsers())
}

module.exports = controller('/users', inject('userService'))({
    getUsers
}, {
    getUsers: get()
})
Enter fullscreen mode Exit fullscreen mode

Now you can be creative and discover highly scalable, testable and decoupled applications.

This package can be found on awesome-express list on middleware category

GitHub logo rajikaimal / awesome-express

:octocat: A curated list of awesome express.js resources

You can go even deeper into the repository documentation:

GitHub logo LucasMendesl / express-decorator-router

⚡ use decorators in a simple way without transpiling javascript code

express-decorator-router

NPM

use decorators in a simple way without transpiling javascript code

Why?

Have you ever considered using the decorators feature using vanilla javascript to automate the creation of express routes?

The express-decorator-router package came to solve this problem in a simple and didactic way, without the need for transpiling processes in your code.

This package is intended to avoid unnecessary creation of two files where one file contains the route definition and the other file has the function that handles the route request / response process, leaving simpler maintenance and more scalable code.

New in 0.2.0

Now, you can work with dependency injection.

Usage

Let's take a short example using the decorators on a prototype-based controller.

const {
  get,
  controller
} = require ('express-decorator-router')
const controllerFactoryDecorator = controller('/users')

class UsersController {
  constructor () {/*...class constructor definition*/}
        
  getUsers (ctx) {
Enter fullscreen mode Exit fullscreen mode

Oldest comments (0)