Skip to main content
Integrate VectoriaDB into an Express.js application.

Basic Setup

src/app.ts
import express from 'express';
import { VectoriaDB, FileStorageAdapter, DocumentMetadata } from 'vectoriadb';

interface ProductDocument extends DocumentMetadata {
  name: string;
  category: string;
  price: number;
}

const app = express();
app.use(express.json());

// Initialize VectoriaDB
const productIndex = new VectoriaDB<ProductDocument>({
  storageAdapter: new FileStorageAdapter({
    cacheDir: './.cache/vectoriadb',
    namespace: 'products',
  }),
  useHNSW: true,
});

// Startup initialization
async function startup() {
  await productIndex.initialize();
  console.log('VectoriaDB initialized');
}

// Search endpoint
app.get('/api/search', async (req, res) => {
  try {
    const { q, category, limit = 10 } = req.query;

    if (!q || typeof q !== 'string') {
      return res.status(400).json({ error: 'Query parameter "q" is required' });
    }

    const results = await productIndex.search(q, {
      topK: Number(limit),
      filter: category ? (m) => m.category === category : undefined,
    });

    res.json({
      query: q,
      results: results.map((r) => ({
        id: r.id,
        score: r.score,
        name: r.metadata.name,
        category: r.metadata.category,
        price: r.metadata.price,
      })),
    });
  } catch (error) {
    console.error('Search error:', error);
    res.status(500).json({ error: 'Search failed' });
  }
});

// Add product endpoint
app.post('/api/products', async (req, res) => {
  try {
    const { id, name, description, category, price } = req.body;

    await productIndex.add(id, `${name}. ${description}`, {
      id,
      name,
      category,
      price,
    });

    await productIndex.saveToStorage();

    res.status(201).json({ id, message: 'Product added' });
  } catch (error) {
    console.error('Add product error:', error);
    res.status(500).json({ error: 'Failed to add product' });
  }
});

// Health check
app.get('/health', (req, res) => {
  res.json({
    status: 'healthy',
    products: productIndex.size(),
  });
});

startup().then(() => {
  app.listen(3000, () => {
    console.log('Server running on port 3000');
  });
});

Error Handling Middleware

src/middleware/error-handler.ts
import { VectoriaError, QueryValidationError } from 'vectoriadb';

export function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {
  if (err instanceof QueryValidationError) {
    return res.status(400).json({
      error: 'Invalid query',
      code: err.code,
      message: err.message,
    });
  }

  if (err instanceof VectoriaError) {
    return res.status(500).json({
      error: 'Database error',
      code: err.code,
    });
  }

  console.error('Unexpected error:', err);
  res.status(500).json({ error: 'Internal server error' });
}

// Usage
app.use(errorHandler);

Async Error Wrapper

src/utils/async-handler.ts
type AsyncHandler = (req: Request, res: Response, next: NextFunction) => Promise<any>;

export function asyncHandler(fn: AsyncHandler) {
  return (req: Request, res: Response, next: NextFunction) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
}

// Usage
app.get('/api/search', asyncHandler(async (req, res) => {
  const results = await productIndex.search(req.query.q as string);
  res.json(results);
}));

Rate Limiting

src/middleware/rate-limit.ts
import rateLimit from 'express-rate-limit';

const searchLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 100, // 100 requests per minute
  message: { error: 'Too many search requests' },
});

app.use('/api/search', searchLimiter);

FrontMCP

FrontMCP integration

Next.js

Next.js integration

Deployment

Production deployment