DEV Community

Cover image for Ditsmod - new NodeJS webframework writen in TypeScript
Костя Третяк
Костя Третяк

Posted on • Updated on

Ditsmod - new NodeJS webframework writen in TypeScript

Motivation to create Ditsmod

Before creating Ditsmod, of course, I was looking for: "Are there ready-made solutions for my purposes?".

I believe that the set of the following features is unique at the moment:

  1. The framework is written in TypeScript (and under the hood there is no ExpressJS or Fastify ;).
  2. Modular architecture with decorators.
  3. Has a hierarchical Dependency Injection that allows you to use classes as a search token, rather than their names.
  4. Clearly delineated providers arrays for DI injectors at the application, module, route, or request level.
  5. Built-in support for nested routes, such as /api/posts/:postId/comments/:commentId.
  6. Check for collisions when importing providers. This feature allows you to detect situations where you import two or more modules that export providers with the same token.
  7. Support for guards with parameters (for example, to pass user roles).
  8. Support for HTTP interceptors (they are very similar to middleware, but can use DI).
  9. Support for multi-providers.
  10. Support for extensions that can be asynchronously initialized and that can depend on each other.
  11. Support for extension groups, with the ability to specify "before" or "after" which group you want to run your extension group.
  12. Ability to dynamically add providers and routes in extensions.
  13. Ability to dynamically add and remove modules after starting the web server, without the need to restart. Moreover, if you fail to add a particular module, you can automatically roll back to the previous set of modules. This rollback can be done non-automatically, for example, if the error did not occur during the adding of a new module, but later.
  14. Has OpenAPI support.

NestJS vs Ditsmod

Of course, I've seen NestJS exist, and its author, like me, was inspired by the Angular architecture. NestJS also has DI, a modular architecture, it's written in TypeScript... but at the moment (v7.6.17) NestJS has a number of the following architectural solutions, which is why I decided to write Ditsmod.

DI searches for instances by class name

DI uses class names as search tokens, not references to them. That is, if you have two different classes that have the same name, NestJS DI will consider it the same class. This is especially problematic when you import third-party modules into your application, and they have no idea what classes are in your application.

In the next - 8 version of NestJS - it is planned to fix, but, in my opinion, it had to be done in the first version. Especially since NestJS is positioned as a "framework for scalable applications".

Lack of support for nested routes

NestJS has the ability to create a single global prefix for routes, and there are controller-level prefixes, but module-level prefixes are not supported. That is, if you want to have a parent module at /api/posts/:postId and a child module at /api/posts/:postId/comments/:commentId, you will not be able to do so.

It is true that there is a third-party nest-router module, which does something like that, but at the moment NestJS does not have it in the official module. This is also bad for a "framework for scalable applications".

Almost everything is shared across incoming requests

I was surprised to learn that NestJS controllers by default have application-level sigletons. Can you imagine!? =). That is, if you want to create a variable at the class level in the controller, you can get into trouble, because all requests coming on a particular route will have access to this variable.

Exported providers are not checked for collisions

Imagine you have Module1 where you imported Module2 and Module3. You did this import because you need Service2 and Service3 from these modules, respectively. You are viewing how these services work, but for some reason Service3 does not work as expected. You start debug and it turns out that Service3 exports both modules:Module2 and Module3. You expected that Service3 would only be exported from Module3, but the version exported from Module2 actually worked.

Specifically in this case:

  1. Module2 substitute and then exports the provider with the token Service3;
  2. and Module3 substitute and then exports the provider with the token Service3.

Therefore, the framework must have to detect such collisions.

It is not possible to connect or disconnect modules after starting the web server

In NestJS it is possible to pass parameters for modules (here such modules are called dynamic), but there is no possibility to connect or disconnect modules after start of the web server.

This feature can also be quite desirable, for example for temporary connection monitoring, or for CMS such as Wordpress, etc.

No extension system (or plugins)

NestJS has the ability to pass arguments to modules, and it has Lifecycle hooks, but these mechanisms are not a system of extensions (or plug-ins) where you can specify one extension in dependency from another, or determine the order in which different groups of extensions run.

Discussion (2)

olesmartyniuk profile image
Oleksandr Martyniuk

First of all, good work!

I just can suggest adding a simple "how-to" with code and some illustrations. It can give more comprehension of what is Ditsmod. It is quite difficult to understand the purpose of the framework starting from comparison with NestJS. Especially for those who never worked with NextJS before.

kostyatretyak profile image
Костя Третяк Author

Hmm, interesting. As soon as I published this post, about 5 people read it in the first 30 minutes. Given that it was at 03:00 (that is, late at night) and it was visitors from Europe, I hoped that when the next day came, the number of visitors would be much higher.

But it did not happen (now only 29 views). It seems that on it is necessary to publish in the morning, or in the afternoon that the post was not lost.