Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

effector-apollo

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

effector-apollo

Effector bindings for Apollo Client

  • 0.5.0
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
1
decreased by-66.67%
Maintainers
1
Weekly downloads
 
Created
Source

effector-apollo

A lightweight wrapper around Apollo Client to interoperate with ☄️ Effector. Create and manage your GraphQL Queries & Mutations declaratively, with Effector, while using powerful Apollo Client features, like normalized cache and Apollo Link.

🔗 Installation & use

$ npm install effector-apollo
# or
$ yarn add effector-apollo
# or
$ pnpm add effector-apollo

Note that this library requires effector@23 and @apollo/client as peer dependencies, so make sure you have them installed in your project.

API

createQuery

Creates a new query that allows you to read data from GraphQL server or cache on request.

Options:

  • client: ApolloClient | Store<ApolloClient> that the query will use to fetch data
  • document: DocumentNode describing your query
  • context: DefaultContext? allows you to (optionally) provide arbitrary context to your Apollo Link

Returns: a new Query instance

Query

Commands:

  • start: EventCallable<Variables> unconditionally starts your query, and will send a network request
  • refresh: EventCallable<Variables> will refresh the query, using cache if possible
  • reset: EventCallable<void> resets your query to its initial state

Query state:

  • $data: Store<Data | null> containing your query data
  • $error: Store<ApolloError | null> possibly containing query execution error
  • $status: Store<'initial' | 'pending' | 'done' | 'fail'> reflecting current status of your query, which is also split into separate 'convenience' stores
    • $idle: true if the Query has not ever started
    • $pending: true if the Query is currently fetching
    • $failed: true if the Query has failed with some ApolloError
    • $succeeded: true if the Query has succeeded with data
    • $finished: true if the Query has finished with either success or failure

Query state events:

  • finished.success: Event<{ variables: Variables; meta: QueryMeta, data: Data }> is fired when your Query succeeds, providing variables that you called the query with, and data that the query has returned
  • finished.failure: Event<{ variables: Variables; meta: QueryMeta, error: ApolloError }> is fired when your Query fails, providing variables and the corresponding error
  • finished.finally: Event is fired when your Query finishes with either status: "done" or status: "fail", and will provide you with data/error
Example usage
const query = createQuery({
  client,
  document: gql`
    query user {
      user {
        id
        name
      }
    }
  `,
})

sample({
  clock: appStarted,
  target: query.start,
})

createMutation

Creates a new mutation to modify data on your GraphQL server.

Options:

  • client: ApolloClient | Store<ApolloClient> that the mutation will use to fetch data
  • document: DocumentNode describing your mutation
  • context: DefaultContext? allows you to (optionally) provide arbitrary context to your Apollo Link

Returns: a new Mutation instance

Mutation

Commands:

  • start: EventCallable<Variables> unconditionally starts your Mutation, and will send a network request immediately
  • reset: EventCallable<void> resets your mutation to its initial state

Mutation state:

  • $status: Store<'initial' | 'pending' | 'done' | 'fail'> reflecting current status of your Mutation, which is also split into separate 'convenience' stores
    • $idle: true if the Mutation has not ever started
    • $pending: true if the Mutation is currently fetching
    • $failed: true if the Mutation has failed with some ApolloError
    • $succeeded: true if the Mutation has succeeded with data
    • $finished: true if the Mutation has finished with either success or failure

Mutation state events:

  • finished.success: Event<{ variables: Variables; data: Data }> is fired when your Mutation succeeds with data that the GraphQL server has returned
  • finished.failure: Event<{ variables: Variables; error: ApolloError }> is fired when your Mutation fails with the corresponding execution error
  • finished.finally: Event that's fired when your Mutation finishes with either status: "done" or status: "fail", and will provide you with data/error

createFragmentBinding

createFragmentBinding sets up a light, read-only binding into Apollo Cache. This can come in handy to access entities from your Apollo Cache without requiring a specific Query to do that.

Like useFragment from Apollo Client, fragment binding does not trigger network requests on its own. Rather, it keeps data in sync between Apollo Cache and Effector.

Unlike useFragment, however, createFragmentBinding's primary purpose is to provide you with singleton-like entities that your business logic might requre. Common examples would be: currently logged in User entity, a specific Setting, or feature flags.

Options:

  • client: ApolloClient | Store<ApolloClient> that provides cached data

  • document: DocumentNode with a single fragment definition you want to bind

  • id: Store<string> | Store<StoreObject> to identify a specific fragment

    • When provided with Store<string>, binding will treat this as a ready-to-use Canonical Cache ID (like User:137)

    • When provided with Store<StoreObject>, binding treats this as an object with key fields that uniquely identify your fragment

      Unless you customize your cache ID, id or _id are your key fields. So, Store<{ id: string }> is usually the way to go!

      If you did customize cache ID for your fragment, provide all necessary key fields set in your type policy.

      💡 You do not need to provide __typename in this Store, as it is inferred from your fragment.

  • variables?: Store<Variables> that your fragment requires to resolve

    • You can omit this if your fragment does not require any variables
    • ⚠️ If the fragment does need variables, you must provide this option with correct Variables, otherwise you'll never receive data
  • setup: Event that the binding will initialize on (upon trigger)

    • Usually, that would be your appStarted event, but you can also use any other trigger, like Query.finished.success
  • teardown: Event tears down the binding, clearing $data and stopping listening for updates

  • optimistic?: boolean can be set to false to disable reading optimistic cache

Returns: a new FragmentBinding

FragmentBinding

A live binding into ApolloCache for a specific fragment.

  • $data: Store<Data | null> containing your fragment data (or null if no fragment was found in Cache)
  • $active: Store<boolean> marking if your binding is active or not

watchQuery

watchQuery allows you to subscribe a particular query to Apollo Cache. By default, Query only reads data through a request, and does not read cache (unlike Apollo's React hooks).

This operator allows you to connect Query to cache if you expect other parts of your app to request the same query. This will help you avoid extra requests.

Options:

  • query: Query that you want to subscribe to cache
  • optimistic?: boolean can be set to false to disable reading optimistic cache
  • client?: ApolloClient | Store<ApolloClient> to use cache from. Will use the client from createQuery if not provided

keepFresh

Enables automatic refreshes for a query, ensuring that the data stays up-to-date in response to specific events or triggers.

Options:

  • query: Query you want to keep fresh
  • triggers: Array<Event | TriggerProtocol> containing triggers that will invalidate the query and initiate a network request for fresh data. Trigger can be either:
  • enabled?: Store<boolean> that controls whether the automatic refresh is enabled or disabled. If ommited, defaults to always enabled
Example usage:

Fetch the query when network connection is restored

import { keepFresh, createQuery } from "effector-apollo"
import { trackNetworkStatus } from "@withease/web-api"

const userQuery = createQuery({ client, document: USER_QUERY })

// If the connection is lost, fetch User as soon as it is restored
keepFresh(userQuery, {
  triggers: [trackNetworkStatus],
})

Refetch a related query when a mutation fails

import { keepFresh, createQuery, createMutation } from "effector-apollo"

const userQuery = createQuery({ client, document: USER_QUERY })
const updateCountryMutation = createMutation({ client, document: UPDATE_COUNTRY_MUTATION })

// When update fails, data may become inconsistent,
// so we refetch User, ensuring data is most up to date
keepFresh(userQuery, {
  triggers: [updateCountryMutation.finished.failure],
})

paginate

paginate creates a fetchMore-like function for your query, allowing for easy pagination powered by Apollo Cache.

Note that this operator requires two things from you to work properly:

  1. You must define a proper Field Policy on a paginated field using a merge function of InMemoryCache. This allows to store paginated results in the cache
  2. The Query must not be "idle" when you use pagination. Fetch the Query using .refresh or .start before paginating.

Triggering the event returned by paginate(query) will

  • shallowly merge last used query variables and new variables provided to paginate
  • execute the query to fetch the next page based on updated variables
  • merge pages using your policy (as defined in InMemoryCache)
  • store results in query.$data

Read more about Pagination API in Apollo.

Options:

  • query: Query that will be paginated

Returns: EventCallable<Partial<Variables>> which you can call to fetch the next page

Example usage:

Paginate a query using a cursor in a Relay-style pagination.

import { createQuery, paginate } from "effector-apollo"
import { gql } from "@apollo/client"

const document = gql`
  query list($cursor: String) {
    items(cursor: $cursor) {
      nodes {
        id
      }

      pageInfo {
        endCursor
      }
    }
  }
`

const listQuery = createQuery({ client, document })

const nextPageRequested = createEvent<void>()

sample({
  // when the next page is requested
  clock: nextPageRequested,
  // take the end cursor of the list
  source: listQuery.$data.map(({ items }) => items.pageInfo.endCursor),
  // construct an update to query variables
  fn: (cursor) => ({ cursor }),
  // launch pagination
  target: paginate(listQuery),
})

optimistic

optimistic helps you define an optimistic response for your mutation. This will fill in data in Apollo Cache when running the mutation, so that your UI is responsive to user action. See more in Apollo Client "Optimistic results" documentation.

Options:

  • mutation: Mutation that you want to define an optimistic response for
  • fn: Variables => Data function that constructs an optimistic response for a mutation
  • client?: ApolloClient | Store<ApolloClient> to write response to. Will use the client from createMutation if not provided

💬 Pick your library

When starting a new project from scratch, please, take a look at Farfetched, a great data fetching tool, before using effector-apollo.

This library is an interoperability layer for projects that already use Apollo Client. It makes your life easier by giving you access to your GraphQL data from Effector.

This library strives to keep its API similar to Farfetched so that your future migration to this tool is simpler.

Releases policy

Versions 0.x.x may contain breaking changes in minor releases, which will be documented.

Keywords

FAQs

Package last updated on 07 May 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc