This report is generated based on example business code and official examples.
Scores in this report are given by AI after horizontal comparison.
Evaluation Date: January 2026
Evaluation Version: garph@0.6.8
Evaluation Method: Deep source code audit based on example business code and official examples
📋 Basic Information
| Project | Content |
|---|---|
| Current Version | 0.6.8 |
| GitHub | https://github.com/stepci/garph |
| Documentation | https://garph.dev/docs |
| First Commit | 2023-01-19 |
| Latest Commit | 2024-03-01 |
📊 Overall Score
| Dimension | Score (1-5) | Brief Review |
|---|---|---|
| 1. Architecture Pattern | 4.5 | Builder pattern, zero magic, write and use immediately, lightweight dependencies |
| 2. Type Definition | 3.5 | Deep inference, smart inheritance, flexible enums, Union requires manual handling |
| 3. Resolvers & Validation | 2.9 | Automatic parameter inference, native DataLoader, no built-in validation |
| 4. Built-in Features | 3.0 | Core features complete, advanced features missing, security features insufficient |
| 5. Ecosystem Integration | 2.0 | Standard compatible, weak ORM/validation integration, no official adapters |
1. Architecture Pattern (Architecture)
Architecture Pattern Type
Builder Pattern: Garph uses a functional chained API to explicitly build GraphQL Schema, provides type definition methods through GarphSchema instances (usually named g), and finally converts definitions to standard GraphQL Schema at runtime through the buildSchema() function.
Core Implementation Mechanism
Source Code Evidence:
- Core API definition:
garph/src/index.ts(lines 598-727) defines theGarphSchemaclass and its methods - Schema building: The
buildSchema()function ingarph/src/schema.ts(lines 17-21) usesgraphql-compose'sSchemaComposerfor conversion - Business code example:
typescript-graphql-schemas/garph/src/schema.ts(line 7) creates aGarphSchemainstance, line 306 callsbuildSchema({ g, resolvers })
Build Flow:
// 1. Create Schema instance
const g = new GarphSchema()
// 2. Define types (chained API)
const UserType = g.type('User', {
id: g.int(),
name: g.string(),
})
// 3. Build Schema at runtime
const schema = buildSchema({ g, resolvers })
Scoring Details
1.1 Dependency Complexity (Dependency Complexity)
Score: 4.0
Evidence:
-
Runtime dependencies (
garph/package.jsonlines 30-33):-
graphql-compose: ^9.0.10- GraphQL Schema building tool -
single-user-cache: ^0.6.0- DataLoader cache implementation
-
-
No decorator dependencies: No need for
reflect-metadataor decorator support - No code generation tools: No need for CLI or code generation steps
Analysis:
- ✅ Only 2 runtime dependencies, lighter than decorator pattern (requires
reflect-metadata,class-validator, etc.) - ⚠️
graphql-composeis a feature-complete Schema building library, increases dependency size but provides powerful underlying capabilities - ✅
single-user-cacheis used for built-in DataLoader support, a feature enhancement rather than a core dependency
1.2 Build Flow (Build Flow)
Score: 5.0
Evidence:
-
Pure runtime building: The
buildSchema()function ingarph/src/schema.ts(lines 17-21) executes at runtime -
No code generation: Business code (
typescript-graphql-schemas/garph/src/server.ts) runs TypeScript directly, no pre-build steps required -
No CLI tools:
garph/package.jsonhas no dedicated build scripts, only documentation and test scripts
Actual Usage:
// typescript-graphql-schemas/garph/src/server.ts
import { schema } from './schema.ts'
const yoga = createYoga({ schema })
// Run directly, no build steps required
Analysis:
- ✅ Complete runtime building, developers can run code directly after writing
- ✅ Supports hot reload (e.g.,
node --watch), excellent development experience - ✅ No need to learn additional CLI commands or build configurations
1.3 Config & Language Magic (Config & Language Magic)
Score: 5.0
Evidence:
-
No decorators: All type definitions use function calls, such as
g.type(),g.string() -
No reflection metadata: No need for
import 'reflect-metadata'orexperimentalDecoratorsconfiguration -
Standard TypeScript:
typescript-graphql-schemas/garph/tsconfig.jsononly contains standard configuration, no special settings -
Type inference: Uses TypeScript generics and conditional types to achieve type safety (
Infer,InferResolvers)
Code Example:
// Fully compliant with native TypeScript best practices
const UserType = g.type('User', {
id: g.int(),
name: g.string(),
})
// Type inference works automatically
type User = Infer<typeof UserType>
Analysis:
- ✅ Zero magic, fully compliant with native TypeScript best practices
- ✅ No dependency on experimental features or compiler plugins
- ✅ Excellent IDE support, type hints and autocomplete work normally
- ✅ Strong code readability, chained API is intuitive and easy to understand
1.4 Ecosystem Integration (Ecosystem Integration)
Score: 4.0
Evidence:
-
Standard installation:
npm install garphcan be used immediately, no special requirements -
Server compatibility: Official examples (
garph/examples/demo.ts) usegraphql-yoga, but can integrate with any GraphQL Server -
Uses graphql-compose under the hood:
garph/src/schema.ts(line 2) importsSchemaComposer, ultimately outputs standardGraphQLSchema -
Business code integration:
typescript-graphql-schemas/garph/src/server.tsdirectly usesgraphql-yoga, simple integration
Analysis:
- ✅ Standard npm package, can be freely integrated into any project
- ✅ Outputs standard GraphQL Schema, compatible with all GraphQL Servers
- ✅ Not bound to specific frameworks, flexible choice of underlying implementation
- ⚠️ Although not mandatory, official examples and documentation mainly showcase
graphql-yogaintegration
Architecture Pattern Overall Score
Score: 4.5
Scoring Basis:
- Dependency complexity: 4.0 (lightweight dependencies, but
graphql-composeincreases size) - Build flow: 5.0 (write and use immediately, zero build steps)
- Config & language magic: 5.0 (zero magic, completely native TypeScript)
- Ecosystem integration: 4.0 (good integration, standard compatible)
Advantages:
- Zero-config startup: No need for decorators, reflection, or code generation, works out of the box
- Type safety: Achieves end-to-end type safety through TypeScript type system
- Excellent development experience: Chained API is intuitive, IDE support is complete
- Runtime building: Supports hot reload, fast development iteration
Disadvantages:
- Dependency on graphql-compose: Although powerful, increases package size
- Explicit API calls: Compared to decorator pattern, requires more explicit code (but gains zero magic advantage)
2. Type Definition (Type Definition)
Core Implementation Mechanism
Garph uses Builder API + type inference to implement type definitions. Schema definitions are created through chained API, TypeScript types are automatically inferred from Schema definitions through the Infer utility type, and GraphQL Schema is generated at runtime through buildSchema().
Source Code Evidence:
- Type inference implementation:
garph/src/index.ts(lines 93-118) defines theInfertype utility - Schema building:
garph/src/schema.ts(lines 85-170) converts Garph types to GraphQL Schema - Business code example:
typescript-graphql-schemas/garph/src/schema.ts(lines 68-70) usesInferto infer types
Scoring Details
2.1 Single Source of Truth (SSOT) Implementation
Score: 4.0
Evidence:
-
Schema definition as data source:
typescript-graphql-schemas/garph/src/schema.ts(lines 23-66) defines Schema through methods likeg.type() -
TypeScript type automatic inference: Lines 68-70 use
Infer<typeof UserType>to infer types from Schema definition -
GraphQL Schema automatic generation: Line 306 generates standard GraphQL Schema through
buildSchema({ g, resolvers }) - Validation logic separation: Validation needs to be manually implemented in Scalar or Resolver (line 181), does not support automatic type generation from validation rules
Code Example:
// Single source of truth: Schema definition
const UserType = g.type('User', {
id: g.int(),
name: g.string(),
email: g.string(),
})
// TypeScript type automatic inference
type User = Infer<typeof UserType>
// Result: { id: number, name: string, email: string }
// GraphQL Schema automatic generation
const schema = buildSchema({ g, resolvers })
Analysis:
- ✅ Schema definition is the single source of truth, both TypeScript types and GraphQL Schema are derived from it
- ✅ Deep type inference: Supports nested types, optional fields, arrays, and other complex scenarios
- ⚠️ Validation logic needs manual integration: Although there are Zod examples (
garph/www/docs/advanced/validation.mdlines 35-70), it's not native support, needs manual validation calls in Scalar'sparseValue - ⚠️ Validation rules separated from type definitions: Cannot automatically generate types from validation rules, needs manual synchronization
2.2 Enum & String Union Support (Enum & String Union Types)
Score: 4.0
Evidence:
-
as constarray support:typescript-graphql-schemas/garph/src/schema.ts(lines 15-19) usesg.enumType('OrderStatus', ['PENDING', 'COMPLETED', 'CANCELLED'] as const) -
TypeScript Enum support: Official documentation (
garph/www/docs/guide/schemas.mdlines 129-138) shows support for TypeScript Enum -
Type inference requirement: Must use
as constto correctly infer types (documentation line 127 explicitly states)
Code Example:
// Method 1: as const array (recommended)
const OrderStatusEnum = g.enumType('OrderStatus', [
'PENDING',
'COMPLETED',
'CANCELLED',
] as const)
// Method 2: TypeScript Enum
enum Fruits {
Apples,
Oranges
}
g.enumType('Fruits', Fruits)
Analysis:
- ✅ Supports two methods:
as constarray and TypeScript Enum - ✅ No need to redefine member names: Directly use array or Enum, no manual mapping required
- ⚠️ Must use
as const: Missingas constwill cause type inference to fail, developers need to remember this requirement - ✅ Type safe: Enum values are completely synchronized in TypeScript and GraphQL
2.3 Interface Inheritance & Union Type Experience (Interface & Union)
Score: 4.0
Evidence:
-
Interface fields automatic inheritance:
typescript-graphql-schemas/garph/src/schema.ts(lines 34-51) demonstrates interface implementation-
FoodInterfacedefines common fields (id, name, price) -
CoffeeTypeandDessertTypeautomatically inherit through.implements(FoodInterface) - Implementation types only need to define unique fields (sugarLevel/origin and calories)
-
-
Runtime automatic merging:
garph/src/schema.ts(lines 94-98) automatically adds interface fields to implementation types when building Schema -
Type system support:
garph/src/index.ts(line 195) usesUnionToIntersectionto merge interface fields at the type level -
Union types require manual handling:
typescript-graphql-schemas/garph/src/schema.ts(lines 202-211) needs to manually returntypenamein Resolver -
Union type resolution:
garph/examples/union.ts(lines 36-39) needs to manually implementresolveType
Code Example:
// Interface definition
const FoodInterface = g.interface('Food', {
id: g.int(),
name: g.string(),
price: g.float(),
})
// Implement interface (automatic field inheritance)
const CoffeeType = g
.type('Coffee', {
sugarLevel: g.ref(SugarLevelEnum),
origin: g.string(),
})
.implements(FoodInterface)
// CoffeeType automatically includes id, name, price fields
// Union type definition
const MenuItemType = g.unionType('MenuItem', {
Coffee: CoffeeType,
Dessert: DessertType,
})
// Union types require manual __typename handling
createCoffee: (_, { name, price, sugarLevel, origin }) => {
return {
__typename: 'Coffee' as const, // Must manually specify
id,
name,
price,
sugarLevel,
origin,
}
}
Analysis:
- ✅ Interface fields automatic inheritance: Implementation types don't need to repeat common field declarations
- ✅ Type system support: TypeScript types also automatically include interface fields
- ⚠️ Union types require manual
__typename: Must explicitly specify type name in return object - ⚠️ Union types require manual
__resolveType: Need to implement type resolution function (optional but usually needed) - ✅ Supports multiple interface implementation: Can implement multiple interfaces simultaneously (
garph/examples/implements.tsline 13)
2.4 Type Inference Strength & Explicit Declaration Balance
Score: 3.0
Evidence:
-
Automatic inference of basic types:
garph/src/index.ts(lines 108-118)InferShallowautomatically handles String, Int, Float, Boolean, ID, Enum and other basic types -
Automatic inference of complex types: Supports arrays (
AnyList), optional (AnyOptional), nested objects (recursiveInferRaw), Union types -
Resolver type inference:
InferResolvers(lines 134-154) automatically infers Resolver parameter types and return value types -
Requires explicit type annotations:
typescript-graphql-schemas/garph/src/schema.ts(lines 152-160) needs to addInferResolverstype annotation to Resolver object
Code Example:
// Basic type automatic inference
const UserType = g.type('User', {
id: g.int(), // Inferred as number
name: g.string(), // Inferred as string
email: g.string(), // Inferred as string
})
type User = Infer<typeof UserType>
// Automatically inferred as: { id: number, name: string, email: string }
// Complex type automatic inference
const OrderType = g.type('Order', {
userId: g.int(),
itemIds: g.int().list(), // Inferred as number[]
status: g.ref(OrderStatusEnum), // Inferred as enum value
createdAt: g.ref(DateTime), // Inferred as Date
items: g.ref(MenuItemType).list(), // Inferred as MenuItem[]
})
// Resolver type automatic inference
const resolvers: InferResolvers<
{ Query: typeof queryType },
{}
> = {
Query: {
user: (_, { id }) => { // id automatically inferred as number
// ...
}
}
}
Analysis:
- ✅ Powerful type inference: Supports all GraphQL types including basic types, arrays, optional, nested, Union
- ✅ Resolver parameter type automatic inference: Automatically infers parameter types through
InferResolvers, no manual declaration needed - ✅ Recursive type inference: Supports deeply nested object types
- ⚠️ Requires explicit type annotations: Resolver object needs to add
InferResolverstype annotation (although this is for type safety, it increases code volume) - ✅ Excellent IDE support: Type hints and autocomplete work normally
Type Definition Overall Score
Score: 3.5
Scoring Basis:
- SSOT implementation: 4.0 (deep inference, but validation logic separated)
- Enum support: 4.0 (lightweight mapping, but requires
as const) - Interface inheritance: 4.0 (smart inheritance, but Union requires manual handling)
- Type inference strength: 3.0 (powerful inference, but requires explicit type annotations)
Advantages:
- Powerful type inference: Automatically infers TypeScript types from Schema definitions, supports complex scenarios
- Interface automatic inheritance: No need to repeat common field declarations when implementing interfaces
-
Flexible enum support: Supports
as constarrays and TypeScript Enum - Complete type safety: End-to-end type safety, from Schema to Resolver
Disadvantages:
-
Union types require manual handling: Must manually return
__typenameand implement__resolveType - Validation logic separated: Validation rules separated from type definitions, needs manual synchronization
-
Requires explicit type annotations: Resolver object needs to add
InferResolverstype annotation
3. Resolvers & Validation (Resolvers & Validation)
Core Implementation Mechanism
Garph's Resolver definition uses explicit type annotations + automatic type inference. All Resolvers are centralized in one object, organized by Query, Mutation, and type names. Parameter types are automatically inferred through the InferResolvers utility type, but explicit type annotations need to be added to the Resolver object.
Source Code Evidence:
- Resolver type inference:
garph/src/index.ts(lines 134-154) defines theInferResolverstype utility - Business code example:
typescript-graphql-schemas/garph/src/schema.ts(lines 152-304) demonstrates complete Resolver definition
Scoring Details
3.1 Development Experience (Code Conciseness)
Score: 3.5
Evidence:
-
Resolver definition concise:
typescript-graphql-schemas/garph/src/schema.ts(lines 161-178) Query Resolver definition is intuitive -
Parameter type automatic inference: In line 163's
user: (_, { id }),idtype is automatically inferred asnumber -
Requires explicit type annotations: Lines 152-160 need to add
InferResolverstype annotation to Resolver object - Validation logic manually written: Lines 181, 192, 250-260 need to manually write validation logic
Code Example:
// Resolver definition (concise but requires type annotation)
const resolvers: InferResolvers<
{
Query: typeof queryType
Mutation: typeof mutationType
User: typeof UserType
Order: typeof OrderType
},
{}
> = {
Query: {
users: () => Array.from(userMap.values()),
user: (_, { id }) => { // id automatically inferred as number
const user = userMap.get(id)
if (!user) throw new GraphQLError('User not found')
return user
},
},
Mutation: {
createUser: (_, { name, email }) => {
// Need to manually write validation logic
if (!email.includes('@')) {
throw new GraphQLError('Invalid email format')
}
// ...
},
},
}
Analysis:
- ✅ Resolver function definition concise, parameter types automatically inferred
- ✅ Excellent IDE support, type hints and autocomplete work normally
- ⚠️ Requires explicit type annotations: Resolver object needs to add
InferResolverstype annotation (although this is for type safety, it increases code volume) - ⚠️ Validation logic needs manual writing: Each place that needs validation must manually write validation code
3.2 Modular Design (Domain-Driven Development Support)
Score: 0.0
Evidence:
-
Organized by operation type:
typescript-graphql-schemas/garph/src/schema.ts(lines 152-304) all Resolvers are in one object, organized byQuery,Mutation,User,Order - No enforced module boundaries: No enforced module boundaries, all Resolvers are in the same file
- Easy to write coupled code: If not careful, easy to write all domain Query/Mutation/Field Resolvers in one file
- Can manually split: Although can split files by domain modules, needs manual combination, and no enforced module boundaries
Code Example:
// All Resolvers in one object, organized by operation type
const resolvers: InferResolvers<...> = {
Query: {
users: ...,
user: ...,
menu: ...,
menuItem: ...,
orders: ...,
order: ...,
},
Mutation: {
createUser: ...,
updateUser: ...,
deleteUser: ...,
createCoffee: ...,
// ... All Mutations mixed together
},
User: {
orders: ...,
},
Order: {
user: ...,
items: ...,
},
}
Analysis:
- ❌ Completely isolated by operation type:
Query,Mutation,Typeorganized separately, not by domain - ❌ No enforced module boundaries: No enforced module boundaries, easy to write coupled giant files
- ⚠️ Needs manual combination: If modularizing, needs to manually split files and combine, but framework doesn't enforce
- ⚠️ Limited DDD support: Although can organize by files, lacks enforced module boundaries, easy to write coupled code
3.3 Parameter Definition & Type Inference
Score: 4.0
Evidence:
-
Parameter definition in fields:
typescript-graphql-schemas/garph/src/schema.ts(lines 80-82) parameters defined in fields through.args() -
Parameter type automatic inference: In line 163's
user: (_, { id }),idtype automatically inferred asnumberthroughInferResolvers - Excellent IDE hints: TypeScript fully understands parameter types, IDE autocomplete works normally
-
Requires explicit type annotations: Lines 152-160 need to add
InferResolverstype annotation to Resolver object
Code Example:
// Parameter definition in fields
const queryType = g.type('Query', {
user: g.ref(UserType).optional().args({
id: g.int(), // Parameter definition
}),
})
// Parameter type automatic inference
const resolvers: InferResolvers<{ Query: typeof queryType }, {}> = {
Query: {
user: (_, { id }) => { // id automatically inferred as number
// ...
},
},
}
Analysis:
- ✅ Parameter types mostly automatically inferred: Automatically infers parameter types through
InferResolvers, no manual declaration needed - ✅ Excellent IDE hints: TypeScript fully understands parameter types, IDE autocomplete works normally
- ⚠️ Requires explicit type annotations: Resolver object needs to add
InferResolverstype annotation (although this is for type safety, it increases code volume) - ✅ Type safe: Parameter types completely synchronized with Schema definition
3.4 Input Validation Mechanism
Score: 2.0
Evidence:
-
No built-in validation:
typescript-graphql-schemas/garph/src/schema.ts(lines 181, 192, 250-260) all validation logic needs to be manually written -
Can implement through Scalar:
garph/examples/validation.ts(lines 6-15) demonstrates validation through Scalar'sparseValue -
Supports Zod integration:
garph/www/docs/advanced/validation.md(lines 35-70) shows using Zod validation, but needs manual calls in Scalar - Validation logic scattered: Validation code scattered across various Resolvers, difficult to reuse
Code Example:
// Method 1: Manual validation in Resolver
createUser: (_, { name, email }) => {
if (!email.includes('@')) {
throw new GraphQLError('Invalid email format')
}
// ...
}
// Method 2: Validation through Scalar
const username = g.scalarType<string, string>('Username', {
serialize: (username) => username,
parseValue: (username) => {
if (username.length < 3) {
throw new GraphQLError('Username must be at least 3 characters long')
}
return username
}
})
// Method 3: Using Zod (needs manual call)
const usernameValidator = z.string().min(3)
const username = g.scalarType<string, string>('Username', {
parseValue: (username) => {
if (!usernameValidator.safeParse(username).success) {
throw new GraphQLError('Username must be at least 3 characters long')
}
return username
}
})
Analysis:
- ❌ No built-in validation: Does not provide declarative validation API (like
.refine()or@IsEmail()) - ❌ Validation logic repetitive: Needs to manually write validation code in each place that needs validation
- ⚠️ Can implement through Scalar: But needs to create independent Scalar types for each validation scenario, increases code volume
- ⚠️ Supports Zod integration: But needs manual calls in Scalar's
parseValue, validation logic separated from Schema definition - ❌ No declarative API: Does not provide declarative validation API like
.refine()
3.5 Batch Loading (DataLoader) Integration
Score: 5.0
Evidence:
-
Native built-in support: The
addResolverfunction ingarph/src/schema.ts(lines 193-220) automatically handlesloadandloadBatchmethods -
Uses single-user-cache: Lines 4-5 use
single-user-cacheto implement DataLoader functionality -
Almost no boilerplate:
garph/examples/loader.ts(lines 34-44) shows only need to defineloadfunction, no need to configure Context or create DataLoader instances -
Supports cache control:
loadmethod supports caching,loadBatchmethod does not support caching
Code Example:
// Use .omitResolver() when defining fields
const Dog = g.type('Dog', {
name: g.string(),
owner: g.string().omitResolver() // Mark as requiring Resolver
})
// Define load function in Resolver
const resolvers: InferResolvers<{ Query: typeof queryType, Dog: typeof Dog }, {}> = {
Query: {
dogs: (parent, args, context, info) => {
return [{ name: 'Apollo' }, { name: 'Buddy' }]
}
},
Dog: {
owner: {
load(queries) { // Automatic batch loading, supports caching
return Promise.resolve(
queries.map(q => owners[q.parent.name])
)
}
}
}
}
Analysis:
- ✅ Native built-in support: No need to install additional plugins or configuration, directly use
loadorloadBatchmethods - ✅ Almost no boilerplate: Only need to define
loadfunction, no need to configure Context or create DataLoader instances - ✅ Automatic batch processing: Framework automatically collects queries and executes in batches
- ✅ Supports cache control:
loadsupports caching,loadBatchdoes not support caching - ✅ Type safe:
loadfunction parameter and return value types automatically inferred
Resolvers & Validation Overall Score
Score: 2.9
Scoring Basis:
- Development experience: 3.5 (code concise, but requires explicit type annotations)
- Modular design: 0.0 (no modular consideration, organized by operation type)
- Parameter definition & type inference: 4.0 (parameter types mostly automatically inferred)
- Input validation mechanism: 2.0 (no built-in validation, needs complete manual implementation)
- DataLoader integration: 5.0 (native built-in support, seamless usage)
Advantages:
-
Parameter type automatic inference: Automatically infers parameter types through
InferResolvers, excellent IDE support - DataLoader native support: Built-in DataLoader support, almost no boilerplate
- Code concise: Resolver function definitions intuitive, easy to understand
Disadvantages:
- No built-in validation: Needs to manually write all validation logic, validation code repetitive
- Limited modular support: Organized by operation type, doesn't enforce modularization, easy to write coupled code
-
Requires explicit type annotations: Resolver object needs to add
InferResolverstype annotation
4. Built-in Features (Built-in Features)
Feature Support Overview
Garph provides native support for core features (Context, DataLoader, Subscriptions, Custom Scalars), but has limited support for advanced features (Directives, Middleware, Query Complexity, Depth Limiting).
Feature Support Details Table
| Feature | Support Status | Implementation | Evidence/Explanation |
|---|---|---|---|
| Directives | ⛔ Not Implementable | Not Supported | Official documentation (garph/www/docs/guide/schemas.md line 252) explicitly states "Currently not supported", refer to GitHub issue #40 |
| Extensions | ⚠️ Plugin/Additional Implementation | Via GraphQLError |
garph/examples/errors.ts (line 17) demonstrates implementation through GraphQLError's extensions parameter, but not a native API |
| Batch Loading (DataLoader) | ✅ Built-in Support | Native Built-in |
garph/src/schema.ts (lines 193-220) native support for load and loadBatch methods, almost no boilerplate |
| Custom Scalars | ✅ Built-in Support | Native Built-in |
garph/examples/scalars.ts (line 5) defined through g.scalarType(), API intuitive and type safe |
| Subscriptions | ✅ Built-in Support | Native Built-in |
garph/examples/subscriptions.ts (lines 9-33) native support, implemented through async generator |
| Context | ✅ Built-in Support | Native Built-in |
garph/examples/context.ts (lines 15-17) native support, excellent type inference, good IDE hints |
| Middleware | ⛔ Not Implementable | Not Supported | No related support found, cannot inject middleware logic before/after Resolver execution |
| Query Complexity | ⛔ Not Implementable | Not Supported | No related support found, cannot prevent complex query attacks |
| Depth Limiting | ⛔ Not Implementable | Not Supported | No related support found, cannot prevent deep query attacks |
Detailed Analysis
4.1 Directive Support (Directives)
Status: ⛔ Not Implementable
Evidence:
- Official documentation (
garph/www/docs/guide/schemas.mdline 252) explicitly states "Currently not supported" - Refer to GitHub issue #40: https://github.com/stepci/garph/issues/40
Analysis:
- ❌ Completely does not support Directives definition
- ❌ Cannot implement Directives functionality through any means
- ⚠️ This is a known limitation, may be supported in future versions
4.2 Extension Support (Extensions)
Status: ⚠️ Plugin/Additional Implementation
Evidence:
-
garph/examples/errors.ts(line 17) demonstrates implementation throughGraphQLError'sextensionsparameter -
garph/www/docs/advanced/errors.md(lines 28-43) shows error extension usage
Code Example:
throw new GraphQLError('Expected error with extensions', {
extensions: { code: 'EXPECTED_ERROR' }
})
Analysis:
- ⚠️ Does not natively support Extensions API
- ⚠️ Can implement through
GraphQLError'sextensionsparameter, but needs manual handling - ⚠️ Cannot declare query complexity, execution time and other extension information
4.3 Batch Loading (DataLoader) Integration
Status: ✅ Built-in Support
Evidence:
- The
addResolverfunction ingarph/src/schema.ts(lines 193-220) automatically handlesloadandloadBatchmethods -
garph/examples/loader.ts(lines 34-44) shows only need to defineloadfunction, no need to configure Context or create DataLoader instances - Uses
single-user-cacheto implement DataLoader functionality
Code Example:
Dog: {
owner: {
load(queries) { // Automatic batch loading, supports caching
return Promise.resolve(
queries.map(q => owners[q.parent.name])
)
}
}
}
Analysis:
- ✅ Native built-in support, no need to install additional plugins
- ✅ Almost no boilerplate, only need to define
loadfunction - ✅ Automatic batch processing, supports cache control (
loadsupports caching,loadBatchdoes not)
4.4 Custom Scalars (Scalars)
Status: ✅ Built-in Support
Evidence:
-
garph/examples/scalars.ts(line 5) demonstrates defining custom scalars throughg.scalarType() -
typescript-graphql-schemas/garph/src/schema.ts(lines 9-13) demonstrates DateTime scalar definition -
garph/src/index.ts(lines 435-451) definesGScalarclass andscalarTypemethod
Code Example:
const DateTime = g.scalarType<Date, Date>('DateTime', {
serialize: (value) => GraphQLDateTime.serialize(value),
parseValue: (value) => GraphQLDateTime.parseValue(value) as Date,
parseLiteral: (ast) => GraphQLDateTime.parseLiteral(ast, {}) as Date,
})
Analysis:
- ✅ Easy to define new scalar types, API intuitive
- ✅ Type safe, supports generic parameters to specify input/output types
- ⚠️ Does not include built-in common scalars (like DateTime, JSON, BigInt), needs manual definition or use third-party libraries (like
graphql-scalars)
4.5 Subscriptions (Subscription)
Status: ✅ Built-in Support
Evidence:
-
garph/examples/subscriptions.ts(lines 9-33) demonstrates native Subscriptions support -
garph/src/index.ts(lines 135-139)InferResolverstype supports Subscription type - Implements real-time data push through async generator
Code Example:
const subscriptionType = g.type('Subscription', {
counter: g.int(),
})
const resolvers: InferResolvers<{ Subscription: typeof subscriptionType }, {}> = {
Subscription: {
counter: {
subscribe: async function* (parent, args, context, info) {
for (let i = 100; i >= 0; i--) {
await new Promise((resolve) => setTimeout(resolve, 1000))
yield { counter: i }
}
}
}
}
}
Analysis:
- ✅ Native support for GraphQL Subscriptions
- ✅ Supports real-time data push, implemented through async generator
- ✅ Good underlying transport protocol compatibility (supports WebSocket, SSE, etc. through graphql-yoga)
- ✅ API concise, type safe
4.6 Context Injection (Context)
Status: ✅ Built-in Support
Evidence:
-
garph/examples/context.ts(lines 9-26) demonstrates Context usage -
garph/src/index.ts(lines 134-154)InferResolverstype supports Context type parameter -
garph/www/docs/advanced/context.mdprovides complete Context usage documentation
Code Example:
const context = () => {
return {
hello: 'world'
}
}
const resolvers: InferResolvers<
{ Query: typeof queryType },
{ context: YogaInitialContext & ReturnType<typeof context> }
> = {
Query: {
context: (parent, args, context, info) => `Context: ${context.hello}`
}
}
const yoga = createYoga({ schema, context })
Analysis:
- ✅ Native support for injecting context in Resolver
- ✅ Excellent context type inference, specified through
InferResolvers's second type parameter - ✅ Good IDE hints, no need for manual type declarations
- ✅ Supports extending default Context (like
YogaInitialContext)
4.7 Middleware (Middleware)
Status: ⛔ Not Implementable
Evidence:
- No related support documentation or examples found
- No middleware-related code found in
garph/src/schema.tsandgarph/src/index.ts
Analysis:
- ❌ Completely does not support middleware mechanism
- ❌ Cannot inject logic before/after Resolver execution (like logging, permission checks, performance monitoring)
- ⚠️ Can implement similar functionality by manually wrapping Resolvers, but needs additional boilerplate
4.8 Query Complexity Analysis (Query Complexity)
Status: ⛔ Not Implementable
Evidence:
- No related support documentation or examples found
- No query complexity calculation and analysis related code found
Analysis:
- ❌ Completely does not support query complexity analysis
- ❌ Cannot prevent complex query attacks
- ⚠️ Can implement through graphql-yoga plugins, but needs additional configuration
4.9 Depth Limiting (Depth Limiting)
Status: ⛔ Not Implementable
Evidence:
- No related support documentation or examples found
- No depth limiting related code found
Analysis:
- ❌ Completely does not support depth limiting
- ❌ Cannot prevent deep query attacks
- ⚠️ Can implement through graphql-yoga plugins, but needs additional configuration
Built-in Features Overall Score
Score: 3.0
Scoring Basis:
- Directives: ⛔ Not Implementable (0 points) - Official documentation explicitly states not supported
- Extensions: ⚠️ Plugin/Additional Implementation (2 points) - Can implement through
GraphQLError'sextensionsparameter - DataLoader: ✅ Built-in Support (5 points) - Native built-in, through
loadandloadBatchmethods - Scalars: ✅ Built-in Support (5 points) - Defined through
g.scalarType(), API intuitive - Subscription: ✅ Built-in Support (5 points) - Native support, implemented through async generator
- Context: ✅ Built-in Support (5 points) - Native support, excellent type inference
- Middleware: ⛔ Not Implementable (0 points) - Completely does not support middleware mechanism
- Query Complexity: ⛔ Not Implementable (0 points) - Completely does not support query complexity analysis
- Depth Limiting: ⛔ Not Implementable (0 points) - Completely does not support depth limiting
Total Score: 27/45 = 3.0/5.0
Scoring Basis:
- Core features well supported: Context, DataLoader, Subscriptions, Custom Scalars all provide native support
- Advanced features limited support: Directives, Middleware, Query Complexity, Depth Limiting all not supported
- Feature completeness: Out of 9 features, 4 built-in support, 1 plugin/additional implementation, 4 not implementable
Advantages:
- Core features complete: Context, DataLoader, Subscriptions, Custom Scalars all provide native support
- Type safe: All supported features have excellent type inference
- API concise: Supported features have intuitive and easy-to-use APIs
Disadvantages:
- Advanced features missing: Directives, Middleware, Query Complexity, Depth Limiting all not supported
- Security features insufficient: Cannot prevent complex query attacks and deep query attacks
- Limited extensibility: Lacks middleware mechanism, difficult to implement cross-cutting concerns
5. Ecosystem Integration (Ecosystem Integration)
Core Integration Strategy
Garph adopts standard GraphQL Schema output + manual integration strategy. Outputs standard GraphQLSchema through buildSchema(), can integrate with any GraphQL Server, but needs manual adaptation. Mainly showcases integration with graphql-yoga, other Servers and frameworks need to integrate through standard GraphQL Server.
Scoring Details
5.1 ORM Integration Depth (ORM Integration Depth)
Score: <-To Be Scored->
Evidence:
- No official plugins: No official plugins found for Prisma, Drizzle, TypeORM and other ORMs
-
Needs manual integration: All database operations in
typescript-graphql-schemas/garph/src/schema.tsare manually implemented (using in-memory Map) - Type synchronization needs manual maintenance: ORM model definitions separated from GraphQL Schema definitions, needs manual synchronization
Code Example:
// Need to manually define GraphQL types
const UserType = g.type('User', {
id: g.int(),
name: g.string(),
email: g.string(),
})
// Need to manually implement database queries
const resolvers: InferResolvers<...> = {
Query: {
users: () => Array.from(userMap.values()), // Manual query
user: (_, { id }) => userMap.get(id), // Manual query
},
}
Analysis:
- ❌ No official plugins: Does not provide official plugins for Prisma, Drizzle, TypeORM and other ORMs
- ❌ Needs lots of glue code: Must manually write all database query logic
- ❌ Type synchronization needs manual maintenance: ORM model definitions separated from GraphQL Schema definitions
- ⚠️ Can manually integrate: Although can manually integrate ORM, needs lots of boilerplate
5.2 Validation Library Integration (Validation Library Integration)
Score: <-To Be Scored->
Evidence:
-
Supports Zod, but needs manual integration:
garph/www/docs/advanced/validation.md(lines 35-70) shows using Zod validation, but needs manual calls in Scalar'sparseValue - Validation logic separated from Schema definition: Validation rules cannot be directly declared in Schema definition, needs to create independent Scalar types
- Needs manual type synchronization: Validation rules separated from type definitions, needs manual synchronization
Code Example:
// Need to manually create Scalar and call Zod
const usernameValidator = z.string().min(3)
const username = g.scalarType<string, string>('Username', {
serialize: (username) => username,
parseValue: (username) => {
if (!usernameValidator.safeParse(username).success) {
throw new GraphQLError('Username must be at least 3 characters long')
}
return username
}
})
Analysis:
- ❌ No native support: Does not provide declarative validation API (like
.refine()orvalidateoption) - ❌ Validation logic separated from Schema definition: Needs to manually call validation library in Scalar
- ❌ Needs lots of boilerplate: Each validation scenario needs to create independent Scalar types
- ⚠️ Can manually integrate: Although can manually integrate Zod, needs lots of boilerplate
5.3 GraphQL Server Compatibility (Server Compatibility)
Score: <-To Be Scored->
Evidence:
-
Outputs standard GraphQL Schema: The
buildSchema()function ingarph/src/schema.ts(lines 17-21) outputs standardGraphQLSchema -
Compatible with standard GraphQL.js: Uses
graphql-composeto build Schema, ultimately outputs standard GraphQL Schema -
Mainly showcases graphql-yoga:
garph/www/docs/integration/server/graphql-yoga.mdprovides detailed integration documentation -
Supports other Servers:
garph/www/docs/integration/server/apollo-server.mdandmercurius.mdexist (although content incomplete)
Code Example:
// Output standard GraphQL Schema
const schema = buildSchema({ g, resolvers })
// Can integrate with any GraphQL Server
const yoga = createYoga({ schema }) // graphql-yoga
// or
const server = new ApolloServer({ schema }) // Apollo Server
Analysis:
- ✅ Compatible with standard GraphQL.js: Outputs standard
GraphQLSchema, can integrate into any GraphQL Server - ✅ Not bound to specific Server: Can integrate with Apollo Server, GraphQL Yoga, Envelop, Hono, etc.
- ⚠️ Needs manual adaptation: Although compatible, needs manual adaptation, no official adapters provided
- ⚠️ Documentation mainly showcases graphql-yoga: Other Servers' integration documentation incomplete
5.4 Toolchain Integration (Toolchain Integration)
Score: <-To Be Scored->
Evidence:
TypeScript/JavaScript Support:
-
TypeScript native: Core files like
garph/src/index.ts,garph/src/schema.tsare all written in TypeScript -
Compiled to JavaScript:
garph/package.jsonline 10"main": "dist/index.js"indicates compiled JavaScript output -
TypeScript configuration:
garph/tsconfig.jsonshowstarget: "ESNext",module: "NodeNext", uses modern ES modules -
All examples are TypeScript: All example files in
garph/examples/directory are.tsfiles, no pure JavaScript examples
Runtime Environment Support:
-
Node.js: Explicitly supported. All official examples (
garph/examples/demo.ts,garph/examples/context.ts, etc.) use Node.js'screateServerandhttpmodules -
Bun: Documentation mentions support.
garph/www/docs/integration/server/graphql-yoga.mdlines 26-28 providebun i graphql-yogainstallation method,garph/www/docs/index.mdlines 41-43 also provide bun installation example - Deno/Cloudflare Workers: No explicit evidence. No Deno or Cloudflare Workers examples or configurations found in source code and documentation
-
Browser: Not supported. Core code
garph/src/schema.tsdepends ongraphql-composeandsingle-user-cache, these dependencies may contain Node.js-specific APIs; all examples are server-side code; no browser runtime examples or documentation
Build Tool Support:
- No explicit configuration: No webpack, vite, rspack and other build tool configuration examples found in source code and documentation
-
Uses TypeScript compiler:
garph/package.jsonline 15 build script is"build": "tsc -p tsconfig.json", only uses TypeScript compiler -
Documentation uses VitePress:
garph/package.jsonlines 12-14 show documentation uses VitePress (based on Vite), but this is documentation build tool, not framework's own build tool integration
Code Example:
// garph/examples/demo.ts - Node.js environment
import { g, InferResolvers, buildSchema } from '../src/index'
import { createYoga } from 'graphql-yoga'
import { createServer } from 'http' // Node.js specific API
const schema = buildSchema({ g, resolvers })
const yoga = createYoga({ schema })
const server = createServer(yoga) // Requires Node.js http module
server.listen(4000, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
Analysis:
- ✅ TypeScript native support: Framework completely written in TypeScript, compiled to JavaScript
- ✅ Supports Node.js and Bun: Explicitly supports Node.js, documentation mentions Bun support
- ⚠️ Does not support browser: Core dependencies may contain Node.js-specific APIs, no browser runtime evidence
- ⚠️ Deno/Cloudflare Workers support unclear: No related examples or documentation
- ⚠️ Build tool integration missing: No webpack, vite, rspack and other build tool configuration examples or documentation
- ⚠️ Mainly server-side oriented: All examples and documentation are server-side usage scenarios
Ecosystem Integration Overall Score
Score: 2.0
Scoring Basis:
- ORM integration depth: 2.0 (weak integration, needs lots of glue code)
- Validation library integration: 2.0 (weak integration, needs lots of boilerplate)
- GraphQL Server compatibility: 3.0 (standard compatible, but needs manual adaptation)
- Toolchain integration: 2.0 (mainly supports TypeScript and Node.js/Bun, does not support browser, build tool integration missing)
Advantages:
- Standard compatible: Outputs standard GraphQL Schema, can integrate with any GraphQL Server
- Not bound to specific Server: Can integrate with Apollo Server, GraphQL Yoga, Envelop, etc.
- Has example references: Provides Next.js, Nuxt, Remix integration examples
Disadvantages:
- Weak ORM integration: No official plugins, needs lots of glue code
- Weak validation library integration: Needs manual integration, validation logic separated from Schema definition
- Limited toolchain support: Does not support browser environment, Deno/Cloudflare Workers support unclear, no build tool integration examples
- Mainly server-side oriented: All examples and documentation are server-side usage scenarios, client-side usage limited
- Limited integration documentation: Mainly showcases graphql-yoga, other Servers and frameworks' documentation incomplete
📝 Summary
Overall Score: 2.7/5.0
| Dimension | Score | Description |
|---|---|---|
| Architecture Pattern | 4.5 | Builder pattern, zero magic, write and use immediately, lightweight dependencies |
| Type Definition | 3.5 | Deep inference, smart inheritance, flexible enums, Union requires manual handling |
| Resolvers & Validation | 2.9 | Automatic parameter inference, native DataLoader, no built-in validation |
| Built-in Features | 3.0 | Core features complete, advanced features missing, security features insufficient |
| Ecosystem Integration | 2.0 | Standard compatible, weak ORM/validation integration, no official adapters |
Overall Evaluation
Garph adopts the Builder pattern, achieving a zero magic, write-and-use-immediately design philosophy. Lightweight dependencies, pure runtime building, supports hot reload, excellent development experience. Native DataLoader support is a highlight, almost no boilerplate. But has limited support in validation, modularization, advanced features (Directives, Middleware, query complexity, depth limiting), and weak ORM and validation library integration.
Core Advantages
- Zero magic design: No need for decorators, reflection metadata, or code generation, fully compliant with native TypeScript best practices
- Write and use immediately: Pure runtime building, supports hot reload, fast development iteration
- DataLoader native support: Built-in batch loading, almost no boilerplate, automatic batch processing and caching
- Type safety: End-to-end type safety, excellent type inference from Schema to Resolver
-
Lightweight dependencies: Only depends on
graphql-composeandsingle-user-cache, lighter than decorator pattern
Main Disadvantages
- No built-in validation: Needs to manually write all validation logic, validation code repetitive, validation logic scattered
- Limited modular support: Organized by operation type (Query, Mutation, Type), doesn't enforce modularization, easy to write coupled code
- Advanced features missing: Directives, Middleware, Query Complexity, Depth Limiting all not supported
- Weak ORM/validation library integration: No official plugins, needs lots of glue code, type synchronization needs manual maintenance
-
Requires explicit type annotations: Resolver object needs to add
InferResolverstype annotation
Use Cases
Recommended For
- Small to medium projects, need quick startup and iteration
- Teams that need zero magic, write-and-use-immediately, prefer native TypeScript practices
- Projects with strong DataLoader requirements
- Projects that don't need Directives or Middleware
Not Recommended For
- Projects that need Directives or Middleware
- Projects that need deep ORM integration
- Projects that need declarative validation
- Projects that need query complexity analysis or depth limiting
Improvement Suggestions
-
Provide declarative validation API: Support declarative validation like
.refine(), reduce manual validation code - Enhance modular support: Provide domain-organized API, enforce module boundaries, avoid coupling
- Provide Directives and Middleware support: Meet advanced feature requirements
- Provide official plugins for ORM and validation libraries: Reduce glue code, improve integration
-
Reduce explicit type annotation requirements: Reduce
InferResolversannotations through better type inference
Top comments (0)