Files
threetwo-metadata-service/README_SCHEMA_STITCHING.md
2026-03-04 23:36:10 -05:00

9.6 KiB

GraphQL Schema Stitching - Unified Gateway

This service now implements GraphQL Schema Stitching to combine multiple GraphQL schemas into a single unified endpoint.

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Client Application                        │
└────────────────────────┬────────────────────────────────────┘
                         │
                         │ Single GraphQL Endpoint
                         ▼
┌─────────────────────────────────────────────────────────────┐
│          API Gateway (port 3080)                             │
│          /graphql endpoint                                   │
└────────────────────────┬────────────────────────────────────┘
                         │
                         │ Moleculer RPC
                         ▼
┌─────────────────────────────────────────────────────────────┐
│          Gateway Service (Schema Stitching)                  │
│          - Combines local + remote schemas                   │
│          - Routes queries to appropriate service             │
└────────┬────────────────────────────────────┬───────────────┘
         │                                    │
         │ Local Schema                       │ Remote Schema
         ▼                                    ▼
┌────────────────────┐              ┌────────────────────────┐
│  Local Services    │              │  Remote GraphQL Server │
│  - ComicVine       │              │  (port 3000)           │
│  - Metron          │              │  - Core Service        │
│  - Metadata        │              │  - Other queries       │
└────────────────────┘              └────────────────────────┘

What is Schema Stitching?

Schema stitching combines multiple GraphQL schemas into a single unified schema. This allows you to:

  1. Query multiple services through a single endpoint
  2. Combine data from different sources in one request
  3. Maintain service independence while providing a unified API
  4. Gradually migrate services without breaking existing clients

Configuration

Environment Variables

Set the remote GraphQL server URL:

export REMOTE_GRAPHQL_URL="http://localhost:3000/graphql"

If not set, it defaults to http://localhost:3000/graphql.

Service Files

How It Works

1. Schema Introspection

On startup, the gateway service:

  1. Introspects the remote GraphQL server at port 3000
  2. Builds a client schema from the introspection result
  3. Creates a local executable schema from the metadata service
  4. Stitches both schemas together

2. Query Routing

When a query is received:

  1. The gateway analyzes the query
  2. Routes local queries (ComicVine, Metron) to local resolvers
  3. Routes remote queries to the remote GraphQL server
  4. Combines results if the query spans both schemas

3. Fallback Behavior

If the remote server is unavailable:

  • The gateway starts with local schema only
  • Logs a warning about remote unavailability
  • Continues to serve local queries normally
  • Remote queries will fail gracefully

Usage

Starting the Service

npm run dev

The unified GraphQL endpoint will be available at: http://localhost:3080/graphql

Example: Local Query (Metadata Service)

query SearchComicVine {
  searchComicVine(input: { 
    query: "Batman", 
    resources: "volume", 
    limit: 5 
  }) {
    number_of_total_results
    results {
      id
      name
      start_year
    }
  }
}

Example: Remote Query (Core Service on port 3000)

Assuming your remote server has queries like getUser, getComics, etc.:

query GetUser {
  getUser(id: "123") {
    id
    username
    email
  }
}

Example: Combined Query (Both Services)

query CombinedQuery {
  # Local metadata service
  searchComicVine(input: { 
    query: "Batman", 
    resources: "volume", 
    limit: 3 
  }) {
    results {
      id
      name
    }
  }
  
  # Remote core service
  getUser(id: "123") {
    id
    username
  }
}

Benefits

1. Single Endpoint

  • Clients only need to know about one GraphQL endpoint
  • Simplifies frontend configuration
  • Easier to manage authentication/authorization

2. Flexible Queries

  • Query data from multiple services in one request
  • Reduce network round trips
  • Better performance for complex data requirements

3. Service Independence

  • Each service maintains its own schema
  • Services can be developed and deployed independently
  • No tight coupling between services

4. Gradual Migration

  • Add new services without breaking existing clients
  • Migrate queries between services transparently
  • Maintain backward compatibility

Monitoring & Debugging

Logs

The gateway service logs important events:

[GATEWAY] Initializing Apollo Gateway with Schema Stitching...
[GATEWAY] Attempting to introspect remote schema at http://localhost:3000/graphql
[GATEWAY] Successfully introspected remote schema
[GATEWAY] Stitching local and remote schemas together...
[GATEWAY] Schema stitching completed successfully
[GATEWAY] Apollo Gateway Server started successfully

Introspection

Query the stitched schema:

query IntrospectionQuery {
  __schema {
    queryType {
      name
      fields {
        name
        description
      }
    }
  }
}

Health Check

Check gateway status:

query GetGatewayInfo {
  __typename
}

Troubleshooting

Remote Server Unavailable

Symptom: Warning logs about remote schema introspection failure

Solution:

  1. Ensure the remote server is running on port 3000
  2. Check the REMOTE_GRAPHQL_URL environment variable
  3. Verify network connectivity
  4. The gateway will continue with local schema only

Query Routing Issues

Symptom: Queries to remote service fail or return null

Solution:

  1. Check that the remote server is responding
  2. Verify the query syntax matches the remote schema
  3. Use introspection to see available fields
  4. Check gateway logs for routing errors

Type Conflicts

Symptom: Errors about duplicate types or conflicting definitions

Solution:

  1. Ensure type names are unique across schemas
  2. Use schema transformation if needed
  3. Consider renaming conflicting types in one schema
  4. Check the mergeTypes configuration in gateway.service.ts

Advanced Configuration

Custom Executors

Modify the executor in gateway.service.ts to add:

  • Authentication headers
  • Request logging
  • Error handling
  • Caching

Schema Transformations

Use @graphql-tools/wrap to transform schemas:

  • Rename types
  • Filter fields
  • Add custom directives
  • Modify field arguments

Performance Optimization

Consider implementing:

  • DataLoader for batching requests
  • Response caching at the gateway level
  • Query complexity analysis to prevent expensive queries
  • Rate limiting per client or query type

Migration from Separate Endpoints

Before (Separate Endpoints)

// Frontend code
const metadataClient = new ApolloClient({
  uri: 'http://localhost:3080/graphql'
});

const coreClient = new ApolloClient({
  uri: 'http://localhost:3000/graphql'
});

After (Unified Gateway)

// Frontend code
const client = new ApolloClient({
  uri: 'http://localhost:3080/graphql'  // Single endpoint!
});

Comparison with Apollo Federation

Feature Schema Stitching Apollo Federation
Setup Complexity Moderate Higher
Service Independence Good Excellent
Type Merging Manual Automatic
Best For Existing services New microservices
Learning Curve Lower Higher

Support

For issues or questions:

  1. Check the gateway service logs
  2. Verify both servers are running
  3. Test each service independently
  4. Review the schema stitching configuration

Future Enhancements

  • Add authentication/authorization at gateway level
  • Implement DataLoader for batching
  • Add response caching
  • Implement query complexity analysis
  • Add rate limiting
  • Support for GraphQL subscriptions
  • Schema transformation utilities
  • Automated schema versioning