Files
Edu/services/parent-bff/src/shared/errors/application-error.ts
SpecialX 2229309a1e feat: initialize parent-bff service with full core features
add complete parent-bff implementation including:
- GraphQL endpoint with depth/cost validation
- ChildGuard越权校验 with redis cache and singleflight
- parallel orchestration with partial failure fallback
- three-level cache fallback strategy (Redis + LRU + downstream)
- Kafka consumer for cache invalidation and notification push
- opossum circuit breaker for downstream services
- Prometheus metrics and SLO alerts
- Helm chart for k8s deployment with multi-environment configs
- Grafana dashboard for observability
- complete unit and integration tests
2026-07-10 18:49:06 +08:00

165 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* parent-bff 统一错误体系(对齐 02-architecture-design.md §6.2)。
*
* 错误码前缀统一 BFF_PARENT_*C1 仲裁BFF 在前,不是 PARENT_BFF_
*
* 错误码清单:
* - BFF_PARENT_VALIDATION_ERROR (400)
* - BFF_PARENT_UNAUTHORIZED (401)
* - BFF_PARENT_CHILD_NOT_BOUND (403) — ChildGuard 拦截
* - BFF_PARENT_NOT_FOUND (404)
* - BFF_PARENT_CONFLICT (409)
* - BFF_PARENT_BUSINESS_ERROR (422)
* - BFF_PARENT_BAD_GATEWAY (502)
* - BFF_PARENT_GATEWAY_TIMEOUT (504)
* - BFF_PARENT_SERVICE_UNAVAILABLE (503) — 熔断器开启P6
* - BFF_PARENT_INTERNAL_ERROR (500)
*/
export type ErrorType =
| "validation"
| "unauthorized"
| "child_not_bound"
| "not_found"
| "conflict"
| "business"
| "bad_gateway"
| "gateway_timeout"
| "service_unavailable"
| "internal";
export interface ErrorDetails {
[key: string]: unknown;
}
export abstract class ApplicationError extends Error {
abstract readonly type: ErrorType;
abstract readonly statusCode: number;
readonly code: string;
readonly details?: ErrorDetails;
traceId?: string;
constructor(message: string, code: string, details?: ErrorDetails) {
super(message);
this.name = this.constructor.name;
this.code = code;
this.details = details;
}
toJSON(): Record<string, unknown> {
return {
success: false,
error: {
code: this.code,
message: this.message,
details: this.details,
traceId: this.traceId,
},
};
}
}
export class ValidationError extends ApplicationError {
readonly type = "validation" as const;
readonly statusCode = 400;
constructor(message: string, details?: ErrorDetails) {
super(message, "BFF_PARENT_VALIDATION_ERROR", details);
}
}
export class UnauthorizedError extends ApplicationError {
readonly type = "unauthorized" as const;
readonly statusCode = 401;
constructor(message: string, details?: ErrorDetails) {
super(message, "BFF_PARENT_UNAUTHORIZED", details);
}
}
/**
* ChildGuard 越权拦截childId 不在家长绑定列表。
*
* 对齐 02 §2.3DataScope=CHILDREN 防御BFF 层先拦截减少无效下游调用。
*/
export class ChildNotBoundError extends ApplicationError {
readonly type = "child_not_bound" as const;
readonly statusCode = 403;
constructor(parentId: string, requestedChildId: string, boundChildren: string[]) {
super(
`Child ${requestedChildId} not bound to parent ${parentId}`,
"BFF_PARENT_CHILD_NOT_BOUND",
{
parentId,
requestedChildId,
boundChildren,
},
);
}
}
export class NotFoundError extends ApplicationError {
readonly type = "not_found" as const;
readonly statusCode = 404;
constructor(resource: string, id: string) {
super(`${resource} not found: ${id}`, "BFF_PARENT_NOT_FOUND", {
resource,
id,
});
}
}
export class ConflictError extends ApplicationError {
readonly type = "conflict" as const;
readonly statusCode = 409;
constructor(message: string, details?: ErrorDetails) {
super(message, "BFF_PARENT_CONFLICT", details);
}
}
export class BusinessError extends ApplicationError {
readonly type = "business" as const;
readonly statusCode = 422;
constructor(message: string, details?: ErrorDetails) {
super(message, "BFF_PARENT_BUSINESS_ERROR", details);
}
}
/**
* 下游服务返回非 ok 或 gRPC rejected。
*/
export class BadGatewayError extends ApplicationError {
readonly type = "bad_gateway" as const;
readonly statusCode = 502;
constructor(message: string, details?: ErrorDetails) {
super(message, "BFF_PARENT_BAD_GATEWAY", details);
}
}
/**
* 下游调用超时。
*/
export class GatewayTimeoutError extends ApplicationError {
readonly type = "gateway_timeout" as const;
readonly statusCode = 504;
constructor(message: string, details?: ErrorDetails) {
super(message, "BFF_PARENT_GATEWAY_TIMEOUT", details);
}
}
/**
* 熔断器开启P6 opossum 熔断器触发)。
*/
export class ServiceUnavailableError extends ApplicationError {
readonly type = "service_unavailable" as const;
readonly statusCode = 503;
constructor(message: string, details?: ErrorDetails) {
super(message, "BFF_PARENT_SERVICE_UNAVAILABLE", details);
}
}
export class InternalError extends ApplicationError {
readonly type = "internal" as const;
readonly statusCode = 500;
constructor(message: string, details?: ErrorDetails) {
super(message, "BFF_PARENT_INTERNAL_ERROR", details);
}
}