binder
TypeScript icon, indicating that this package has built-in type declarations

2.0.5 • Public • Published

Binder

npm version Build Status coverage Package size Known Vulnerabilities

Simple, yet powerful IoC container and service locator for both, the browser and node. Inspired by Illuminate/Container.

Installation

NPM users:

> npm i binder

YARN users:

> yarn add binder

Usage

While we miss a documentation website for this, you can simply check out the following example.

You can also refer to the test cases and the Container API, which is pretty easy

import { Container } from 'binder'
const container = new Container()

class User {
  constructor({ email, password }) {
    this.email = email.toLowerCase().trim()
    this.password = password.trim()
  }
}

/**
 * This class is bound to the container using a factory function
 * that passes a Connection object as its dependency 
 */
class UserRepository {
  constructor(connection) {
    this.db = connection;
  }

  async create({ email, password }) {
    const user = new User({ email, password })
    await UserRepository.validate(user)

    return this.db.insert(user.toJSON())
  }

  async findById(id) {
    const user = await this.db.select('email', 'password').where({ id })

    if (user) return new User(user)

    return null
  }

  static validate({ email, password }) {
    if (!email) throw new TypeError('Email is required')
    if (!password) throw new TypeError('Password is required')
  }
}

/**
 * This class is directly bound to the container, which injects itself
 * as the first param whenever the class is resolved. 
 */
class UserController {
  constructor(container) {
    // UserRepository is resolved by reference, so we have intellisense support!
    this.userRepo = containger.get(UserRepository)
  }

  // Simple handler for an express route, using the controller's instance
  async createUser(req, res) {
    const { email, password } = req.body;
    try {
      const user = await this.userRepo.create({ email, password })
      res.send({ user })
    } catch (err) {
      const { stack, ...error } = err
      res.status(400).send({ error })
    }
  }

  async getUser(req, res) {
    const { id } = req.body;
    try {
      const user = await this.userRepo.findById(id)
      if (user === null) {
        throw Object.assign(new Error(`User ${id} not found`), { status: 404 })
      }

      res.send({ user })
    } catch (err) {
      const { stack, status = 500, ...error } = err
      res.status(status).send({ error })
    }
  }
}

/**
 * We want to share the same instance of UserRepository, 
 * hence we bind it as a singleton, otherwise we'd use .bind()
 * 
 * We can provide a factory function as the second param
 * to resolve its dependencies (also from the container).
 */
container.singleton(UserRepository, (container) => {
  const connection = container.get('db').table('users')
  return new UserRepository(connection)
})

/**
 * Because UserController depends directly on the Container,
 * we can simply pass its class to either .get() or .make() methods.
 * The Container will know how to resolve and return an instance of it
 */
container.singleton(UserController)

// Example usage with an Express application (you may want to use a middleware instead)
app.post('/users', (req, res) => container.get(UserController).createUser(req, res))
app.post('/users/:id', (req, res) => container.get(UserController).getUser(req, res))

Versions

Current Tags

  • Version
    Downloads (Last 7 Days)
    • Tag
  • 2.0.5
    1
    • latest

Version History

Package Sidebar

Install

npm i binder

Weekly Downloads

1

Version

2.0.5

License

MIT

Unpacked Size

45.6 kB

Total Files

14

Last publish

Collaborators

  • frondor