App API

Core APIs for accessing your app instance, grouping routes under shared prefixes, and auto-loading route files from the filesystem.

What You'll Learn

How to access the app singleton from any file
Grouping routes under shared prefixes with nesting
Auto-loading route files from a directory
File conventions for route auto-loading
1

getApp() — App Singleton Accessor

Route files no longer need the app instance passed in. Any file can import and register routes directly using getApp(). This returns the singleton app instance created by createApp().

Using getApp()

typescript

1import { getApp } from '@morojs/moro';
2const app = getApp();
3
4app.get('/health', (req, res) => {
5  res.json({ status: 'healthy' });
6});

Why use getApp()?

  • • No need to thread the app instance through imports
  • • Route files become self-contained and portable
  • • Works anywhere after createApp() has been called
  • • Pairs naturally with app.loadRoutes() for auto-loading
2

app.group() — Route Grouping

Group routes under a shared prefix. Supports the full chainable API and nesting for clean, organized route definitions.

Basic Route Grouping

typescript

1app.group('/auth', (auth) => {
2  auth.post('/login').body(LoginSchema).handler(actions.login);
3  auth.post('/logout').handler(actions.logout);
4  auth.get('/me', requireAuth, actions.me);
5});

Nested Groups

typescript

1// Nested groups for API versioning
2app.group('/api', (api) => {
3  api.group('/v1', (v1) => {
4    v1.get('/users').handler(listUsers);
5    v1.get('/users/:id').handler(getUser);
6    v1.post('/users').body(CreateUserSchema).handler(createUser);
7  });
8
9  api.group('/v2', (v2) => {
10    v2.get('/users').handler(listUsersV2);
11  });
12});

Group Features

  • • Shared prefix applied to all child routes
  • • Full chainable API inside the group callback
  • • Unlimited nesting depth
  • • Middleware can be applied per-group or per-route
3

app.loadRoutes() — Auto-Load Route Files

Automatically imports route files from a directory. Top-level files are loaded directly. Subdirectories load only index.ts — other files like actions.ts or schemas.ts are ignored by the loader and pulled in by the index.

Usage

typescript

1await app.loadRoutes('./src/routes');

Directory Convention

text

1routes/
2  health.ts              -> loaded
3  auth/
4    index.ts             -> loaded (uses app.group('/auth'))
5    actions.ts           -> ignored (imported by index.ts)
6    schemas.ts           -> ignored (imported by index.ts)
7  stats/
8    index.ts             -> loaded
9    actions.ts           -> ignored

Example Route File

typescript

1// routes/health.ts
2import { getApp } from '@morojs/moro';
3const app = getApp();
4
5app.get('/health', (req, res) => {
6  res.json({ status: 'healthy', uptime: process.uptime() });
7});

Example Route Directory

typescript

1// routes/auth/index.ts
2import { getApp } from '@morojs/moro';
3import * as actions from './actions';
4import { LoginSchema } from './schemas';
5
6const app = getApp();
7
8app.group('/auth', (auth) => {
9  auth.post('/login').body(LoginSchema).handler(actions.login);
10  auth.post('/logout').handler(actions.logout);
11  auth.get('/me', requireAuth, actions.me);
12});

Loading Rules

  • • Top-level .ts files are loaded directly
  • • Subdirectories only load index.ts
  • • Supporting files (actions.ts, schemas.ts) are imported by the index, not the loader
  • • Keeps route directories self-contained and organized