Create a centralized repository module that initializes your Firestore connection and repository instances.
repositories/user.repository.ts
import { FirestoreRepository } from '@spacelabstech/firestoreorm';import { db } from '../config/firebase';import { userSchema, User } from '../schemas/user.schema';export const userRepo = FirestoreRepository.withSchema<User>( db, 'users', userSchema);
2
Create Express Routes
Build RESTful routes using the repository. FirestoreORM automatically validates data and provides detailed error information.
routes/user.routes.ts
import express from 'express';import { userRepo } from '../repositories/user.repository';import { ValidationError, NotFoundError } from '@spacelabstech/firestoreorm';const router = express.Router();router.post('/users', async (req, res, next) => { try { const user = await userRepo.create({ ...req.body, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }); res.status(201).json(user); } catch (error) { next(error); // errorHandler middleware will process this }});router.get('/users', async (req, res, next) => { try { const { page = 1, limit = 20, status } = req.query; let query = userRepo.query(); if (status) { query = query.where('status', '==', status); } const result = await query .orderBy('createdAt', 'desc') .offsetPaginate(Number(page), Number(limit)); res.json(result); } catch (error) { next(error); }});router.get('/users/:id', async (req, res, next) => { try { const user = await userRepo.getById(req.params.id); if (!user) { throw new NotFoundError(`User with id ${req.params.id} not found`); } res.json(user); } catch (error) { next(error); }});router.patch('/users/:id', async (req, res, next) => { try { const user = await userRepo.update(req.params.id, { ...req.body, updatedAt: new Date().toISOString() }); res.json(user); } catch (error) { next(error); }});router.delete('/users/:id', async (req, res, next) => { try { await userRepo.softDelete(req.params.id); res.status(204).send(); } catch (error) { next(error); }});export default router;
3
Register Error Handler
Add the built-in error handler as the last middleware to automatically convert ORM errors to proper HTTP responses.
app.ts
import express from 'express';import { errorHandler } from '@spacelabstech/firestoreorm';import userRoutes from './routes/user.routes';const app = express();app.use(express.json());app.use('/api', userRoutes);app.use(errorHandler); // Must be lastapp.listen(3000, () => { console.log('Server running on port 3000');});
The error handler must be registered after all routes and before starting the server. This ensures all route errors are caught and formatted correctly.
Create repositories in a centralized repositories/ directory and export them as singleton instances. Never create repository instances in route handlers.
Error Handling
Always use try/catch blocks in async route handlers and pass errors to next(). Register the error handler middleware last.
Validation
Let FirestoreORM handle validation through Zod schemas. Don’t duplicate validation logic in route handlers.
Pagination
Always use pagination on list endpoints. Prefer cursor-based pagination for better performance on large datasets.
For production applications, add request validation middleware, rate limiting, and proper logging alongside FirestoreORM’s built-in features.