Express Integration
FOON provides first-class Express.js support with automatic request transformation.
Installation
npm install foon-sdkNo additional packages needed - Express integration is included.
Basic Setup
createFonRouter()
Create a router that automatically transforms request bodies:
import express from 'express';
import { createFonRouter } from 'foon-sdk/express';
import { OpenAIProvider } from 'foon-sdk';
const app = express();
app.use(express.json());
const fonRouter = createFonRouter({
provider: new OpenAIProvider({
apiKey: process.env.OPENAI_API_KEY,
model: 'gpt-5-nano'
}),
prefix: '/foon',
confidenceThreshold: 0.85
});
// Mount the router
app.use(fonRouter.getRouter());
app.listen(3000);Defining Routes
With Schema
Register routes that transform incoming data to your schema:
const customerSchema = {
type: 'object',
properties: {
name: {
type: 'object',
properties: {
given: { type: 'string' },
family: { type: 'string' }
},
required: ['given', 'family']
},
email: { type: 'string', format: 'email' }
},
required: ['name', 'email']
};
fonRouter.post('/users', {
schema: customerSchema,
handler: (req, res) => {
// req.body is already transformed and validated!
res.json({ success: true, user: req.body });
}
});Dual Routes
FOON automatically creates two routes for each registration:
| Route | Description |
|---|---|
POST /users | Original route (untransformed) |
POST /foon/users | FOON route (transformed) |
Requests to FOON routes:
- Transform
req.bodyusing the configured schema - Replace
req.bodywith validated output - Add trace ID header (
X-FON-Trace-Id) - Forward to the same handler
Router Configuration
interface FonRouterConfig {
provider: Provider; // LLM provider (required)
prefix?: string; // Route prefix (default: '/foon')
methods?: HttpMethod[]; // Methods to transform (default: ['POST', 'PUT', 'PATCH'])
confidenceThreshold?: number; // Confidence threshold (default: 0.85)
cache?: Cache; // Cache instance
security?: SecurityOptions; // Security options
traceHeader?: string; // Trace header name (default: 'X-FON-Trace-Id')
onError?: ErrorHandler; // Custom error handler
createOriginalRoutes?: boolean; // Create original routes (default: true)
verbose?: boolean; // Verbose logging (default: false)
}Route Configuration
interface RouteConfig {
schema: object; // JSON Schema for this route
handler: RequestHandler; // Express handler
createOriginal?: boolean; // Override: create original route
confidenceThreshold?: number; // Override: confidence threshold for this route
}Error Handling
Default Error Handler
When transformation fails, the default error handler returns:
{
"error": "CONFIDENCE_TOO_LOW",
"message": "1 assignment(s) below confidence threshold 0.85",
"traceId": "uuid",
"details": { ... }
}HTTP status codes:
400- Bad Request (validation error, confidence too low)413- Payload Too Large (security limits exceeded)500- Internal Server Error (execution error)502- Bad Gateway (provider error)
Custom Error Handler
const fonRouter = createFonRouter({
provider,
onError: (error, req, res, next) => {
res.status(400).json({
error: error.category,
message: error.message,
traceId: error.traceId,
trace: req.fonTrace
});
}
});Configuration Examples
Disable Original Routes
const fonRouter = createFonRouter({
provider,
createOriginalRoutes: false // Only create FOON routes
});
// Now only /foon/users exists, not /usersCustom Prefix
const fonRouter = createFonRouter({
provider,
prefix: '/api/semantic'
});
fonRouter.post('/users', { schema, handler });
// Creates: POST /api/semantic/usersPer-Route Configuration
fonRouter.post('/users', {
schema: userSchema,
handler: createUserHandler,
createOriginal: false, // Don't create /users for this route
confidenceThreshold: 0.9 // Higher threshold for this route
});Trace Headers
FOON routes automatically add headers to responses:
X-FON-Trace-Id: Unique trace ID for debuggingX-FON-Timing-Total: Total processing time (verbose mode)X-FON-Timing-Proposal: LLM call time (verbose mode)X-FON-Cache-Hit: Whether cache was hit (verbose mode)
Accessing Trace Data
The trace is attached to the request object:
fonRouter.post('/users', {
schema: userSchema,
handler: (req, res) => {
const trace = (req as any).fonTrace;
console.log('Confidence:', trace.confidenceSummary);
console.log('Timings:', trace.timings);
res.json(req.body);
}
});With Cache
import { createFonRouter } from 'foon-sdk/express';
import { OpenAIProvider, LRUCache } from 'foon-sdk';
const cache = new LRUCache({ max: 100, ttl: 3600000 });
const fonRouter = createFonRouter({
provider: new OpenAIProvider({
apiKey: process.env.OPENAI_API_KEY,
model: 'gpt-5-nano'
}),
cache
});With Security Options
const fonRouter = createFonRouter({
provider,
security: {
maxInputSize: 1024 * 1024,
maxDepth: 10,
maxKeys: 1000,
redactKeys: ['password', 'token'],
sanitizePrompt: true
}
});