@gati-framework/runtime
v2.0.8
Published
Gati runtime execution engine for running handler-based applications
Maintainers
Readme
@gati-framework/runtime
Runtime execution engine for Gati handler-based applications
Installation
npm install @gati-framework/runtime
# or
pnpm add @gati-framework/runtime
# or
yarn add @gati-framework/runtimeUsage
Basic Setup
import { createApp } from '@gati-framework/runtime';
const app = createApp({
port: 3000,
host: 'localhost',
logging: true,
});
// Register handlers manually
app.get('/hello', (req, res) => {
res.json({ message: 'Hello, World!' });
});
// Start the server
await app.listen();Automatic Handler Discovery
The runtime can automatically discover and register handlers from a directory:
import { createApp, loadHandlers } from '@gati-framework/runtime';
const app = createApp();
// Automatically load all handlers from ./src/handlers
await loadHandlers(app, './src/handlers', {
basePath: '/api', // Optional: prefix all routes
verbose: true, // Optional: log registration
});
await app.listen();Handler File Structure
Handlers should export a handler function:
// src/handlers/hello.ts
import type { Handler } from '@gati-framework/runtime';
export const handler: Handler = (req, res) => {
const name = req.query.name || 'World';
res.json({ message: `Hello, ${name}!` });
};
// Optional: Export metadata for registration
export const metadata = {
method: 'GET',
route: '/hello'
};File path routing:
src/handlers/hello.ts→GET /hellosrc/handlers/users/create.ts→POST /users/createsrc/handlers/api/v1/posts.ts→GET /api/v1/posts
Configuration
import { createApp } from '@gati-framework/runtime';
const app = createApp({
port: parseInt(process.env.PORT || '3000'),
host: process.env.HOST || '0.0.0.0',
timeout: 30000, // 30 seconds
logging: process.env.NODE_ENV !== 'production',
logger: { // Optional logger configuration
level: 'info', // 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'
pretty: process.env.NODE_ENV !== 'production', // Pretty print in dev
},
});Structured Logging
The runtime includes structured logging with pino for production observability:
import { createApp, logger, createLogger } from '@gati-framework/runtime';
// Use the default logger in your handlers
app.get('/users', (req, res, gctx, lctx) => {
logger.info({ requestId: lctx.requestId }, 'Fetching users');
// Your logic here
const users = getUsersFromDB();
logger.info(
{ requestId: lctx.requestId, count: users.length },
'Users fetched successfully'
);
res.json({ users });
});
// Create a custom logger for specific modules
const dbLogger = createLogger({
name: 'database',
level: 'debug',
pretty: false, // Force JSON output
});
dbLogger.info({ query: 'SELECT * FROM users' }, 'Running query');
dbLogger.error({ error: err.message }, 'Database error');Log Levels:
trace- Very detailed debugging informationdebug- Debugging informationinfo- Informational messages (default)warn- Warning messageserror- Error messagesfatal- Critical errors
Output Formats:
- Development: Pretty-printed, human-readable logs
- Production: JSON logs for aggregation tools (e.g., ELK, Datadog)
Middleware
import { createApp, createCorsMiddleware } from '@gati-framework/runtime';
const app = createApp();
// Add custom middleware
app.use(async (req, res, gctx, lctx, next) => {
console.log(`${req.method} ${req.path}`);
await next();
});
// Add CORS middleware (built-in helper)
app.use(createCorsMiddleware({
origin: 'https://myapp.com',
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
}));
// Apply middleware to specific paths
app.use(authMiddleware, { path: '/api/*' });
// Error handling middleware
app.useError((error, req, res, gctx, lctx) => {
console.error('Error:', error);
res.status(500).json({ error: 'Internal Server Error' });
});CORS Configuration
The built-in CORS middleware supports multiple configuration options:
import { createCorsMiddleware } from '@gati-framework/runtime';
// Allow all origins (default)
app.use(createCorsMiddleware());
// Specific origin
app.use(createCorsMiddleware({ origin: 'https://myapp.com' }));
// Multiple origins
app.use(createCorsMiddleware({
origin: ['https://app1.com', 'https://app2.com']
}));
// Dynamic origin validation
app.use(createCorsMiddleware({
origin: (origin) => origin.endsWith('.myapp.com'),
credentials: true,
exposedHeaders: ['X-Total-Count'],
maxAge: 86400, // 24 hours
}));Graceful Shutdown
The server supports graceful shutdown, waiting for active requests to complete:
const app = createApp({
port: 3000,
timeout: 30000 // Request timeout: 30 seconds
});
await app.listen();
// Handle shutdown signals
process.on('SIGTERM', async () => {
console.log('Shutting down gracefully...');
await app.close(); // Waits up to 10 seconds for active requests
process.exit(0);
});
process.on('SIGINT', async () => {
console.log('Shutting down gracefully...');
await app.close();
process.exit(0);
});Method-specific Routes
app.get('/users', getUsersHandler);
app.post('/users', createUserHandler);
app.put('/users/:id', updateUserHandler);
app.patch('/users/:id', patchUserHandler);
app.delete('/users/:id', deleteUserHandler);API Reference
createApp(config?: AppConfig): GatiApp
Creates a new Gati application instance.
Config options:
port?: number- Port to listen on (default: 3000)host?: string- Host to bind to (default: 'localhost')timeout?: number- Server timeout in ms (default: 30000)logging?: boolean- Enable request logging (default: true)
loadHandlers(app, dir, options?): Promise<void>
Automatically discovers and registers handlers from a directory.
Parameters:
app: GatiApp- Application instancedir: string- Directory path (e.g., './src/handlers')options.basePath?: string- Route prefix (default: '')options.verbose?: boolean- Log registration (default: false)
GatiApp Methods
get(path, handler)- Register GET routepost(path, handler)- Register POST routeput(path, handler)- Register PUT routepatch(path, handler)- Register PATCH routedelete(path, handler)- Register DELETE routeuse(middleware)- Add middlewareuseError(errorMiddleware)- Add error handlerlisten()- Start HTTP serverclose()- Stop HTTP server gracefullyisRunning()- Check if server is runninggetConfig()- Get current configuration
Type Definitions
All TypeScript types are exported:
import type {
Handler,
Request,
Response,
GlobalContext,
LocalContext,
Middleware,
ErrorMiddleware,
AppConfig,
} from '@gati-framework/runtime';Examples
See the examples directory for complete examples:
- hello-world - Basic application
- scaffold-verify - Scaffolded project structure
Requirements
- Node.js >= 18.0.0
- TypeScript >= 5.3.0 (for development)
License
MIT © Krishna Paul
