Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Simple and powerful dependency injection container for with strong type checking system. rsdi
offers strong
type-safety support.
Popular dependency injection libraries utilize reflect-metadata to retrieve argument types and use those types to carry out autowiring. Autowiring is an advantageous feature, but it necessitates the wrapping of all your components with decorators.
@injectable()
class Foo {
constructor(@inject("Database") private database?: Database) {}
}
// Notice how in order to allow the use of the empty constructor new Foo(),
// we need to make the parameters optional, e.g. database?: Database.
Why should component Foo be aware that it's injectable?
Your business logic relies on a particular framework, which isn't part of your domain model and is subject to change.
More thoughts in a dedicated article
RSDI
is most effective in complex applications. When the complexity of your application is high, it becomes necessary to
break up huge components into smaller ones to control the complexity. You have components that use other components that
use other components. You have application layers and a layer hierarchy. There is a need to transfer dependencies from
the upper layers to the lower ones.
You like and respect and use Dependency Injection and TDD. You have to use Dependency Injection in order to have proper unit tests. Tests that test only one module - class, component, function, but not integration with nested dependencies.
RSDI
expects (but does not require) that you build all your dependencies into a dependency tree. Let's take a typical
web application as an example. Given that your application is quite large and has many layers:
An application always has an entry point, whether it is a web application or a CLI application. This is the only place where you should configure your dependency injection container. The top level components will then have the lower level components injected.
Let's take a simple web application as an example. We will cut into a small part of the application that registers a new user. A real application will consist of dozens of components. The logic of the components will be much more complicated. This is just a demo. It's up to you to use classes or factory functions for the demonstration, and we'll use both.
const container = new DIContainer()
.add("a", () => "name1")
.add("bar", () => new Bar())
.add("foo", (get) => new Foo(get("a"), get("bar")));
const foo = container.get("foo");
// sample web application components
export function UserController(
userRegistrator: UserRegistrator,
userRepository: UserRepository,
) {
return {
async create(req: Request, res: Response) {
const user = await userRegistrator.register(req.body);
res.send(user);
},
async list(req: Request) {
const users = await userRepository.findAll(req.body);
res.send(users);
},
};
}
export class UserRegistrator {
public constructor(public readonly userRepository: UserRepository) {}
public async register(userData: SignupData) {
// validate and send sign up email
return this.userRepository.saveNewUser(userData);
}
}
export function MyDbProviderUserRepository(db: Knex): UserRepository {
return {
async saveNewUser(userAccountData: SignupData): Promise<void> {
await this.db("insert").insert(userAccountData);
},
};
}
export function buildDbConnection(): Knex {
return knex({
/* db credentials */
});
}
Now we need to configure the dependency injection container before use. Dependencies are declared and not really initiated
until the application really needs them. Your DI container initialization function - configureDI
will include:
import DIContainer from "rsdi";
export type AppDIContainer = ReturnType<typeof configureDI>;
export default function configureDI() {
return new DIContainer()
.add("dbConnection", buildDbConnection())
.add("userRepository", (get) =>
MyDbProviderUserRepository(get("dbConnection")),
)
.add("userRegistrator", (get) => new UserRegistrator(get("userRepository")))
.add("userController", (get) =>
UserController(get("userRepository"), get("userRegistrator")),
);
}
container.get
- return type based on declaration.
All resolvers are resolved only once and their result persists over the life of the container.
Let's map our web application routes to configured controllers
// configure Express router
export default function configureRouter(
app: core.Express,
diContainer: AppDIContainer,
) {
const usersController = diContainer.get("UsersController");
app
.route("/users")
.get(usersController.list.bind(usersController))
.post(usersController.create.bind(usersController));
}
Add configureDI
in the entry point of your application.
// express.ts
const app = express();
const diContainer = configureDI();
configureRouter(app, diContainer);
app.listen(8000, () => {
console.log(`⚡️[server]: Server is running`);
});
The complete web application example can be found here
rsdi
offers strong type-safety due to its native TypeScript support. It leverages TypeScript's type system to provide
compile-time checks and ensure proper injection of dependencies.
FAQs
TypeScript dependency injection container. Strong types without decorators.
The npm package rsdi receives a total of 0 weekly downloads. As such, rsdi popularity was classified as not popular.
We found that rsdi demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.