Graffle Documentation

repository·main·Indexed 27 days ago

https://github.com/graffle-js/graffle

A minimal, extensible, and type-safe GraphQL client for JavaScript. Graffle focuses on developer experience through full type inference and a rich extension ecosystem. The documentation covers getting started, configuring the Graffle Generator for code generation from GraphQL schemas, and advanced TypeScript guides on type diagnostics and variance (Covariant, Contravariant, and Invariant) using phantom types.

Tokens
35.5K
Snippets
121
Records
188
Agent score
90%

What's inside graffle

  1. Overview of Graffle

    main

    Graffle is a general-purpose GraphQL client for JavaScript designed to execute GraphQL documents in various runtimes, including browsers, Node.js, Deno, Bun, and Cloudflare Workers. It is optimized for scripts and backend logic rather than specialized frontend state management (unlike Relay or Urql).

    Core capabilities include:

    • Executing GraphQL requests over HTTP or in-memory.
    • Using native GraphQL document syntax.
    • Extensibility via plugins for features like OpenTelemetry or file uploads.
    • An optional generated client for enhanced developer experience.
  2. Understand Schema Driven Data Map (SDDM)

    main

    A Schema Driven Data Map (SDDM) (or Schema Map) is a specialized data structure generated by the Graffle generator. It contains minimal schema information designed to enable specific runtime features while maintaining small bundle sizes.

    Key characteristics:

    • Optimized for size: It only includes the information necessary for specific features.
    • Implementation detail: Users should generally not interact with or be aware of this structure directly.
    • Opt-in usage: Graffle avoids using SDDM by default to keep bundles small. It is only utilized when specific features are enabled.

    Features that require SDDM:

    • Custom Scalars
    • Schema Errors (via extension)
  3. Compare Graffle with other GraphQL clients

    main

    Use the following comparison to determine if Graffle is the right choice for your project based on use case, type safety, bundle size, and features.

    FeatureGraffleApollo ClientUrqlgraphql-request
    Primary Use CaseGeneral-purposeReact appsReact appsSimple HTTP
    Type Safety⭐⭐⭐ Inference + Generation⭐⭐ With codegen⭐⭐ With gql.tada⭐ Basic
    Bundle Size~50KB~150KB+~40KB~8KB
    Framework IntegrationBasic⭐⭐⭐ React⭐⭐⭐ React/Vue/SvelteBasic
    CachingExtension possible✅ Normalized✅ Optional
    Extension System✅ Type-safe✅ Apollo Link✅ Exchanges
    Document Builder✅ Optional
    Multi-Transport✅ HTTP + MemoryHTTP onlyHTTP + SSRHTTP only
    Custom Scalars✅ AutomaticManualManualManual
    Schema Errors✅ ExtensionManualManualManual
    Learning CurveMediumHighMediumLow
  4. Core features of Graffle

    main

    Graffle provides several key capabilities for working with GraphQL:

    • Spec Compliant: Complies with GraphQL over HTTP and GraphQL Multipart Request specifications.
    • Extensible: Type-safe extension system to intercept inputs/outputs or add new methods via hooks.
    • Multi-Transport: Supports querying remote APIs or executing documents against in-memory schemas.
    • Custom Scalars: Client-side codecs for automatic encoding/decoding of custom scalars.
    • Document Builder: A TypeScript alternative to GQL syntax for building type-safe documents.
    • Type Safe Results: Automatically inferred results based on selection sets, aliases, fragments, etc.
    • Output Modes: Configurable error handling via envelope (wrap results), return-error (errors as values), or throw modes.
    • Static Document Builder: Generate typed documents without a client instance for zero runtime overhead.
  5. Understand Graffle Transports

    main

    A transport defines how a GraphQL document reaches the schema for execution. Graffle supports two primary execution modes through its transport system:

    • HTTP: Used to send requests to remote GraphQL APIs over HTTP/HTTPS.
    • Memory: Used to execute documents against in-memory schemas.

    Both transports share the same client interface, enabling you to switch between remote and local execution without modifying your application logic.

  6. Understand Variable Hoisting in Graffle

    main
    Variable hoisting is the process of lifting field arguments to the GraphQL operation level as variables. Instead of embedding values directly in the query string, Graffle extracts them into a separate variables object. This improves query caching, enables automatic custom scalar encoding/decoding, and aligns with GraphQL best practices by separating query structure from data.
  7. Author an extension for Graffle

    main

    Graffle extensions allow you to extend the client with custom functionality by hooking into the request/response lifecycle or adding new methods to the client. Extensions are created using the Extension.create method.

    To implement an extension, follow this basic pattern:

    import { type Extension } from 'graffle'
    
    export const MyExtension = () => {
      return Extension.create({
        name: 'MyExtension',
        // Extension implementation
      })
    }
  8. Optimize TypeScript type performance

    main

    If you encounter performance issues (high instantiation counts), apply these common fixes:

    1. Avoid large unions in constraints: Instead of using a large union, use a structural constraint.

      • Slow: type Process<T extends Type1 | Type2 | ... | Type50> = ...
      • Fast: type Process<T extends BaseType> = ...
    2. Avoid intersection constraints: Intersections are not cached. Use an interface instead.

      • Slow: type Process<T extends Base & { x: X } & { y: Y }> = ...
      • Fast: interface Constraint extends Base { x: X; y: Y }; type Process<T extends Constraint> = ...
    3. Simplify conditional types: TypeScript evaluates conditionals eagerly. Try to lift conditionals out of the type or use mapped types to reduce deep nesting.

  9. Configure the Graffle generator

    main

    The CLI automatically looks for a graffle.config.{js,ts,mts,mjs} file in your project root. The configuration is defined via the default export of that module. Command-line arguments take precedence over settings in the configuration file.

    TypeScript Configuration Support

    • Node.js 24.0+ or 22.18+: Supports TypeScript config files natively via built-in type stripping.
    • Advanced TypeScript (enums, namespaces, etc.):
      • Recommended: Use Node's transform flag: NODE_OPTIONS=--experimental-transform-types pnpm graffle
      • Alternative: Use tsx by setting GRAFFLE_USE_TSX=1 pnpm graffle (requires tsx installed).
    • Older Node versions (< 22.18): You must use tsx:
      pnpm add -D tsx
      GRAFFLE_USE_TSX=1 pnpm graffle
    
    ```ts
    // graffle.config.ts
    import { Generator } from 'graffle/generator'
    
    export default Generator.configure({
      lint: {
        missingCustomScalarCodec: false,
      },
    })
  10. Implement direct value/type exports for safe names in TypeScript

    main

    If the name you are exporting is not a TypeScript reserved keyword or a global type, you can use direct exports. TypeScript allows export const and export type declarations to share the same name when using this syntax, avoiding identifier conflicts.

    // Works for safe names like 'Date'
    export const Date = CustomScalars.Date
    export type Date = typeof Date