HeliosDB GraphQL Interface
HeliosDB GraphQL Interface
A comprehensive GraphQL API layer for HeliosDB v3.0 with automatic schema generation, real-time subscriptions, and federation support.
Features
- Automatic Schema Generation: Generate GraphQL schemas from SQL table definitions
- CRUD Operations: Full Create, Read, Update, Delete support via GraphQL mutations
- Real-time Subscriptions: WebSocket-based subscriptions with CDC integration
- Advanced Filtering: Complex where clauses with AND/OR/NOT operators
- Sorting & Pagination: Cursor-based and offset-based pagination
- GraphQL Playground: Interactive API explorer for development
- Federation Support: Apollo Federation for microservices architecture
- Type Safety: Strongly-typed GraphQL schema with proper SQL type mappings
- Authentication: JWT-based authentication and role-based access control
- Rate Limiting: Configurable rate limiting per IP address
- Query Complexity: Protection against expensive queries
Quick Start
Basic Server
use heliosdb_graphql::{GraphQLServer, GraphQLConfigBuilder};
#[tokio::main]async fn main() -> anyhow::Result<()> { let config = GraphQLConfigBuilder::new() .bind_address("0.0.0.0:8080".parse()?) .playground(true) .introspection(true) .subscriptions(true) .build();
let server = GraphQLServer::new(config).await?; server.run().await?.wait().await?;
Ok(())}Schema Generation
Given a SQL table:
CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, created_at TIMESTAMP DEFAULT NOW());The following GraphQL schema is auto-generated:
type User { id: ID! name: String! email: String! createdAt: DateTime!}
type Query { user(id: ID!): User users( where: UserWhereInput orderBy: [UserOrderByInput!] skip: Int take: Int ): [User!]! usersCount(where: UserWhereInput): Int!}
type Mutation { createUser(data: UserCreateInput!): User! updateUser(id: ID!, data: UserUpdateInput!): User deleteUser(id: ID!): User}
type Subscription { userCreated: User! userUpdated: User! userDeleted: User!}Queries
Find by ID
query { user(id: "1") { id name email }}List with Filtering
query { users( where: { AND: [ { name: { contains: "John" } } { email: { endsWith: "@example.com" } } ] } orderBy: [{ createdAt: DESC }] take: 10 skip: 0 ) { id name email createdAt }}Count
query { usersCount(where: { name: { contains: "John" } })}Mutations
Create
mutation { createUser(data: { name: "John Doe" email: "john@example.com" }) { id name email }}Update
mutation { updateUser( id: "1" data: { name: "Jane Doe" } ) { id name email }}Delete
mutation { deleteUser(id: "1") { id name }}Subscriptions
Real-time Updates
subscription { userCreated { id name email }}
subscription { userUpdated { id name email }}
subscription { userDeleted { id }}Filtering
String Filters
input StringFilter { equals: String not: String in: [String!] notIn: [String!] contains: String startsWith: String endsWith: String mode: QueryMode # DEFAULT or INSENSITIVE}Numeric Filters
input IntFilter { equals: Int not: Int in: [Int!] notIn: [Int!] lt: Int lte: Int gt: Int gte: Int}DateTime Filters
input DateTimeFilter { equals: DateTime not: DateTime in: [DateTime!] notIn: [DateTime!] lt: DateTime lte: DateTime gt: DateTime gte: DateTime}Logical Operators
input UserWhereInput { name: StringFilter email: StringFilter AND: [UserWhereInput!] OR: [UserWhereInput!] NOT: UserWhereInput}Pagination
Offset-based
query { users(skip: 0, take: 10) { id name }}Cursor-based (Relay)
query { usersConnection(first: 10, after: "cursor123") { edges { cursor node { id name } } pageInfo { hasNextPage hasPreviousPage startCursor endCursor } }}Authentication
JWT Authentication
use heliosdb_graphql::auth::{TokenManager, Claims};
let manager = TokenManager::new("secret".to_string());let claims = Claims::new("user123".to_string(), vec!["admin".to_string()], 3600);let token = manager.generate_token(claims)?;Authorization Header
Authorization: Bearer <jwt-token>Federation
Entity Resolution
use heliosdb_graphql::federation::{FederationSupport, TableEntityResolver};
let federation = FederationSupport::new();let resolver = Arc::new(TableEntityResolver::new("users".to_string()));federation.register_resolver("User".to_string(), resolver).await;Federation Schema
extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"])
type User @key(fields: "id") { id: ID! name: String! email: String!}Configuration
use heliosdb_graphql::GraphQLConfigBuilder;use std::time::Duration;
let config = GraphQLConfigBuilder::new() .bind_address("0.0.0.0:8080".parse()?) .playground(true) .introspection(true) .max_depth(10) .max_complexity(100) .subscriptions(true) .federation(false) .request_timeout(Duration::from_secs(30)) .rate_limit(1000) // requests per minute .jwt_secret("your-secret".to_string()) .log_queries(true) .build();Type Mappings
| SQL Type | GraphQL Type |
|---|---|
| VARCHAR, TEXT | String |
| INTEGER, SERIAL | Int |
| BIGINT | String (to avoid precision loss) |
| FLOAT, DOUBLE | Float |
| NUMERIC, DECIMAL | Decimal |
| BOOLEAN | Boolean |
| UUID | UUID |
| JSON, JSONB | JSON |
| TIMESTAMP, DATE | DateTime |
| BYTEA, BLOB | Bytes |
Examples
See the examples/ directory for complete examples:
basic_server.rs- Basic GraphQL server setupsubscription_example.rs- Real-time subscriptions with CDC
Testing
cargo test -p heliosdb-graphqlIntegration with HeliosDB
The GraphQL interface integrates with:
- heliosdb-metadata: Table schema introspection
- heliosdb-compute: Query execution engine
- heliosdb-storage: Data access layer
- heliosdb-cdc: Change data capture for subscriptions
Performance
- Query caching with LRU cache
- DataLoader pattern for batch loading
- Query complexity analysis
- Rate limiting per IP
- Connection pooling
License
Apache-2.0