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

0.3.2 • Public • Published

Netero

npm version Circle CI codecov License: MIT

Typescript agnostic dependency injection framework

Table of Contents

Motivation

Inspired by the PHP framework Symfony and its dependency injection by file, this library wants to provide a framework agnostic way to implement inversion of control in your project.

By using this library, your code will never be changed to add decorators or something else to implement a dependency injection. All dependencies will be written in an external configuration file, making things easier to change.

⚠️ Be careful, this library is not type-safe yet but it will be, it is planned 😉

Requirements

Typescript target >= es5, however for a better usage, it is recommended to set the target to >= es6

Install

$ npm install netero

Getting started

Example

  • Create your Typescript classes:
// folder/Mailer.ts
export class Mailer {
  private transport: string;

  constructor(transport: string) {
    this.transport = transport;
  }

  getTransport() {
    return this.transport;
  }
}
// NewsletterManager.ts
import { Mailer } from './folder/Mailer';

export class NewsletterManager {
  private mailer: Mailer;

  constructor(mailer: Mailer) {
    this.mailer = mailer;
  }

  getMailerTransport() {
    return this.mailer.getTransport();
  }
}
  • Configure your dependencies:
# config.yaml
parameters:
  mailer.transport: sendmail

services:
  mailer:
    path: "folder/Mailer"
    arguments:
      - "%mailer.transport%"
  newsletterManager:
    path: "NewsletterManager"
    arguments:
      - "@mailer"
  • Build your container:
// index.ts
import { Container, YamlLoader } from 'netero';

const container = new Container();
container.load(new YamlLoader('./config.yaml'));
container.compile();
const newsletterManager = container.get('@newsletterManager');
const newsletterManager = container.get('@newsletterManager');
console.log(newsletterManager); // NewsletterManager { mailer: Mailer }
console.log(newsletterManager.getMailerTransport()); // sendmail

Options

API

  • parameters: (optional) list of parameters that could be injected into services
  • services: list of your classes or functions you want to declare for your injections
    • path: relative path to your class file
    • arguments: (optional) list of arguments for your class constructor
    • class: (optional) in case of multiple classes in the file, specify the name of the class you want to inject
    • tags: (optional) list of tags to add to the class for grouped injections

Service

You can inject a class as an argument to an another class:

# config.yaml
services:
  paymentApi:
    path: 'path/to/paymentApi'
    arguments: ['@stripeClient']
  stripeClient:
    path: 'path/to/stripeClient'

Multiple classes

You also have an option if you have multiple classes defined in the same file:

// path/to/paymentClients.ts
export class PaypalClient {}
export class StripeClient {}
# config.yaml
services:
  paypalCLient:
    path: 'path/to/paymentClients'
    class: 'PaypalClient'
  stripeClient:
    path: 'path/to/paymentClients'
    class: 'StripeClient'

Parameter

You can inject global parameters defined in your configuration:

# config.yaml
parameters:
  defaultLanguage: 'en-US'

services:
  translator:
    path: 'path/to/translator'
    arguments: ['%defaultLanguage%']

Group classes

If you want to dynamically inject multiple classes as argument without changing the configuration of the parent class, you can use the tags option. All classes with the tag will be automatically injected in the parent class.

// path/to/httpClients.ts
export class HttpClients {
  constructor(clients: HttpClient[]) {}
}

// path/to/axiosClient.ts
export class AxiosClient implements HttpClient {}

// path/to/gotClient.ts
export class GotClient implements HttpClient {}
# config.yaml
services:
  httpClients:
    path: 'path/to/httpClients'
    arguments: ['#http-client']
  axiosClient:
    path: 'path/to/axiosClient'
    tags: ['http-client']
  gotClient:
    path: 'path/to/gotClient'
    tags: ['http-client']

Environment variable

If you to have different values injected by environment, like for production, staging or development, you may need to use them in your parameters.

# config.yaml
parameters:
  databaseUrl: '%env(DB_URL)%'

services:
  databaseClient:
    path: 'path/to/databaseClient'
    arguments: ['%databaseUrl%']

Loaders

You can use different kind of loader files, such as :

  • Yaml
# config.yaml
parameters:
  mailer.transport: sendmail

services:
  mailer:
    path: "folder/Mailer"
    arguments:
      - "%mailer.transport%"
  newsletterManager:
    path: "NewsletterManager"
    arguments:
      - "@mailer"
  • Json
// config.json
{
  "parameters": {
    "mailer.transport": "sendmail"
  },
  "services": {
    "mailer": {
      "path": "folder/Mailer",
      "arguments": [
        "%mailer.transport%"
      ],
    },
    "newsletterManager": {
      "path": "NewsletterManager",
      "arguments": [
        "@mailer"
      ],
    }
  }
}
  • Typescript
// config.ts
export default {
  parameters: {
    'mailer.transport': 'sendmail',
  },
  services: {
    mailer: {
      path: 'folder/Mailer',
      arguments: [
        '%mailer.transport%',
      ],
    },
    newsletterManager: {
      path: 'NewsletterManager',
      arguments: [
        '@mailer',
      ],
    }
  },
};

Multiple files

Load configuration files from different sources, whatever the order of service declarations:

// index.ts
import { Container, YamlLoader } from 'netero';

const container = new Container();
container.load(new YamlLoader('./config-file-1.yaml'));
container.load(new YamlLoader('./config-file-2.yaml'));
container.compile();

License

Licensed under MIT.

Package Sidebar

Install

npm i netero

Weekly Downloads

0

Version

0.3.2

License

MIT

Unpacked Size

60.9 kB

Total Files

65

Last publish

Collaborators

  • kindergouello