@cardql/node
Version:
CardQL SDK for Node.js and serverless applications
128 lines (109 loc) • 2.9 kB
text/typescript
import type { Request, Response, NextFunction } from "express";
import { NodeCardQL } from "./client";
import type { NodeCardQLConfig } from "./config";
// Extend Express Request type to include cardql instance
declare global {
namespace Express {
interface Request {
cardql?: NodeCardQL;
}
}
}
export interface MiddlewareOptions extends NodeCardQLConfig {
// Additional middleware-specific options
skipHealthCheck?: boolean;
errorHandler?: (
error: Error,
req: Request,
res: Response,
next: NextFunction
) => void;
}
/**
* Express middleware to inject CardQL instance into requests
*/
export function cardqlMiddleware(options: MiddlewareOptions = {}) {
const cardql = new NodeCardQL(options);
// Perform initial health check unless disabled
if (!options.skipHealthCheck) {
cardql.healthCheck().catch((error) => {
console.warn("[CardQL] Initial health check failed:", error.message);
});
}
return (req: Request, res: Response, next: NextFunction) => {
// Attach CardQL instance to request
req.cardql = cardql;
next();
};
}
/**
* Error handling middleware for CardQL errors
*/
export function cardqlErrorHandler() {
return (error: any, req: Request, res: Response, next: NextFunction) => {
// Check if it's a CardQL error
if (error.code && error.message) {
const statusCode = getHttpStatusFromCardQLError(error);
res.status(statusCode).json({
error: {
message: error.message,
code: error.code,
details: error.details,
},
});
return;
}
// Pass through other errors
next(error);
};
}
/**
* Map CardQL error codes to HTTP status codes
*/
function getHttpStatusFromCardQLError(error: any): number {
switch (error.code) {
case "UNAUTHENTICATED":
case "INVALID_API_KEY":
return 401;
case "FORBIDDEN":
case "INSUFFICIENT_PERMISSIONS":
return 403;
case "NOT_FOUND":
case "RESOURCE_NOT_FOUND":
return 404;
case "VALIDATION_ERROR":
case "INVALID_INPUT":
return 400;
case "RATE_LIMITED":
return 429;
case "HTTP_ERROR":
return error.details?.status || 500;
default:
return 500;
}
}
/**
* Utility function to create CardQL context for serverless functions
*/
export function createCardQLContext(config?: NodeCardQLConfig): {
cardql: NodeCardQL;
} {
return {
cardql: new NodeCardQL(config),
};
}
/**
* Higher-order function for serverless function handlers
*/
export function withCardQL<TEvent = any, TResult = any>(
handler: (
event: TEvent,
context: any & { cardql: NodeCardQL }
) => Promise<TResult>,
config?: NodeCardQLConfig
) {
const cardql = new NodeCardQL(config);
return async (event: TEvent, context: any): Promise<TResult> => {
return handler(event, { ...context, cardql });
};
}