-
Notifications
You must be signed in to change notification settings - Fork 2
Context Utilities
What if building APIs felt like using superpowers instead of fighting frameworks? 🦸♂️
Traditional backend development means writing the same boilerplate over and over: database connections, authentication, validation, caching, job queues...
Foxx Builder eliminates this pain with powerful context utilities - pre-built, battle-tested functions that handle the hard stuff so you can focus on your business logic.
Every route in your Foxx Builder API has access to a rich set of utilities via module.context
. Think of it as your API's Swiss Army knife:
// In any route handler
const { db, auth, config, jobs, utils } = module.context;
Traditional approach:
// Express.js - you build everything from scratch
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const redis = require('redis');
const mongodb = require('mongodb');
// 50+ lines of setup code...
// Database connection management
// JWT middleware
// Caching layer
// Error handling
// Validation logic
Foxx Builder approach:
// routes/users/post.js
module.exports = {
handler: (req, res) => {
const { db, auth } = module.context;
// That's it. Everything just works.
const user = db.insert('users', req.body);
const token = auth.encode({ userId: user._key });
return { user, token };
}
};
Skip the ORM complexity. Get type-safe, optimized database operations out of the box:
const { db } = module.context;
// Create
const newUser = await db.insert('users', {
username: 'johndoe',
email: '[email protected]',
role: 'user'
});
// Read with filters
const activeUsers = await db.find('users',
{ status: 'active' },
{ limit: 20, sort: { createdAt: -1 } }
);
// Update
const updated = await db.update('users', userId, {
lastLogin: new Date().toISOString()
});
// Delete
await db.remove('users', userId);
// Batch operations for performance
const users = await db.insertMany('users', [user1, user2, user3]);
// Caching built-in
const cachedData = await db.find('posts', {}, {
useCache: true,
cacheTtl: 300000 // 5 minutes
});
// Raw AQL for complex queries
const analytics = await db.query(`
FOR post IN posts
COLLECT author = post.authorId WITH COUNT INTO postCount
SORT postCount DESC
LIMIT 10
RETURN { author, postCount }
`);
Build AI features without complex infrastructure:
const { db } = module.context;
// Find similar products using AI embeddings
const similarProducts = await db.vector.cosineSimilarity(
'products', // collection
'embedding', // vector field
userSearchVector, // query vector
{
limit: 10,
minScore: 0.8,
filter: { category: 'electronics' }
}
);
// Recommendation engine in 3 lines
const recommendations = await db.vector.l2Distance(
'recommendations',
'userPreferenceVector',
currentUserVector,
{ limit: 5 }
);
JWT authentication that actually works properly:
const { auth } = module.context;
// Create tokens with custom claims
const accessToken = auth.encode({
userId: user._key,
roles: ['user', 'premium'],
permissions: ['read:profile', 'write:posts']
});
// Refresh token system
const refreshToken = auth.createRefreshToken(user._key);
// Validate and extract data
const payload = auth.decode(token);
const userId = auth.validateToken(token);
// Check expiration
if (auth.isExpired(token)) {
// Handle expired token
}
// Create middleware once, use everywhere
const authMiddleware = auth.createMiddleware({
exempt: ['/login', '/signup', '/health'],
onSuccess: (req, res) => {
// Automatically attach user data
const user = module.context.db.get('users', req.userId);
req.user = user;
}
});
// Apply to all routes automatically
module.context.use(authMiddleware);
// routes/admin/users/get.js
module.exports = {
name: 'List All Users',
requiresAuth: true, // Built-in auth check
requiresRole: 'admin', // Role-based access
handler: (req, res) => {
// req.user is automatically available
const users = module.context.db.find('users', {});
return {
users,
requestedBy: req.user.username
};
}
};
Manage configuration without the headaches:
const { config } = module.context;
// Type-safe configuration access
const apiKey = config.getString('stripe.apiKey');
const maxUploadSize = config.getNumber('upload.maxSize', 10485760);
const enableAI = config.getBoolean('features.aiSearch', false);
const emailSettings = config.getJSON('email.smtp', {});
// Feature flags made easy
if (config.isEnabled('experimental.newDashboard')) {
// Show new dashboard
}
// Environment-aware configuration
const dbConfig = config.getSection('database');
Handle long-running tasks without blocking requests:
const { jobs } = module.context;
// Send email in background
const emailJobId = jobs.run('sendEmail', {
to: '[email protected]',
template: 'welcome',
data: { username: 'johndoe' }
}, {
delay: 5000, // 5 second delay
maxFailures: 3 // Retry up to 3 times
});
// Process images asynchronously
const imageJobId = jobs.run('processImages', {
userId: user._key,
images: uploadedFiles
});
// Check job status
const jobStatus = jobs.getStatus(emailJobId);
Ensure data integrity with atomic operations:
const { transaction } = module.context;
// Transfer credits between users atomically
const result = transaction.execute(
function(params) {
const users = db._collection('users');
const logs = db._collection('transaction_logs');
// Deduct from sender
const sender = users.document(params.senderId);
if (sender.credits < params.amount) {
throw new Error('Insufficient credits');
}
users.update(params.senderId, {
credits: sender.credits - params.amount
});
// Add to receiver
const receiver = users.document(params.receiverId);
users.update(params.receiverId, {
credits: receiver.credits + params.amount
});
// Log transaction
logs.save({
type: 'credit_transfer',
senderId: params.senderId,
receiverId: params.receiverId,
amount: params.amount,
timestamp: Date.now()
});
return { success: true };
},
{ write: ['users', 'transaction_logs'] },
{ senderId, receiverId, amount: 100 }
);
Everyday utilities that save you time:
const { utils } = module.context;
// Email validation
const isValidEmail = utils.isEmail('[email protected]'); // true
// Build database filters from user input
const filters = [
{ key: 'status', op: '=', value: 'active' },
{ key: 'age', op: '>', value: 18 },
{ key: 'city', op: 'LIKE', value: 'New%' }
];
const filterExpression = utils.filter(filters, 'user');
// Use in AQL: FOR user IN users ${filterExpression} RETURN user
// Advanced query building with custom conditions
const customQuery = utils.filterBuilder(filters, 'user');
Here's how all these utilities work together in a real endpoint:
// routes/users/post.js - User registration
const joi = require('joi');
module.exports = {
name: 'Register New User',
body: {
type: 'object',
properties: {
username: { type: 'string', minLength: 3 },
email: { type: 'string', format: 'email' },
password: { type: 'string', minLength: 8 }
},
required: ['username', 'email', 'password']
},
handler: async (req, res) => {
const { db, auth, jobs, utils, config } = module.context;
const { username, email, password } = req.body;
// Validate email format
if (!utils.isEmail(email)) {
res.throw(400, 'Invalid email format');
}
// Check if user exists
const existingUser = await db.find('users', { email });
if (existingUser.length > 0) {
res.throw(409, 'User already exists');
}
// Create user with encrypted password
const hashedPassword = crypto.sha384(password);
const newUser = await db.insert('users', {
username,
email,
password: hashedPassword,
status: 'pending',
createdAt: new Date().toISOString()
});
// Generate auth token
const token = auth.encode({
userId: newUser._key,
roles: ['user']
});
// Send welcome email in background
if (config.getBoolean('email.enabled', true)) {
jobs.run('sendWelcomeEmail', {
userId: newUser._key,
email,
username
});
}
// Return user data (without password)
return {
success: true,
user: {
id: newUser._key,
username,
email,
status: 'pending'
},
token
};
}
};
Since your API runs inside ArangoDB, context utilities have zero network latency:
// This executes instantly - no network round-trips
const users = await db.find('users', { active: true });
const posts = await db.find('posts', { authorId: users[0]._key });
const comments = await db.find('comments', { postId: posts[0]._key });
- Connection pooling: Handled automatically
- Query caching: Built into database operations
- Memory efficiency: Shared contexts across requests
- Transaction management: Optimized for ArangoDB
// 200+ lines of setup
const express = require('express');
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const redis = require('redis');
const nodemailer = require('nodemailer');
// Database connection
mongoose.connect(process.env.DB_URL);
// Redis for caching
const redisClient = redis.createClient();
// JWT middleware
const authMiddleware = (req, res, next) => {
// 30+ lines of auth logic
};
// Email service
const emailService = nodemailer.createTransport({
// Configuration...
});
// Route handler
app.post('/users', authMiddleware, async (req, res) => {
// Manual validation
// Manual password hashing
// Manual database operations
// Manual error handling
// Manual response formatting
});
// routes/users/post.js
module.exports = {
requiresAuth: true,
body: { /* validation schema */ },
handler: (req, res) => {
const { db, auth, jobs } = module.context;
// Everything just works
const user = db.insert('users', userData);
const token = auth.encode({ userId: user._key });
jobs.run('sendWelcome', { email: userData.email });
return { user, token };
}
};
"I went from 200 lines of boilerplate to 20 lines of business logic. The context utilities handle everything I used to spend hours on." - Sarah, Full-stack Developer
"The database utilities alone saved me weeks. No ORM complexity, just intuitive operations that work." - Mike, Backend Developer
"Authentication that actually works out of the box? This is what I've been waiting for." - Alex, Startup CTO
Context utilities are available in every route automatically:
// Any route file
module.exports = {
handler: (req, res) => {
const { db, auth, config, jobs, utils } = module.context;
// Build amazing APIs without the boilerplate
}
};
Ready to explore more advanced patterns? Check out API Routes to see how context utilities integrate with file-based routing.
Copyright © 2016-2025, Skitsanos™