@0xobelisk/graphql-server
Version:
Tookit for interacting with dubhe graphql server
488 lines (366 loc) • 15.1 kB
Markdown
# Dubhe GraphQL Server
The Dubhe GraphQL Server is an intelligent universal server adapter that automatically connects to databases created by `dubhe-indexer` and dynamically generates complete GraphQL APIs. Built on PostGraphile, it provides advanced filtering, real-time subscriptions, and comprehensive data access capabilities with zero configuration required.
## Installation
Install the package in your project:
```bash
pnpm install @0xobelisk/graphql-server
```
Or install globally for CLI usage:
```bash
npm install -g @0xobelisk/graphql-server
```
## Requirements
- Node.js 22.0.0+
- PostgreSQL database (managed by dubhe-indexer)
- TypeScript 5.0+
## Quick Start
### Using the CLI
The server provides a comprehensive CLI interface for configuration:
```bash
# Start with default configuration
dubhe-graphql-server start
# Start with custom configuration
dubhe-graphql-server start --port 4000 --database-url postgres://user:pass@localhost:5432/db
# Development mode with debug logging
dubhe-graphql-server start --debug --enable-metrics
# Production mode
dubhe-graphql-server start --env production --no-cors
```
### CLI Options
All configuration can be managed through CLI arguments or environment variables:
| Option | Environment Variable | Default | Description |
| --------------------------- | ------------------------- | ------------------------------------------------------ | ----------------------------------- |
| `--port, -p` | `PORT` | `4000` | Server port |
| `--database-url, -d` | `DATABASE_URL` | `postgres://postgres:postgres@127.0.0.1:5432/postgres` | Database connection URL |
| `--schema, -s` | `PG_SCHEMA` | `public` | PostgreSQL schema name |
| `--endpoint, -e` | `GRAPHQL_ENDPOINT` | `/graphql` | GraphQL endpoint path |
| `--cors` | `ENABLE_CORS` | `true` | Enable CORS |
| `--subscriptions` | `ENABLE_SUBSCRIPTIONS` | `true` | Enable GraphQL subscriptions |
| `--env` | `NODE_ENV` | `development` | Environment mode |
| `--debug` | `DEBUG` | `false` | Enable debug mode (verbose logging) |
| `--query-timeout` | `QUERY_TIMEOUT` | `30000` | GraphQL query timeout (ms) |
| `--max-connections` | `MAX_CONNECTIONS` | `1000` | Maximum database connections |
| `--heartbeat-interval` | `HEARTBEAT_INTERVAL` | `30000` | WebSocket heartbeat interval (ms) |
| `--enable-metrics` | `ENABLE_METRICS` | `false` | Enable performance metrics |
| `--enable-live-queries` | `ENABLE_LIVE_QUERIES` | `true` | Enable GraphQL live queries |
| `--enable-pg-subscriptions` | `ENABLE_PG_SUBSCRIPTIONS` | `true` | Enable PostgreSQL subscriptions |
| `--enable-native-websocket` | `ENABLE_NATIVE_WEBSOCKET` | `true` | Enable native WebSocket support |
| `--realtime-port` | `REALTIME_PORT` | `undefined` | Realtime WebSocket port |
### Environment Configuration (Alternative)
You can also use a `.env` file instead of CLI arguments:
```env
# Database configuration (connect to dubhe-indexer database)
DATABASE_URL=postgres://username:password@localhost:5432/sui_indexer_db
# Server configuration
PORT=4000
NODE_ENV=development
# GraphQL configuration
GRAPHQL_ENDPOINT=/graphql
PG_SCHEMA=public
# Feature toggles
ENABLE_CORS=true
ENABLE_SUBSCRIPTIONS=true
# Performance settings
QUERY_TIMEOUT=30000
MAX_CONNECTIONS=1000
HEARTBEAT_INTERVAL=30000
# Debug and monitoring
DEBUG=false
ENABLE_METRICS=false
# Subscription capabilities
ENABLE_LIVE_QUERIES=true
ENABLE_PG_SUBSCRIPTIONS=true
ENABLE_NATIVE_WEBSOCKET=true
REALTIME_PORT=4001
```
## Core Features
### Intelligent Database Adaptation
The server automatically scans and adapts to your database structure:
- **Dynamic Scanning**: Automatically discovers all tables created by `dubhe-indexer`
- **PostGraphile Powered**: Generates GraphQL APIs based on database schema
- **Zero Configuration**: No manual schema definition required
- **Real-time Schema Updates**: Automatically adapts to database changes
### Plugin Architecture
The server uses a modular plugin architecture:
- **Database Introspector**: Scans and analyzes database table structures
- **Welcome Page Generator**: Creates informative server homepage
- **PostGraphile Configuration**: Manages GraphQL API generation
- **Subscription Manager**: Handles real-time WebSocket connections
- **Enhanced Server Manager**: Manages HTTP and WebSocket servers
### Advanced Filtering
The server provides comprehensive filtering capabilities through the `postgraphile-plugin-connection-filter` plugin:
- **Rich Operators**: Supports 20+ filtering operators (eq, gt, lt, in, like, etc.)
- **Logical Combinations**: AND, OR, NOT operations for complex queries
- **Type-aware Filtering**: Automatic operator selection based on field types
- **Case-insensitive Search**: Text search with case sensitivity options
- **Null Handling**: Explicit null and not-null filtering
```graphql
# Basic filtering
query GetHighValueAccounts {
accounts(filter: { balance: { gt: "1000" } }) {
nodes {
assetId
account
balance
}
}
}
# Complex logical combinations
query GetComplexFilteredAccounts {
accounts(
filter: {
and: [
{ or: [{ balance: { gt: "1000" } }, { assetId: { like: "%special%" } }] }
{ not: { account: { includesInsensitive: "test" } } }
]
}
) {
nodes {
assetId
account
balance
}
}
}
```
### Real-time Subscriptions
Advanced WebSocket support powered by PostgreSQL LISTEN/NOTIFY:
- **Live Queries**: PostGraphile Live Queries for real-time data updates
- **PostgreSQL Subscriptions**: Native database change notifications
- **WebSocket Transport**: Unified WebSocket endpoint for all subscriptions
- **Connection Management**: Automatic heartbeat and connection recovery
- **Universal Subscriptions**: Custom subscription plugin for store tables
```graphql
# Subscribe to specific table changes
subscription OnAccountChanges {
accounts(first: 10, orderBy: [CREATED_AT_TIMESTAMP_DESC]) {
nodes {
assetId
account
balance
}
}
}
```
## Access Endpoints
After starting the server, you can access:
- **Welcome Page**: `http://localhost:4000/` - Server information and table overview
- **GraphQL Playground**: `http://localhost:4000/playground` - Modern GraphQL IDE
- **GraphQL API**: `http://localhost:4000/graphql` - API endpoint
- **Health Check**: `http://localhost:4000/health` - Server health status
- **Subscription Config**: `http://localhost:4000/subscription-config` - Client configuration
- **WebSocket**: `ws://localhost:4000/graphql` - Subscription endpoint
## Deployment
### Development
```bash
# Start development server
pnpm install
dubhe-graphql-server start --debug --enable-metrics
```
### Production
```bash
# Build the project
pnpm install
pnpm build
# Start production server
dubhe-graphql-server start \
--env production \
--max-connections 500 \
--query-timeout 60000
```
### Docker Deployment
Create a `docker-compose.yml`:
```yaml
version: '3.8'
services:
graphql-server:
image: node:22-alpine
working_dir: /app
command: npx @0xobelisk/graphql-server start
ports:
- '4000:4000'
environment:
- DATABASE_URL=postgres://user:password@postgres:5432/sui_indexer
- PORT=4000
- ENABLE_SUBSCRIPTIONS=true
- NODE_ENV=production
depends_on:
- postgres
postgres:
image: postgres:15
environment:
- POSTGRES_DB=sui_indexer
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
```
### Production Configuration
```bash
# CLI approach for production
dubhe-graphql-server start \
--env production \
--database-url "postgres://user:password@prod-db:5432/sui_indexer" \
--port 4000 \
--no-cors \
--max-connections 500 \
--query-timeout 60000 \
--enable-metrics
```
## Configuration
### Server Configuration Interface
The server uses a comprehensive configuration interface:
```typescript
interface ServerConfig {
// Basic server configuration
port: string;
databaseUrl: string;
schema: string;
endpoint: string;
cors: boolean;
subscriptions: boolean;
env: string;
// Debug configuration
debug: boolean;
// Performance configuration
queryTimeout: number;
maxConnections: number;
heartbeatInterval: number;
enableMetrics: boolean;
// Subscription capabilities
enableLiveQueries: boolean;
enablePgSubscriptions: boolean;
enableNativeWebSocket: boolean;
realtimePort?: number;
// Internal debug flags
debugNotifications: boolean;
}
```
### Database Permissions
Set up proper database permissions:
```sql
-- Create read-only user
CREATE USER graphql_readonly WITH PASSWORD 'secure_password';
-- Grant query permissions
GRANT CONNECT ON DATABASE sui_indexer TO graphql_readonly;
GRANT USAGE ON SCHEMA public TO graphql_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO graphql_readonly;
-- If write permissions needed
GRANT INSERT, UPDATE, DELETE ON specific_tables TO graphql_readonly;
```
## Monitoring and Debugging
### Health Checks
The server provides comprehensive monitoring endpoints:
- `http://localhost:4000/` - Welcome page with system information
- `http://localhost:4000/health` - Health check endpoint with subscription status
- `http://localhost:4000/subscription-config` - Client configuration for subscriptions
- `http://localhost:4000/subscription-docs` - Configuration documentation
- `http://localhost:4000/playground` - Enhanced GraphQL Playground
### Debug Mode
Enable debug mode for detailed logging:
```bash
# Enable debug mode with verbose logging
dubhe-graphql-server start --debug
# Enable performance metrics
dubhe-graphql-server start --enable-metrics
# Combine both for comprehensive monitoring
dubhe-graphql-server start --debug --enable-metrics
```
### Performance Monitoring
The server includes built-in performance monitoring:
- **Query Logging**: SQL query logs (controlled by `--debug`)
- **Request Metrics**: HTTP request timing and status
- **Connection Monitoring**: Database connection pool status
- **WebSocket Metrics**: Subscription connection statistics
## Troubleshooting
### Common Issues
1. **Database Connection Failed**
```
Solution: Check DATABASE_URL and database service status
```
2. **Table Scan Empty**
```
Solution: Ensure dubhe-indexer is running and has created tables
```
3. **Schema Generation Failed**
```
Solution: Check if table_fields table exists and has data
```
4. **WebSocket Connection Failed**
```
Solution: Check firewall settings and ENABLE_SUBSCRIPTIONS configuration
```
### Debug Commands
```bash
# View generated schema
ls -la *.graphql
# Check database connection
psql $DATABASE_URL -c "SELECT version();"
# Test GraphQL endpoint
curl -X POST http://localhost:4000/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ __schema { types { name } } }"}'
```
## Architecture
### System Architecture
```
dubhe-indexer database
↓
[Database Introspector] ← Scans table structures
↓
[PostGraphile] ← Generates GraphQL schema
↓
[Enhanced Server Manager] ← Manages HTTP/WebSocket
↓
[GraphQL API + WebSocket] ← Unified endpoint
```
### Core Components
1. **Database Introspector**:
- Scans `store_*` tables and system tables
- Reads field metadata from `table_fields`
- Monitors database connection health
2. **PostGraphile Engine**:
- Generates GraphQL schema from database structure
- Provides CRUD operations and filtering
- Handles connection pooling and query optimization
3. **Subscription Manager**:
- Manages PostgreSQL LISTEN/NOTIFY subscriptions
- Handles WebSocket connections and heartbeat
- Provides universal subscriptions for all store tables
4. **Enhanced Server Manager**:
- Express.js server with modular middleware
- Welcome page, health checks, and documentation
- GraphQL Playground integration
### Supported Table Types
1. **System Tables**: Auto-detected indexer tables
- `table_fields` - Table structure metadata (stores field definitions for dynamic tables)
2. **Dynamic Tables**: Contract-defined tables
- `store_*` - Tables created from your `dubhe.config.json` (e.g., `store_component0`, `store_component1`)
- Each table includes system fields: `created_at_timestamp_ms`, `updated_at_timestamp_ms`, `is_deleted`
- Automatically generate GraphQL types and operations
## Best Practices
### Development
1. **Use debug mode** for development: `--debug --enable-metrics`
2. **Monitor welcome page** for table discovery status
3. **Use GraphQL Playground** for query development and testing
4. **Check health endpoint** regularly for system status
### Production
1. **Configure connection pooling**: Use `--max-connections` appropriately
2. **Set proper timeouts**: Configure `--query-timeout` based on usage
3. **Enable security**: Use `--no-cors` or configure specific origins
4. **Monitor performance**: Enable `--enable-metrics` for production monitoring
5. **Use read-only database user** for security
6. **Implement rate limiting** at the reverse proxy level
7. **Set up proper logging** and monitoring infrastructure
### Database Optimization
1. **Create indexes** on frequently queried columns
2. **Use connection pooling** efficiently
3. **Monitor subscription connections** to prevent resource exhaustion
4. **Configure PostgreSQL** for optimal performance with LISTEN/NOTIFY
### Integration
1. **Start dubhe-indexer first** before GraphQL server
2. **Ensure database schema compatibility** between services
3. **Use environment-specific configurations** for different stages
4. **Implement proper error handling** in client applications