graphql-mandatory-validator
v1.3.2
Published
A GraphQL schema validator using AST-only parsing for mandatory fields with default values, array validation, and composite type validation
Maintainers
Readme
graphql-mandatory-validator
A Node.js package for validating GraphQL schema files to ensure mandatory fields have appropriate default values. This tool helps maintain schema consistency across multiple repositories and prevents breaking changes.
Features
- ✅ Validates mandatory GraphQL fields have default values
- 🏗️ Validates mandatory composite types have at least one mandatory field
- 🎯 NEW: Validates mandatory enum fields have default values
- 🔧 Configurable scalar type defaults
- 📁 Works with standard
src/type-defsdirectory structure - 🚀 Can validate staged files (git pre-commit) or entire projects
- 🎨 Colored terminal output with detailed error messages
- 📦 Available as both CLI tool and programmatic API
- 🔄 Supports multiple repositories with consistent structure
Installation
Global Installation (CLI usage)
npm install -g graphql-mandatory-validatorLocal Installation (Project dependency)
npm install --save-dev graphql-mandatory-validatorCLI Usage
Basic Usage
# Validate staged .graphql files (for pre-commit hooks)
graphql-validator
# Validate all .graphql files in the project
graphql-validator --mode allAdvanced Options
# Use custom base directory
graphql-validator --base-dir schema/definitions
# Validate specific project root
graphql-validator --mode all --project-root /path/to/project
# Disable colored output
graphql-validator --no-color
# Don't exit process on validation failure
graphql-validator --no-exitHelp
graphql-validator --helpProgrammatic API
Basic Usage
import { GraphQLValidator } from 'graphql-mandatory-validator';
const validator = new GraphQLValidator();
// Validate staged files
const result = await validator.validateStagedFiles();
// Validate entire project
const result = await validator.validateProject();
console.log(`Validation ${result.success ? 'passed' : 'failed'}`);
console.log(`Files checked: ${result.filesChecked}`);
console.log(`Errors found: ${result.errors.length}`);Advanced Configuration
import { GraphQLValidator } from 'graphql-mandatory-validator';
const validator = new GraphQLValidator({
baseDir: 'custom/graphql/path',
colorOutput: false,
exitOnError: false,
scalarDefaults: {
String: '@defaultValue(value: "")',
Int: '@defaultValue(value: 0)',
Float: '@defaultValue(value: 0.0)',
Boolean: '@defaultValue(value: false)',
ID: '@defaultValue(value: "")',
// Add custom scalar types
DateTime: '@defaultValue(value: "1970-01-01T00:00:00Z")',
}
});
const result = await validator.run('all', '/path/to/project');Validation Rules
1. Scalar Type Default Values
The validator enforces the following default values for GraphQL scalar types:
| GraphQL Type | Required Default Value |
|--------------|------------------------|
| String! | @defaultValue(value: "") |
| Int! | @defaultValue(value: 0) |
| Float! | @defaultValue(value: 0.0) |
| Boolean! | @defaultValue(value: false) |
| ID! | @defaultValue(value: "") |
2. Composite Type Validation
The validator ensures that if a composite type is used as a mandatory field, the composite type itself must contain at least one mandatory field.
Why this rule? If a composite type has no mandatory fields, making it mandatory doesn't provide any meaningful constraint - it could be an empty object and still satisfy the schema.
3. Enum Type Validation
NEW: The validator ensures that mandatory enum fields have appropriate default values.
Default Value Format: @defaultValue(value: "ENUM_VALUE")
Recommended Values:
- Use
"UNKNOWN"if available in the enum - Otherwise, use any valid enum value
Why this rule? Mandatory enum fields without defaults can break existing queries when new enum types are introduced.
Example GraphQL Schema
Scalar Type Validation
❌ Invalid (will fail validation)
type User {
id: ID!
name: String!
age: Int!
isActive: Boolean!
}✅ Valid (passes validation)
type User {
id: ID! @defaultValue(value: "")
name: String! @defaultValue(value: "")
age: Int! @defaultValue(value: 0)
isActive: Boolean! @defaultValue(value: false)
}Composite Type Validation
❌ Invalid (will fail validation)
type User {
id: ID! @defaultValue(value: "")
profile: Profile! # ERROR: Profile has no mandatory fields
}
type Profile {
bio: String # Optional field
avatar: String # Optional field
website: String # Optional field
}Error: Mandatory composite field "profile" of type "Profile!" references a type with no mandatory fields. Type "Profile" should have at least one mandatory field.
✅ Valid (passes validation)
# Option 1: Add mandatory field to composite type
type User {
id: ID! @defaultValue(value: "")
profile: Profile!
}
type Profile {
userId: ID! @defaultValue(value: "") # Now has mandatory field
bio: String
avatar: String
website: String
}
# Option 2: Make composite field optional
type User {
id: ID! @defaultValue(value: "")
profile: Profile # Made optional (no !)
}
type Profile {
bio: String
avatar: String
website: String
}Enum Type Validation
❌ Invalid (will fail validation)
type Order {
id: ID! @defaultValue(value: "")
status: OrderStatus! # ERROR: Missing default value
priority: Priority! # ERROR: Missing default value
}Error: Mandatory field "status" of type "OrderStatus!" must have a default value. For enum types, use @defaultValue(value: "UNKNOWN") or @defaultValue(value: "<enum_value>") with one of the enum values.
✅ Valid (passes validation)
# Option 1: Using UNKNOWN (recommended)
type Order {
id: ID! @defaultValue(value: "")
status: OrderStatus! @defaultValue(value: "UNKNOWN")
priority: Priority! @defaultValue(value: "UNKNOWN")
}
# Option 2: Using specific enum values
type Task {
id: ID! @defaultValue(value: "")
status: TaskStatus! @defaultValue(value: "PENDING")
priority: Priority! @defaultValue(value: "MEDIUM")
}
# Option 3: Mixed approach
type Product {
id: ID! @defaultValue(value: "")
category: Category! @defaultValue(value: "UNKNOWN") # Has UNKNOWN
status: ProductStatus! @defaultValue(value: "DRAFT") # No UNKNOWN, use first value
}Git Pre-commit Hook Integration
Using Husky
Install husky:
npm install --save-dev husky npx husky installAdd pre-commit hook:
npx husky add .husky/pre-commit "graphql-validator"
Using pre-commit (Python)
Add to your .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: graphql-validator
name: GraphQL Schema Validator
entry: graphql-validator
language: node
files: \\.graphql$
pass_filenames: falsePackage.json Scripts
Add to your package.json:
{
"scripts": {
"validate-graphql": "graphql-validator --mode all",
"validate-graphql:staged": "graphql-validator"
}
}Configuration Options
Constructor Options
interface ValidationOptions {
baseDir?: string; // Default: 'src/type-defs'
scalarDefaults?: Record<string, string>;
colorOutput?: boolean; // Default: true
exitOnError?: boolean; // Default: true
}ValidationResult
interface ValidationResult {
success: boolean;
errors: ValidationError[];
filesChecked: number;
}
interface ValidationError {
file: string;
line: number;
fieldName: string;
fieldType: string;
expectedDefault: string;
message: string;
}Repository Structure Requirements
This package assumes your GraphQL files are located in:
your-project/
├── src/
│ └── type-defs/
│ ├── schema1.graphql
│ ├── schema2.graphql
│ └── ...
└── package.jsonYou can customize the base directory using the baseDir option.
License
MIT
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support
For issues and questions, please open an issue on the GitHub repository.
