@llm-dev-ops/llm-marketplace-graphql-gateway
v1.1.1
Published
GraphQL API Gateway for LLM Marketplace
Maintainers
Readme
GraphQL API Gateway
Enterprise-grade GraphQL API Gateway for the LLM Marketplace platform. Provides a unified, type-safe API layer for accessing all marketplace services.
Features
- Unified Schema - Single GraphQL endpoint for all services
- Type Safety - Strict TypeScript implementation with comprehensive type definitions
- Performance - DataLoader batching, Redis caching, query optimization
- Security - JWT authentication, role-based authorization, rate limiting
- Real-time - WebSocket subscriptions for live updates
- Developer Experience - GraphQL Playground, introspection, comprehensive documentation
Architecture
Client Applications
↓
GraphQL API Gateway (Apollo Server 4)
├─ Schema Stitching
├─ Authentication Middleware
├─ DataLoaders (N+1 prevention)
├─ Redis Cache
└─ REST Data Sources
↓
Microservices
├─ Publishing Service (port 3001)
├─ Discovery Service (port 3002)
├─ Consumption Service (port 3003)
└─ Admin Service (port 3004)Quick Start
Prerequisites
- Node.js 18+
- Redis 7+
- Running microservices (Publishing, Discovery, Consumption, Admin)
Installation
# Install dependencies
npm install
# Copy environment variables
cp .env.example .env
# Edit .env with your configuration
nano .envDevelopment
# Start development server with hot reload
npm run dev
# GraphQL Playground will be available at:
# http://localhost:4000/graphqlProduction
# Build TypeScript
npm run build
# Start production server
npm startDocker
# Build and run with Docker Compose
docker-compose up -d
# View logs
docker-compose logs -f graphql-gateway
# Stop
docker-compose downAPI Documentation
Endpoints
- GraphQL Endpoint:
POST /graphql - WebSocket Subscriptions:
ws://localhost:4000/graphql - GraphQL Playground:
GET /graphql(development only)
Authentication
Include JWT token in Authorization header:
Authorization: Bearer <your-jwt-token>Example Queries
Search Services
query SearchServices {
searchServices(
query: "text generation"
filter: {
category: "AI"
minRating: 4.0
}
pagination: {
limit: 10
}
) {
services {
id
name
description
rating
provider {
name
verified
}
pricing {
model
price
currency
}
}
total
took
}
}Get Service Details
query GetService($id: ID!) {
service(id: $id) {
id
name
description
version
category
tags
provider {
id
name
email
verified
rating
}
pricing {
model
price
currency
tiers {
name
requestsIncluded
price
}
}
endpoints {
url
method
description
}
rating
usageCount
createdAt
updatedAt
}
}Create Service
mutation CreateService($input: CreateServiceInput!) {
createService(input: $input) {
... on Service {
id
name
status
}
... on ValidationError {
message
fields {
field
message
}
}
}
}Subscribe to Service Updates
subscription OnServiceUpdated($id: ID!) {
serviceUpdated(id: $id) {
id
name
status
updatedAt
}
}Directives
@auth
Requires user authentication:
type Query {
recommendations: [Service!]! @auth
}@requireRole(role: Role!)
Requires specific user role:
type Mutation {
approveService(id: ID!): ApprovalResult! @requireRole(role: ADMIN)
}@rateLimit(limit: Int!, window: Int!)
Limits requests per time window:
type Query {
searchServices(query: String!): SearchResult!
@rateLimit(limit: 200, window: 60)
}@cacheControl(maxAge: Int!, scope: CacheControlScope)
Sets cache TTL for responses:
type Query {
categories: [Category!]! @cacheControl(maxAge: 3600)
}Schema
The schema is organized by domain:
- Common - Scalars, pagination, errors, directives
- Publishing - Service management and publishing
- Discovery - Search, recommendations, categories
- Consumption - Usage tracking, quotas, billing
- Admin - Analytics, audit logs, user management
Custom Scalars
DateTime- ISO 8601 date-time stringJSON- Arbitrary JSON valueURL- Valid HTTP/HTTPS URLEmailAddress- Valid email formatPositiveInt- Integer > 0NonNegativeInt- Integer >= 0NonNegativeFloat- Float >= 0
Error Handling
Errors are returned as union types for explicit handling:
union ServiceResult = Service | ValidationError | NotFoundError | AuthorizationErrorClient can handle different error types:
mutation CreateService($input: CreateServiceInput!) {
createService(input: $input) {
... on Service {
id
name
}
... on ValidationError {
message
fields {
field
message
}
}
... on NotFoundError {
message
resourceType
}
}
}Performance
DataLoader Batching
All relationship fields use DataLoader for automatic batching:
// Instead of N+1 queries
services.forEach(service => {
const provider = await getProvider(service.providerId);
});
// DataLoader batches into single query
const providers = await batchGetProviders(allProviderIds);Redis Caching
Query responses are automatically cached based on @cacheControl directives:
type Query {
categories: [Category!]! @cacheControl(maxAge: 3600)
}Cache headers are set on responses:
X-Cache: HIT
X-Response-Time: 5msQuery Complexity
Maximum query complexity is limited to prevent expensive queries:
const MAX_COMPLEXITY = 1000;Queries exceeding the limit are rejected:
{
"errors": [{
"message": "Query is too complex: 1250. Maximum allowed: 1000",
"extensions": {
"code": "QUERY_TOO_COMPLEX"
}
}]
}Query Depth
Maximum query depth is limited to prevent deeply nested queries:
const MAX_DEPTH = 10;Security
Authentication
JWT-based authentication with role hierarchy:
USER- Regular userPROVIDER- Service providerADMIN- AdministratorSUPER_ADMIN- Super administrator
Rate Limiting
Field-level rate limiting prevents abuse:
type Query {
searchServices(query: String!): SearchResult!
@rateLimit(limit: 200, window: 60)
}Rate limit exceeded errors include retry information:
{
"errors": [{
"message": "Rate limit exceeded",
"extensions": {
"code": "RATE_LIMIT_EXCEEDED",
"limit": 200,
"window": 60,
"retryAfter": 45
}
}]
}CORS
Configure allowed origins in environment:
ALLOWED_ORIGINS=https://marketplace.example.com,https://admin.example.comMonitoring
Metrics
Metrics are collected for every request:
{
"type": "graphql_request",
"operation": "SearchServices",
"status": "success",
"duration": 125,
"requestId": "1234567890-abc",
"userId": "user-123",
"timestamp": "2025-01-19T10:30:00.000Z"
}Slow Field Warnings
Fields taking > 100ms are logged:
{
"type": "slow_field",
"field": "Query.searchServices",
"duration": 250,
"requestId": "1234567890-abc"
}Health Check
Health endpoint returns system status:
query {
health {
status
version
uptime
timestamp
services {
name
status
responseTime
}
}
}Testing
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests in watch mode
npm run test:watchEnvironment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| PORT | Server port | 4000 |
| NODE_ENV | Environment | development |
| API_BASE_URL | Base URL for microservices | http://localhost:3000 |
| REDIS_URL | Redis connection string | redis://localhost:6379 |
| JWT_SECRET | JWT signing secret | required |
| MAX_QUERY_COMPLEXITY | Maximum query complexity | 1000 |
| MAX_QUERY_DEPTH | Maximum query depth | 10 |
Troubleshooting
Connection Refused
If you get connection errors:
- Ensure Redis is running:
redis-cli ping - Verify microservices are accessible
- Check
API_BASE_URLin.env
Authentication Errors
If you get authentication errors:
- Verify JWT token is valid
- Check
JWT_SECRETmatches token issuer - Ensure token hasn't expired
Performance Issues
If queries are slow:
- Check Redis cache is working
- Enable DataLoader batching
- Review query complexity
- Check slow field warnings in logs
Contributing
- Follow TypeScript best practices
- Add tests for new features
- Update documentation
- Run linter:
npm run lint
License
Proprietary - LLM Marketplace Platform
