GraphQL API Overview
GraphQL API Overview
Section titled “GraphQL API Overview”The Banyan Platform automatically generates a complete GraphQL schema from all service contracts, with permission-based filtering for enhanced security.
Key Features
Section titled “Key Features”Automatic Schema Generation
Section titled “Automatic Schema Generation”Every service contract automatically generates GraphQL types:
- Commands generate mutations with input types
- Queries generate query fields with input types
- Events generate subscription types
- Permissions filter schema based on user access
- Validation enforced from contract definitions
Permission-Based Schema Filtering
Section titled “Permission-Based Schema Filtering”The schema dynamically filters based on user permissions. Users only see operations they can perform:
# User with permissions: ["users:read"]type Query { getUser(input: GetUserInput!): UserResult listUsers(input: ListUsersInput!): ListUsersResult}# No mutations visible (no users:create permission)# User with permissions: ["users:read", "users:create", "users:update"]type Query { getUser(input: GetUserInput!): UserResult listUsers(input: ListUsersInput!): ListUsersResult}
type Mutation { createUser(input: CreateUserInput!): CreateUserResult updateUser(input: UpdateUserInput!): UpdateUserResult}# Still no deleteUser (no users:delete permission)This provides:
- Better security - Users can’t discover unauthorized operations
- Cleaner API - Schema shows only relevant operations
- Developer experience - Auto-completion shows available actions
GraphQL Endpoint
Section titled “GraphQL Endpoint”Interactive Playground
Section titled “Interactive Playground”Access the GraphiQL interactive playground:
http://localhost:3003/graphqlFeatures:
- Auto-completion and syntax highlighting
- Interactive documentation explorer
- Query history
- Real-time validation
- Permission-aware schema
GraphQL Endpoint
Section titled “GraphQL Endpoint”All GraphQL requests go to:
POST http://localhost:3003/graphqlContent-Type: application/jsonAuthorization: Bearer <token>Request body:
{ "query": "query GetUser($userId: String!) { ... }", "variables": { "userId": "user-123" }, "operationName": "GetUser"}Schema Generation Rules
Section titled “Schema Generation Rules”Commands → Mutations
Section titled “Commands → Mutations”Commands represent state-changing operations:
@Command({ description: 'Create a new user', permissions: ['users:create']})export class CreateUserCommand { email!: string; firstName!: string; lastName?: string;}Generates:
input CreateUserInput { email: String! firstName: String! lastName: String}
type CreateUserResult { userId: String! email: String! createdAt: String!}
type Mutation { createUser(input: CreateUserInput!): CreateUserResult}Queries → Query Fields
Section titled “Queries → Query Fields”Queries represent read operations:
@Query({ description: 'Get user by ID', permissions: ['users:read']})export class GetUserQuery { userId!: string;}Generates:
input GetUserInput { userId: String!}
type UserResult { userId: ID! email: String! firstName: String! lastName: String}
type Query { getUser(input: GetUserInput!): UserResult}Events → Subscriptions
Section titled “Events → Subscriptions”Events generate real-time subscriptions:
@DomainEvent('User.Events.UserCreated', { broadcast: true })export class UserCreatedEvent { userId!: string; email!: string; firstName!: string;}Generates:
type UserCreatedEvent { userId: String! email: String! firstName: String! timestamp: String!}
type Subscription { userCreated: UserCreatedEvent}Type System
Section titled “Type System”Scalar Types
Section titled “Scalar Types”GraphQL scalars map to TypeScript types:
| GraphQL | TypeScript | Description |
|---|---|---|
String | string | UTF-8 text |
Int | number | 32-bit integer |
Float | number | Floating point |
Boolean | boolean | true/false |
ID | string | Unique identifier |
Input Types
Section titled “Input Types”Input types represent command/query parameters:
input CreateUserInput { email: String! # Required firstName: String! # Required lastName: String # Optional age: Int active: Boolean}Object Types
Section titled “Object Types”Object types represent results:
type UserResult { userId: ID! email: String! firstName: String! lastName: String createdAt: String! updatedAt: String}Lists represent collections:
type ListUsersResult { users: [UserResult!]! # Non-null list of non-null users totalCount: Int! page: Int! pageSize: Int!}Enums represent fixed sets of values:
enum UserRole { ADMIN USER GUEST}
input CreateUserInput { role: UserRole!}Operations
Section titled “Operations”Queries (Read Operations)
Section titled “Queries (Read Operations)”Fetch data without side effects:
query GetUser { getUser(input: { userId: "user-123" }) { userId email firstName }}Mutations (Write Operations)
Section titled “Mutations (Write Operations)”Modify data:
mutation CreateUser { createUser(input: { email: "user@example.com" firstName: "John" lastName: "Doe" }) { userId email createdAt }}Subscriptions (Real-time Updates)
Section titled “Subscriptions (Real-time Updates)”Receive real-time events:
subscription OnUserCreated { userCreated { userId email firstName }}Authentication
Section titled “Authentication”All GraphQL requests require authentication (except public operations):
Production (JWT)
Section titled “Production (JWT)”POST /graphqlAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Content-Type: application/jsonDevelopment Mode
Section titled “Development Mode”For local development only:
POST /graphqlX-Dev-User-Id: dev-user-123X-Dev-Permissions: users:create,users:readContent-Type: application/jsonWARNING: Development mode bypasses all authentication. Never use in production.
Error Handling
Section titled “Error Handling”GraphQL errors follow a standard format:
{ "errors": [ { "message": "Validation failed", "locations": [{ "line": 2, "column": 3 }], "path": ["createUser"], "extensions": { "code": "VALIDATION_ERROR", "details": { "email": "Invalid email format" } } } ], "data": null}Common error codes:
VALIDATION_ERROR- Input validation failedPERMISSION_DENIED- Insufficient permissionsNOT_FOUND- Resource not foundINTERNAL_ERROR- Server error
Query Complexity Limits
Section titled “Query Complexity Limits”Queries are analyzed for complexity to prevent abuse:
Limits:
- Max depth: 10 levels
- Max fields: 100 per query
- Max complexity: 1000 points
Example - too complex:
query TooComplex { listUsers(input: { page: 1, pageSize: 100 }) { users { orders { items { product { reviews { user { orders { # Too deeply nested - rejected } } } } } } } }}Best Practices
Section titled “Best Practices”Request Only Needed Fields
Section titled “Request Only Needed Fields”✅ DO:
query GetUser { getUser(input: { userId: "123" }) { userId email }}❌ DON’T:
query GetUser { getUser(input: { userId: "123" }) { userId email firstName lastName address phoneNumber # Requesting unnecessary fields }}Use Fragments for Reusability
Section titled “Use Fragments for Reusability”fragment UserFields on UserResult { userId email firstName lastName}
query GetUser { getUser(input: { userId: "123" }) { ...UserFields }}
query ListUsers { listUsers(input: { page: 1 }) { users { ...UserFields } }}Use Variables for Dynamic Values
Section titled “Use Variables for Dynamic Values”✅ DO:
query GetUser($userId: String!) { getUser(input: { userId: $userId }) { userId email }}❌ DON’T:
query GetUser { getUser(input: { userId: "user-123" }) { userId email }}Avoid Deep Nesting
Section titled “Avoid Deep Nesting”Keep queries shallow for better performance:
✅ DO:
query GetUserOrders { getUser(input: { userId: "123" }) { userId } getUserOrders(input: { userId: "123" }) { orders { orderId } }}❌ DON’T:
query GetUserOrders { getUser(input: { userId: "123" }) { userId orders { items { product { reviews { # Too nested } } } } }}Advantages Over REST
Section titled “Advantages Over REST”Single Request for Multiple Resources
Section titled “Single Request for Multiple Resources”query GetUserDashboard { getUser(input: { userId: "123" }) { userId email } getUserSettings(input: { userId: "123" }) { theme notifications } getUserOrders(input: { userId: "123" }) { orders { orderId total } }}No Over-fetching or Under-fetching
Section titled “No Over-fetching or Under-fetching”Request exactly the fields you need:
query GetUserEmails { listUsers(input: { page: 1 }) { users { email # Only fetch emails } }}Strong Typing and Validation
Section titled “Strong Typing and Validation”Schema provides compile-time validation and IDE auto-completion.
Real-time Subscriptions
Section titled “Real-time Subscriptions”Built-in support for real-time updates:
subscription OnUserCreated { userCreated { userId email }}Next Steps
Section titled “Next Steps”- GraphQL Schema - Complete schema reference
- GraphQL Examples - Working code examples
- WebSocket API - Alternative for real-time
- Authentication - JWT tokens and permissions