0.3.5 • Published 2 years ago

@rocketmakers/ioc v0.3.5

Weekly downloads
-
License
ISC
Repository
-
Last release
2 years ago

Rocketmakers IoC

Introduction

This package provides helper methods for inversify (https://inversify.io/) to: 1. simplify registering classes, functions and constants. 1. simplify resolving classes, functions and constants. 1. provide function curry facilities - resolving function parameters from the IoC container.

Typing the Container

You should first create a type that describes your Container items, then create a containerRegister to help you to register those types.

Application

service/admin.ts

export class AdminService {
  doSomething(value: number) {
    return Math.round(value);
  }
}

controller/admin.ts

import { AdminService } from '../service/admin';

export class AdminController {
  constructor(private adminService: AdminService) {}
}

service/external-api.ts

import { fetchUserData, IUser } from './external';

// NOTE: we want the apiKey param to be provided (curried) from the container - so we never need to explicitly pass this when consuming this function!
export function getExternalUserData(apiKey: string, id: number): IUser {
  return fetchUserData(apiKey, id);
}

ioc/types.ts

import { Curried1, Curried2 } from '@rocketmakers/ioc';

// Application Types
import type { AdminController } from '../controller/admin';
import type { AdminService } from '../service/admin';
import type { getExternalUserData } from '../service/external-api';

/** Define the types registered within the container */
export type ControllerContainerTypes = {
  id: number;
  apiKey: string;
  adminService: AdminService;
  adminController: AdminController;
  getExternalUserData: typeof getExternalUserData;
  getExternalUserData1: Curried1<typeof getExternalUserData>;
  getExternalUserData2: Curried2<typeof getExternalUserData>;
};

Registration (IoC Container Modules)

Building the container

ioc/register.ts

import { IContainer, register } from '@rocketmakers/ioc';

import { AdminController } from '../controller/admin';
import { AdminService } from '../service/admin';
import { getExternalUserData } from '../service/external-api';
import { ControllerContainerTypes } from './types';

export function makeContainer(): IContainer<ControllerContainerTypes> {
  // Register all the keys of the 'ControllerContainerTypes'
  return register<ControllerContainerTypes>({
    id: b => b.constant(31313),
    apiKey: b => b.constant('xyz...'),
    adminService: b => b.class(AdminService, []),
    adminController: b => b.class(AdminController, ['adminService']),
    getExternalUserData: b => b.function(getExternalUserData),
    getExternalUserData1: b => b.functionCurry(getExternalUserData, ['apiKey']),
    getExternalUserData2: b => b.functionCurry(getExternalUserData, ['apiKey', 'id']),
  });
}

ioc/register-with-prefix.ts

import { registerWithPrefix } from '@rocketmakers/ioc';

import { AdminController } from '../controller/admin';
import { AdminService } from '../service/admin';
import { getExternalUserData } from '../service/external-api';
import { ControllerContainerTypes } from './types';

export function makeContainerPrefixed<TPrefix extends string>(prefix: TPrefix, id: number, apiKey: string) {
  // Register all the keys of the 'ControllerContainerTypes'
  return registerWithPrefix<TPrefix, ControllerContainerTypes>('none', prefix, {
    id: b => b.constant(id),
    apiKey: b => b.constant(apiKey),
    adminService: b => b.class(AdminService, []),
    adminController: b => b.class(AdminController, ['adminService']),
    getExternalUserData: b => b.function(getExternalUserData),
    getExternalUserData1: b => b.functionCurry(getExternalUserData, ['apiKey']),
    getExternalUserData2: b => b.functionCurry(getExternalUserData, ['apiKey', 'id']),
  });
}

const v1 = makeContainerPrefixed('this-', 31313, 'xyz...');
v1.get('this-id');
v1.get('this-apiKey');
v1.get('this-adminService');
v1.get('this-adminController');
v1.get('this-getExternalUserData');
v1.get('this-getExternalUserData1');
v1.get('this-getExternalUserData2');

const v2 = makeContainerPrefixed('that-', 13131, 'abc...');
v2.get('that-id');
v2.get('that-apiKey');
v2.get('that-adminService');
v2.get('that-adminController');
v2.get('that-getExternalUserData');
v2.get('that-getExternalUserData1');
v2.get('that-getExternalUserData2');

Resolving with the container

import { makeContainer } from './ioc/register';

export function boot() {
  // Register the container
  const container = makeContainer();

  //  getExternalUserData1 has type "(id: number): IUser" as we curried out the apiKey param
  const getExternalUserData1 = container.get('getExternalUserData1');
  const userData = getExternalUserData1(23);
  return userData;
}

boot();

Registration (Legacy)

Building the container

ioc/register.ts

import { containerFactory, containerRegister, containerRegisterFunctionResolver } from '@rocketmakers/ioc';

// Application Types
import { AdminController } from '../controller/admin';
import { AdminService } from '../service/admin';
import { getExternalUserData } from '../service/external-api';
import { ControllerContainerTypes } from './types';

/** @deprecated LEGACY: Create register helper  */
export const register = containerRegister<ControllerContainerTypes>();
/** @deprecated LEGACY: Create function resolver  */
export const functionResolver = containerRegisterFunctionResolver<ControllerContainerTypes>();
/** @deprecated LEGACY: Create register container  */
export const container = containerFactory<ControllerContainerTypes>();

export function registerIoC(): void {
  // Register all the keys of the 'ControllerContainerTypes'
  register.constant('id', 31313);
  register.constant('apiKey', 'xyz...');
  register.class('adminService', AdminService).construct([]).inSingletonScope();
  register.class('adminController', AdminController).construct(['adminService']).inSingletonScope();
  register.function('getExternalUserData', getExternalUserData);
  register.function('getExternalUserData1', functionResolver.curry1(getExternalUserData, 'apiKey'));
  register.function('getExternalUserData2', functionResolver.curry2(getExternalUserData, 'apiKey', 'id'));
}

Resolving with the container

import { container, registerIoC } from './ioc/register-legacy';

export function boot() {
  // Register the container
  registerIoC();

  //  getExternalUserData has type "(id: number): IUser" as we curried out the apiKey param
  const getExternalUserData1 = container.get('getExternalUserData1');

  const userData = getExternalUserData1(23);
  return userData;
}

boot();