Repository & RepoUtils
All good database abstraction layers offer easy to use wrappers that provide object-to-relational mapping and access to the underlying database operations. RapidREST is no different. The @Repository decorator injects a Repository (TypeORM) or MongoRepository wrapper into your code, giving you direct access to the database for the data model in question. However, these low-level wrappers don't do much besides call the underlying database driver functions.
In addition to these basic ORM wrappers, RapidREST offers a powerful utility class called RepoUtils that adds the business logic every REST API needs: caching, validation, permissions, optimistic locking, filtering, and more. RepoUtils is the true foundation of RapidREST's persistence engine, used throughout the entire framework. It's the exact same class ModelRoute itself is built on to power every CRUD endpoint.
@Repository
@Repository(type, required?) is the decorator that gets you the raw wrapper. It resolves to a TypeORM Repository for a SQL-backed entity, or a MongoRepository for a Mongo-backed one, whichever @DataStore on the entity points at:
import { DatabaseDecorators } from '@rapidrest/service-core';
import type { MongoRepository } from '@rapidrest/service-core';
const { Repository } = DatabaseDecorators;
export class PetService {
@Repository(Pet)
private repo!: MongoRepository<Pet>;
}
required (default true) throws at startup if the entity's datastore isn't configured, rather than leaving the property silently undefined.
This is genuinely raw: no ACL check, no cache, no change notification. Reach for it when you need a query shape RepoUtils's filter language can't express, or direct access to something ORM-specific, a TypeORM query builder, a Mongo aggregation pipeline, and apply your own permission checks if the result is ever exposed to a caller.
RepoUtils
RepoUtils<T> is what fills that gap: find/create/update/delete for one entity type, with ACL checks, response caching, and change notifications already wired in, the same behavior Auto CRUD Routes already gives you, available directly in your own code:
import { ObjectDecorators } from '@rapidrest/core';
import { RepoUtils } from '@rapidrest/service-core';
const { Inject } = ObjectDecorators;
export class PetService {
@Inject(RepoUtils, { name: Pet.name, args: [Pet] })
private petUtils?: RepoUtils<Pet>;
async adopt(id: string, user?: JWTUser) {
const existing = await this.petUtils?.findOne(id, { user });
if (!existing) return undefined;
return this.petUtils?.update({ uid: id, adopted: true }, existing, { user });
}
}
The methods worth knowing:
| Method | What it does |
|---|---|
find(query, options?) | Returns matching documents, same filter language as Filtering, Pagination & Sorting |
findOne(id, options?) | Returns a single document by id, or undefined |
count(query, options?) | Counts matching documents |
exists(id, options?) | Whether a document with the given id exists |
create(obj, options?) | Creates a document, running the same validation a CRUD endpoint would |
update(obj, existing, options?) | Updates a document. obj is the partial patch, existing is the current record, fetch it with findOne first |
delete(uid, options) | Deletes (or soft-deletes) a document |
truncate(query, options) | Deletes every document matching the query |
Every one of these takes an options object that carries the acting user (for the ACL check), among other things, pass it through, the same way a route handler would. Skip it and the call runs as if no one were authenticated, which usually means it gets rejected once ACLs are enabled.
Which one to use
- Building a service that does what a CRUD endpoint does, list/get/create/update/delete for one model, permission-checked, cached: use
RepoUtils. - Running a query
RepoUtils's filter language can't express, or calling something ORM-specific (a TypeORM query builder, a Mongo aggregation pipeline): use@Repository, and apply your own permission checks if the result is ever exposed to a caller. - Need both in the same service? Inject both, they're not mutually exclusive,
RepoUtilsfor the common path,@Repositoryfor the one query that needs it.