Ferry GraphQL Client

repository·master·Indexed 20 days ago

https://github.com/gql-dart/ferry

A fully-typed GraphQL client for Flutter and Dart featuring a normalized cache, automatic code generation, and built-in Flutter widgets. The ecosystem includes ferry_generator and ferry_generator2 for creating typed OperationRequests, ferry_cache for type-safe data management, ferry_exec for operation execution, and ferry_hive_ce_store for persistent storage using hive_ce.

Tokens
27.9K
Snippets
97
Records
126
Agent score
70%

What's inside ferry

  1. Overview of Ferry GraphQL Client

    master

    Ferry is a simple and powerful GraphQL client designed for Flutter and Dart. It provides a fully typed experience with compile-time checks and IDE autocomplete for both network operations and cache interactions.

    Key capabilities include:

    • Code Generation: Automatically generates immutable data classes for GraphQL Operations and Fragments based on your schema.
    • Normalized Cache: Features a normalized, optimistic cache to keep data in sync and allow for instant UI updates.
    • Customizable Networking: Uses gql_link to allow composing and extending Links for highly customizable network interfaces.
    • Persistence: Supports multiple data stores via the Store interface, including MemoryStore and HiveStore (for offline persistence using hive).
    • Flutter Integration: Provides out-of-the-box Flutter Widgets for handling Queries, Mutations, and Subscriptions.
    • Performance: Can run queries in a separate Isolate to keep the UI thread responsive.
  2. Introduction to Ferry GraphQL Client

    master

    Ferry is a highly productive, full-featured, and extensible GraphQL Client designed specifically for Flutter and Dart. It provides a fully typed experience with compile-time checks and IDE autocomplete, powered by a built-in code generator that creates immutable data classes for GraphQL Operations and Fragments based on your schema.

    Key features include:

    • Normalized Optimistic Cache: Keeps data in sync and allows for instant UI updates.
    • Multiple Data Stores: Supports extensible storage, including MemoryStore and HiveStore for offline persistence.
    • Cache Management: Supports manual cache eviction and automatic garbage collection.
    • Pagination & Refetching: Built-in support for seamless pagination and response updates.
    • Flutter Integration: Includes an Operation Widget for use within Flutter applications.
    • Extensibility: Built on a composable TypedLink architecture (a typed version of the gql_link ecosystem).
  3. Overview of ferry_flutter

    master

    The ferry_flutter package provides Flutter widgets designed to execute GraphQL operations using a ferry client.

    Note: These widgets are thin wrappers around Flutter's native StreamBuilder widget. Depending on your use case, you may find that you can interact with the ferry client directly in Flutter without needing these specific widgets.

  4. Normalize and denormalize GraphQL data

    master

    The normalize package provides utilities to transform hierarchical GraphQL response data into a flat, normalized Map and back again. This is primarily used for implementing efficient client-side caches.

    Core Functions

    • normalizeOperation: Writes normalized documents to a normalized Map by traversing a GraphQL DocumentNode.
    • denormalizeOperation: Reconstructs original objects from a normalized Map.
    • normalizeFragment: Writes normalized fragments to a normalized Map.
    • denormalizeFragment: Reconstructs fragments from a normalized Map.

    Entity Identification

    The library only normalizes entities that include a __typename field and a valid ID. IDs are determined using the following priority:

    1. TypePolicy.keyFields: If a TypePolicy is provided for the type.
    2. dataIdFromObject: If a custom function is provided.
    3. Default fields: The id or _id fields are used if the above are not present.
  5. Use ferry_generator to create typed OperationRequests

    master
    The ferry_generator package is a Dart code generator designed to work with the ferry client. It automatically generates fully typed OperationRequest objects based on your GraphQL operations, ensuring type safety when interacting with your GraphQL API within Dart applications.
  6. What ferry_generator2 generates

    master

    The ferry_generator2 package produces plain Dart classes (not using built_value) for the following artifacts:

    • *.ast.gql.dart: GraphQL AST constants.
    • *.data.gql.dart: Response and data models.
    • *.var.gql.dart: Variable models.
    • *.req.gql.dart: Request classes (requires ast, data, and vars outputs).
    • *.schema.gql.dart: Schema enums, input objects, and possible types map.
    • *.utils.gql.dart: Shared equality and hash helpers (when enabled).

    Key features include support for sealed class hierarchies for interfaces/unions, fragment reuse, tri-state variables via gql_tristate_value, and optional utility methods like copyWith and when/maybeWhen.

  7. What is a TypedLink and how does it work?

    master

    Ferry is built using a modular system of TypedLinks. A TypedLink is a class that implements a request() method, which returns a Stream<OperationResponse>.

    There are two main types of behavior for a TypedLink:

    1. Terminating Links: These resolve the request directly (e.g., fetching from a Cache or a Network link) and do not call a forward callback.
    2. Forwarding Links: These modify the request or response and then call the forward() callback to pass the request to the next link in the chain.

    By composing these links, you can build complex request/response pipelines.

    /// A terminating link that fetches the operation from the Cache, mapping the
    /// result to an [OperationResponse].
    class CacheTypedLink extends TypedLink {
      final Cache cache;
    
      CacheTypedLink(Cache cache) : cache = cache ?? Cache();
    
      @override
      Stream<OperationResponse<TData, TVars>> request<TData, TVars>(
        OperationRequest<TData, TVars> operationRequest, [
        forward,
      ]) => ...
    }