Skip to main content

Auto-Discovery

Unlike most other frameworks, there is no central file where you register routes, models, or jobs in RapidREST. Nor is there a required file system convention for how to organize your code. Instead, every class you export anywhere under your server's source directory is found and registered automatically at startup, by the ClassLoader.

How it works

When the server starts, it recursively scans the project's source directory (.ts/.tsx/.js files, configurable), imports every module it finds, and registers each exported class (default or named) with the dependency injection container (the ObjectFactory).

src/
├── routes/
│ └── PetRoute.ts ← exports a class → discovered → registered
├── models/
│ └── Pet.ts ← exports a class → discovered → registered
└── services/
└── PetService.ts ← plain class, no decorators → still discovered

A class's registered name (its "fully-qualified name") is derived from its file path and export: a default export named PetRoute in src/routes/PetRoute.ts is registered as routes.PetRoute; a named export uses the export's own name instead of the file name. This fully-qualified name is what @Inject('SomeClassName') resolves by string.

What this means in practice

  • Adding a route is just adding a file. Export a class annotated with @Route, and it's live on the next server start. No router file to edit.
  • Plain service classes are injectable for free. A class with no RapidREST decorators at all, just business logic, can still be @Inject-ed anywhere, because discovery doesn't care whether a class "looks like" a route or model.
  • Neither file location or naming convention matter. Discovery is purely based on "is this file under the scanned directory and does it export a class," not on filename suffixes like *.route.ts, or sub-folder placement like routes.

Excluding files

Not every file under your source tree should be scanned. Your server's own entry point and config file, for instance, don't export anything meant for injection. Exclude them via the class_loader:ignore configuration key (an array of regular expressions matched against filenames):

conf.defaults({
class_loader: {
ignore: [/server\..*/, /config\..*/],
},
});
Why this matters early

Because so much of the framework (routing, models, background jobs, event listeners) is powered by this same discovery mechanism, understanding "it's just: export a class under src/" up front makes the rest of the framework feel a lot less like magic.