@struktos/adapter-fastify
v0.1.0
Published
Fastify adapter for Struktos.js - Context propagation and cancellation for Fastify applications
Maintainers
Readme
@struktos/adapter-fastify
Fastify adapter for Struktos.js - Bringing enterprise-grade context propagation and cancellation tokens to Fastify applications.
🎯 Features
- Context Propagation - Automatic context propagation through async operations
- Trace ID Generation - Unique trace ID for each request
- Cancellation Tokens - Automatic cancellation on client disconnect
- Type Safety - Full TypeScript support with Fastify types
- Zero Config - Works out of the box with sensible defaults
- Fastify Plugin - Native Fastify plugin architecture
- Performance - Minimal overhead with high-performance context management
📦 Installation
npm install @struktos/adapter-fastify @struktos/core fastify🚀 Quick Start
Basic Usage
import Fastify from 'fastify';
import { createStruktosPlugin } from '@struktos/adapter-fastify';
const fastify = Fastify();
// Register Struktos plugin
await fastify.register(createStruktosPlugin());
// Access context in routes
fastify.get('/api/user', async (request, reply) => {
const context = request.getContext();
console.log('TraceID:', context.get('traceId'));
return { user: 'John Doe' };
});
await fastify.listen({ port: 3000 });With Options
await fastify.register(createStruktosPlugin({
// Custom trace ID generator
generateTraceId: () => `trace-${Date.now()}`,
// Enable/disable automatic cancellation
enableCancellation: true,
// Extract user from request
extractUser: (request) => {
const token = request.headers.authorization?.substring(7);
return token ? { id: 'user-123', token } : undefined;
},
// Lifecycle callbacks
onContextCreated: (context, request) => {
console.log('Context created:', context.get('traceId'));
},
onContextDestroyed: (context, request) => {
console.log('Context destroyed:', context.get('traceId'));
}
}));📖 API
createStruktosPlugin(options?)
Creates a Fastify plugin that integrates Struktos context propagation.
Options:
interface StruktosPluginOptions {
// Custom function to generate trace IDs
generateTraceId?: () => string;
// Custom context key for storing context in request
contextKey?: string;
// Enable automatic cancellation on client disconnect
enableCancellation?: boolean;
// Extract user information from request
extractUser?: (request: FastifyRequest) => Record<string, any> | undefined;
// Callback when context is created
onContextCreated?: (context: RequestContext<any>, request: FastifyRequest) => void;
// Callback when context is destroyed
onContextDestroyed?: (context: RequestContext<any>, request: FastifyRequest) => void;
}Request Extensions
The plugin extends Fastify's FastifyRequest with:
interface FastifyRequest {
// Struktos context for this request
struktosContext?: RequestContext<any>;
// Get the current context (throws if not available)
getContext(): RequestContext<any>;
}🎓 Examples
Context Propagation
import { RequestContext } from '@struktos/core';
// Context automatically propagates through async operations
fastify.get('/api/data', async (request, reply) => {
const context = request.getContext();
// Context is available in nested functions
await fetchUserData();
await fetchOrderData();
return { message: 'Success' };
});
async function fetchUserData() {
// Access context from anywhere
const context = RequestContext.current();
console.log('TraceID:', context?.get('traceId'));
// Simulate async operation
await new Promise(resolve => setTimeout(resolve, 100));
}Request Metadata
Context automatically includes request metadata:
fastify.get('/api/info', async (request, reply) => {
const context = request.getContext();
return {
traceId: context.get('traceId'),
method: context.get('method'), // 'GET'
url: context.get('url'), // '/api/info'
ip: context.get('ip'), // '127.0.0.1'
userAgent: context.get('userAgent') // 'curl/7.64.1'
};
});Cancellation Tokens
fastify.get('/api/slow', async (request, reply) => {
const context = request.getContext();
for (let i = 0; i < 100; i++) {
// Check if client disconnected
if (context.isCancelled()) {
console.log('Client disconnected, stopping operation');
return { error: 'Cancelled' };
}
await processChunk(i);
}
return { message: 'Completed' };
});Caching with CacheManager
import { RequestContext, CacheManager } from '@struktos/core';
const productCache = new CacheManager<string, any>(1000);
async function getProducts() {
const context = RequestContext.current();
// Check cache first
const cached = productCache.get('products');
if (cached) {
return cached;
}
// Fetch from database
const products = await db.products.findAll();
// Store in cache
productCache.set('products', products, 60000); // TTL: 60 seconds
return products;
}
fastify.get('/api/products', async (request, reply) => {
const products = await getProducts();
return { products };
});See examples/ for more complete examples.
📄 License
MIT © Struktos.js Team
