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:
- Query multiple services through a single endpoint
- Combine data from different sources in one request
- Maintain service independence while providing a unified API
- 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
services/gateway.service.ts- Gateway service with schema stitching logicservices/api.service.ts- API gateway routing to the gateway serviceservices/graphql.service.ts- Original local GraphQL service (still available)
How It Works
1. Schema Introspection
On startup, the gateway service:
- Introspects the remote GraphQL server at port 3000
- Builds a client schema from the introspection result
- Creates a local executable schema from the metadata service
- Stitches both schemas together
2. Query Routing
When a query is received:
- The gateway analyzes the query
- Routes local queries (ComicVine, Metron) to local resolvers
- Routes remote queries to the remote GraphQL server
- 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:
- Ensure the remote server is running on port 3000
- Check the
REMOTE_GRAPHQL_URLenvironment variable - Verify network connectivity
- The gateway will continue with local schema only
Query Routing Issues
Symptom: Queries to remote service fail or return null
Solution:
- Check that the remote server is responding
- Verify the query syntax matches the remote schema
- Use introspection to see available fields
- Check gateway logs for routing errors
Type Conflicts
Symptom: Errors about duplicate types or conflicting definitions
Solution:
- Ensure type names are unique across schemas
- Use schema transformation if needed
- Consider renaming conflicting types in one schema
- Check the
mergeTypesconfiguration ingateway.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 |
Related Documentation
Support
For issues or questions:
- Check the gateway service logs
- Verify both servers are running
- Test each service independently
- 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