-
Notifications
You must be signed in to change notification settings - Fork 0
Backend Architecture Routing System Routing System
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
This document describes the InfraWatch routing system built with Express. It explains the modular router architecture, route organization by domain, and the endpoint structure for network, RPC, validators, epoch, and alerts. It also documents middleware usage, parameter validation, error handling, and how routes integrate with the service and data layers.
The backend exposes a single API base path and mounts sub-routers grouped by domain. Each route file encapsulates endpoints for its domain and delegates data access to services and the data layer.
graph TB
A["Express App<br/>server.js"] --> B["Routes Aggregator<br/>routes/index.js"]
B --> C["Network Routes<br/>routes/network.js"]
B --> D["RPC Routes<br/>routes/rpc.js"]
B --> E["Validators Routes<br/>routes/validators.js"]
B --> F["Epoch Routes<br/>routes/epoch.js"]
B --> G["Alerts Routes<br/>routes/alerts.js"]
C --> H["Queries (DB)<br/>models/queries.js"]
C --> I["Redis Cache<br/>models/redis.js"]
D --> H
D --> I
D --> J["RPC Prober<br/>services/rpcProber.js"]
E --> H
E --> I
E --> K["Validators.app Client<br/>services/validatorsApp.js"]
F --> I
F --> L["Solana RPC Client<br/>services/solanaRpc.js"]
G --> H
Diagram sources
- server.js:71-72
- routes/index.js:16-21
- routes/network.js:1-135
- routes/rpc.js:1-135
- routes/validators.js:1-112
- routes/epoch.js:1-62
- routes/alerts.js:1-46
- models/queries.js:1-200
- models/redis.js:1-161
- services/rpcProber.js:1-200
- services/validatorsApp.js:1-200
- services/solanaRpc.js:1-200
Section sources
- server.js:71-79
- routes/index.js:16-21
- Express app and middleware pipeline: Helmet, compression, CORS, body parsing, health check, global error handler, and 404 handling.
- Routes aggregator mounts domain-specific routers under /api.
- Domain routers implement endpoints with cache-first patterns, parameter validation, and error propagation to the global handler.
- Services encapsulate external integrations (RPC probing, Validators.app, Solana RPC) and internal data access via queries.
Section sources
- server.js:52-79
- routes/index.js:16-21
- middleware/errorHandler.js:44-127
The routing system follows a modular, layered architecture:
- Entry point initializes middleware and routes.
- Sub-routers define domain endpoints.
- Endpoints call services and the data layer.
- Redis cache is used for fast reads; database is used as fallback.
- Global error handler standardizes error responses.
sequenceDiagram
participant Client as "Client"
participant App as "Express App<br/>server.js"
participant Router as "Routes Aggregator<br/>routes/index.js"
participant Net as "Network Router<br/>routes/network.js"
participant Q as "Queries<br/>models/queries.js"
participant R as "Redis<br/>models/redis.js"
Client->>App : GET /api/network/current
App->>Router : route to /network
Router->>Net : dispatch GET /current
Net->>R : getCache(NETWORK_CURRENT)
alt cache hit
R-->>Net : cached data
Net-->>Client : JSON response
else cache miss
Net->>Q : getLatestNetworkSnapshot()
Q-->>Net : snapshot
Net-->>Client : JSON response
end
Diagram sources
- server.js:71-72
- routes/index.js:17
- routes/network.js:17-79
- models/redis.js:75-90
- models/queries.js:54-62
Endpoints:
-
GET /api/network/current
- Purpose: Returns current network status.
- Cache-first: Attempts Redis; falls back to database.
- Validation: None.
- Authentication: Not required.
- Response: JSON with status, TPS, slot metrics, epoch info, counts, and timestamp.
- Error handling: 503 on startup/unavailable; global handler for unexpected errors.
-
GET /api/network/history?range=1h|24h|7d
- Purpose: Returns historical network snapshots for charts.
- Cache-first: Attempts Redis; falls back to database.
- Validation: Validates range parameter against allowed values.
- Authentication: Not required.
- Response: Array of snapshots.
- Error handling: Returns empty array on DB failure; logs cache failures as warnings.
flowchart TD
Start(["GET /api/network/current"]) --> TryCache["Try Redis cache"]
TryCache --> CacheHit{"Cache hit?"}
CacheHit --> |Yes| ReturnCached["Return cached JSON"]
CacheHit --> |No| QueryDB["Query latest snapshot"]
QueryDB --> DBSuccess{"DB success?"}
DBSuccess --> |No| Return503["Return 503 JSON"]
DBSuccess --> |Yes| ReturnJSON["Return snapshot JSON"]
ReturnCached --> End(["End"])
ReturnJSON --> End
Return503 --> End
Diagram sources
- routes/network.js:17-79
- models/redis.js:75-90
- models/queries.js:54-62
Section sources
- routes/network.js:17-79
- routes/network.js:85-132
- models/cacheKeys.js:8-11
- models/redis.js:75-112
Endpoints:
-
GET /api/rpc/status
- Purpose: Returns current provider statuses with rolling statistics and a recommendation.
- Cache-first: Attempts Redis; falls back to database.
- Rolling stats: Merges latest DB results with stats computed by the prober service.
- Recommendation: Best provider derived from rolling stats.
- Response: Providers array with stats, recommendation, and timestamp.
- Error handling: Returns empty array on DB failure; global handler for unexpected errors.
-
GET /api/rpc/:provider/history?range=1h|24h|7d
- Purpose: Returns health history for a specific provider.
- Validation: Validates range parameter.
- Response: Transformed array of health checks.
- Error handling: Returns empty array on DB failure; global handler for unexpected errors.
sequenceDiagram
participant Client as "Client"
participant RPC as "RPC Router<br/>routes/rpc.js"
participant R as "Redis<br/>models/redis.js"
participant Q as "Queries<br/>models/queries.js"
participant P as "RPC Prober<br/>services/rpcProber.js"
Client->>RPC : GET /api/rpc/status
RPC->>R : getCache(RPC_LATEST)
alt cache hit
R-->>RPC : providers
else cache miss
RPC->>Q : getRpcLatestByProvider()
Q-->>RPC : providers
end
RPC->>P : getAllProviderStats()
P-->>RPC : stats
RPC->>P : getBestProvider()
P-->>RPC : best
RPC-->>Client : {providers, recommendation, timestamp}
Diagram sources
- routes/rpc.js:17-88
- models/redis.js:75-90
- models/queries.js:124-132
- services/rpcProber.js:140-180
Section sources
- routes/rpc.js:17-88
- routes/rpc.js:94-132
- services/rpcProber.js:11-63
- services/rpcProber.js:140-180
- models/cacheKeys.js:9
- models/redis.js:75-112
Endpoints:
-
GET /api/validators/top?limit=1..100
- Purpose: Returns top validators sorted by score.
- Cache-first: Attempts Redis; falls back to database.
- Validation: Clamps limit between 1 and 100.
- Response: Array of validators.
- Error handling: Returns empty array on DB failure; global handler for unexpected errors.
-
GET /api/validators/:votePubkey
- Purpose: Returns a single validator’s details.
- Validation: Requires votePubkey parameter.
- Priority: Try Redis; then Validators.app; finally database.
- Response: Validator object.
- Error handling: 404 if not found; global handler for unexpected errors.
flowchart TD
StartV(["GET /api/validators/:votePubkey"]) --> CheckParam["Check votePubkey param"]
CheckParam --> ParamOK{"Provided?"}
ParamOK --> |No| Return400["Return 400 JSON"]
ParamOK --> |Yes| TryCacheV["Try Redis cache by votePubkey"]
TryCacheV --> CacheHitV{"Cache hit?"}
CacheHitV --> |Yes| ReturnCachedV["Return cached validator"]
CacheHitV --> |No| FetchVA["Fetch from Validators.app"]
FetchVA --> FetchOK{"Fetched?"}
FetchOK --> |Yes| CacheSet["Cache result"] --> ReturnVA["Return validator"]
FetchOK --> |No| QueryDBV["Query DB by pubkey"]
QueryDBV --> DBOK{"Found?"}
DBOK --> |No| Return404["Return 404 JSON"]
DBOK --> |Yes| CacheSet2["Cache result"] --> ReturnDB["Return validator"]
Return400 --> EndV(["End"])
Return404 --> EndV
ReturnCachedV --> EndV
ReturnVA --> EndV
ReturnDB --> EndV
Diagram sources
- routes/validators.js:52-109
- services/validatorsApp.js:186-200
- models/queries.js:1-200
- models/cacheKeys.js:25
Section sources
- routes/validators.js:17-46
- routes/validators.js:52-109
- services/validatorsApp.js:115-149
- models/cacheKeys.js:11
Endpoint:
- GET /api/epoch/current
- Purpose: Returns current epoch information.
- Cache-first: Attempts Redis; falls back to Solana RPC client.
- Response: Epoch info with progress and ETA.
- Error handling: Global handler for unexpected errors.
sequenceDiagram
participant Client as "Client"
participant Epoch as "Epoch Router<br/>routes/epoch.js"
participant R as "Redis<br/>models/redis.js"
participant S as "Solana RPC<br/>services/solanaRpc.js"
Client->>Epoch : GET /api/epoch/current
Epoch->>R : getCache(EPOCH_INFO)
alt cache hit
R-->>Epoch : epochInfo
Epoch-->>Client : JSON with epoch metrics
else cache miss
Epoch->>S : getEpochInfo()
S-->>Epoch : epochInfo
Epoch->>R : setCache(EPOCH_INFO, epochInfo, TTL)
Epoch-->>Client : JSON with epoch metrics
end
Diagram sources
- routes/epoch.js:16-59
- models/redis.js:75-112
- services/solanaRpc.js:124-156
- models/cacheKeys.js:10
Section sources
- routes/epoch.js:16-59
- services/solanaRpc.js:124-156
- models/cacheKeys.js:10
Endpoint:
- GET /api/alerts?limit=1..100
- Purpose: Returns recent alerts.
- Validation: Clamps limit between 1 and 100.
- Response: Array of alerts with normalized fields.
- Error handling: Returns empty array on DB failure; global handler for unexpected errors.
Section sources
- routes/alerts.js:14-43
- models/queries.js:1-200
- The routes aggregator mounts sub-routers at /api/network, /api/rpc, /api/validators, /api/epoch, and /api/alerts.
- Nested patterns:
- RPC: /:provider/history uses a path parameter.
- Validators: /:votePubkey uses a path parameter.
- Route composition:
- Each router composes service and data-layer calls.
- Middleware runs before route handlers.
Section sources
- routes/index.js:16-21
- routes/rpc.js:94
- routes/validators.js:54
- Express app depends on:
- Routes aggregator.
- Global error handler and not-found handler.
- WebSocket setup.
- Routes depend on:
- Queries for database access.
- Redis for caching.
- Services for external integrations.
- Services depend on:
- Configuration for endpoints and keys.
- External APIs and Solana web3 connection.
graph LR
App["server.js"] --> RoutesIdx["routes/index.js"]
RoutesIdx --> Net["routes/network.js"]
RoutesIdx --> RPC["routes/rpc.js"]
RoutesIdx --> Val["routes/validators.js"]
RoutesIdx --> Epoch["routes/epoch.js"]
RoutesIdx --> Alerts["routes/alerts.js"]
Net --> Q["models/queries.js"]
Net --> R["models/redis.js"]
RPC --> Q
RPC --> R
RPC --> Prober["services/rpcProber.js"]
Val --> Q
Val --> R
Val --> VApp["services/validatorsApp.js"]
Epoch --> R
Epoch --> SRPC["services/solanaRpc.js"]
Alerts --> Q
Diagram sources
- server.js:23-27
- routes/index.js:10-14
- routes/network.js:8-10
- routes/rpc.js:8-11
- routes/validators.js:8-11
- routes/epoch.js:8-10
- routes/alerts.js:8
Section sources
- server.js:23-27
- routes/index.js:10-14
- Caching strategy:
- Redis cache keys are centralized and TTLs are tuned per domain.
- Cache-first reads reduce database and external API load.
- Parameter validation:
- Range parameters validated to avoid invalid queries.
- Limits clamped to safe ranges to prevent heavy loads.
- Graceful degradation:
- On Redis failure, routes fall back to database or external services.
- On DB failure, routes often return empty arrays or minimal responses.
- External service reliability:
- RPC prober and Validators.app clients include timeouts and rate limiting.
- Compression and security:
- Compression and Helmet applied at the app level to optimize transport and security.
Section sources
- models/cacheKeys.js:42-48
- routes/network.js:87-96
- routes/rpc.js:99-106
- routes/validators.js:19-20
- routes/alerts.js:16-17
- models/redis.js:75-112
- services/rpcProber.js:75-134
- services/validatorsApp.js:115-149
- server.js:52-59
- Health check:
- Endpoint: GET /api/health.
- Useful for verifying server readiness.
- Error handling:
- Global handler standardizes responses and logs details.
- Known error classes: validation, not found, unauthorized, forbidden.
- Common issues:
- Redis unavailable: routes continue with DB fallback; cache writes are non-fatal.
- Database unavailable: routes return empty arrays or 503 where appropriate.
- Missing parameters: routes return 400 with validation messages.
- Unknown routes: 404 handled centrally.
Section sources
- server.js:62-69
- middleware/errorHandler.js:44-127
- routes/network.js:48-61
- routes/validators.js:56-60
- routes/rpc.js:100-106
- routes/network.js:114-117
- routes/alerts.js:22-25
The InfraWatch routing system is modular, resilient, and performance-conscious. Each domain router encapsulates its endpoints, enforces parameter validation, and leverages Redis caching with robust database and external service fallbacks. The global error handler ensures consistent error responses, while the app-level middleware provides security and performance enhancements. This design supports scalable growth and maintainability across network, RPC, validators, epoch, and alerts domains.