Giter VIP home page Giter VIP logo

contentful-local-schema's Introduction

Contentful Local Schema

Build status codecov npm version

This package contains a number of utilities that allow you to sync a small Contentful space and query it in-memory without having to hit the Contentful API for every query.

This is very useful in react-native to keep a local offline copy of your content so you can power your app even when users have a spotty connection.

Configuring your data source

This library ships with a single DataSource implementation, the InMemoryDataSource. This data source is updated by calling the index method with data from the Sync API, and it exposes query methods to query data from the in-memory Map objects that hold the entries and assets.

The library also provides wrappers to keep the Data Source up to date with Contentful Sync, and back it up to something like AsyncStorage for react-native.

react-native example

import { createSimpleClient, InMemoryDataSource, addSync, addBackup } from 'contentful-local-schema'
import AsyncStorage from '@react-native-community/async-storage';

const dataSource = new InMemoryDataSource();

const spaceId = process.env.CONTENTFUL_SPACEID;
const environmentId = process.env.CONTENTFUL_ENVIRONMENT || 'master';
const contentfulClient = createSimpleClient({
  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
  space: spaceId,
  environmentId,
});

// Enable Syncing
addSync(dataSource, contentfulClient)
// Enable backup/restore to AsyncStorage
addBackup(dataSource, AsyncStorage, `contentful/${spaceId}/${environmentId}`)

/**
 * Wraps the `sync` and `backup` functions to execute a resync on demand.
 * The react integration handles this for you.
 */
export const resyncContentful = () => {
  const syncPromise = dataSource.sync();
  // In the background, after the sync finishes, backup to AsyncStorage.
  // If this fails, we don't really care because at least the sync succeeded.
  syncPromise.then(() => dataSource.backup()).catch((ex) => {
    console.error('Post-sync backup failed', ex);
  });

  return syncPromise;
};

// Cold startup: import the initial state from async storage.  This returns
// a promise that can be awaited in your initializers.
// The react integration also takes care of this.
const ensureContentfulLoaded = dataSource.restore();
  .then(
    () => resyncContentful(),
    (ex) => {
      console.error('Restore failed, executing full sync', ex);
      return resyncContentful();
    }
  )
  .catch((ex) => {
    console.error('sync failed', ex);
    throw ex;
  });

Usage with React

The contentful-local-schema/react library provides a set of React hooks to easily query your InMemoryDataSource. To get started, import and mount the provider:

import { LocalSchemaProvider } from 'contentful-local-schema/react'
import { SplashScreen } from './screens/splashScreen'

// Import your dataSource that you configured above
import { dataSource } from './dataSource';

export function App() {

  return <LocalSchemaProvider
      dataSource={dataSource}
      Loading={SplashScreen}
    >
    <Router>
      ...
    </Router>
  </LocalSchemaProvider>
}

Then in your individual screens, query the data source:

export function Home() {
  const [announcements, { loading, error, refreshing }, refresh] = useQueryEntries('announcements', { 'date[lt]': Date.now().toISOString() })

  return <FlatList
    refreshing={loading || refreshing}
    onRefresh={refresh}
    data={announcements?.items || []}
    renderItem={({ item }) => <Item {...item} />}>
  </FlatList>
}

export function Announcement({id}: {id: string}) {
  const [entry, { loading }] = useFindEntry(id)

  // Note: entry is undefined until it finishes loading
  return <View>
    <H4>{entry?.fields?.title}</H4>
    ...
  </View>
}

For more information on the various query methods, see the source files:

Note: useQuery can be used to conveniently make multi-step queries against the dataSource. Example:

// Load all the `day` entries that this conference links to, and sort them by date
const [days, { loading, error, refreshing}, refresh] = useQuery(async (dataSource) => {
  const conference = await dataSource.getEntry(conferenceId)
  const dayIds = (conference.fields.days as Link<'Entry'>[]).map((day) => day.sys.id)

  const days = await dataSource.getEntries({ content_type: 'day', 'sys.id[in]': dayIds })
  return days.items.sort(byDate)
}, [conferenceId])

Usage with GraphQL

The contentful-local-schema/graphql package exposes utilities to create a local GraphQL schema and resolvers that can be queried using the @client directive. See https://www.apollographql.com/docs/react/local-state/local-resolvers/ for details.

Ensure you have the GraphQL peer dependencies installed

$ npm install graphql graphql-type-json

Next, download the 'contentful-schema.json' file and commit it to your project repo:

$ npx contentful-local-schema
$ git add ./contentful-schema.json
$ git commit

Then, use the utilities to load the schema with resolvers into your Apollo client:

import { createLocalResolvers, createSchema } from "contentful-local-schema/graphql";
import { ApolloClient, gql, InMemoryCache } from "@apollo/client";

// Import your dataSource that you configured above
import { dataSource } from './dataSource';

// Create the schema
const schema: GraphQLSchema = await createSchema()

// Build the local resolvers around the data source
const resolvers = await createLocalResolvers(dataSource);

// Build the Apollo client from the schema and local resolvers
export const apolloClient = new ApolloClient({
  cache: new InMemoryCache(),
  link: { request: jest.fn() } as any,
  typeDefs: schema as any,
  resolvers,
});

Then you can easily query your apollo client

// Query the apollo client
const result = await apolloClient.query({
  query: gql`
    query getEvent($id: string!) {
      event(id: $id) @client {
        sys {
          id
        }
        title
      }
    }
  `,
  variables: {
    id: "1234",
  },
});

expect(result.errors).toBeUndefined();
const { event } = result.data;
expect(event.sys.id).toEqual("1234");
expect(event.title).toEqual("The event title");

see src/index.spec.ts for more cool queries

Installation:

npm install contentful-local-schema

Or with yarn

yarn add contentful-local-schema

If using typescript:

This package relies on types from @apollo/client. If you don't already have it as a peer dependency, you should install it as dev dependencies in order to compile with Typescript.

npm install --save-dev @apollo/client
yarn add --dev @apollo/client

License

The gem is available as open source under the terms of the MIT License.

Code of Ethics

The developers at Watermark Community Church have pledged to govern their interactions with each other, with their clients, and with the larger wcc-contentful user community in accordance with the "instruments of good works" from chapter 4 of The Rule of St. Benedict (hereafter: "The Rule"). This code of ethics has proven its mettle in thousands of diverse communities for over 1,500 years, and has served as a baseline for many civil law codes since the time of Charlemagne.

See the full Code of Ethics

contentful-local-schema's People

Contributors

gburgett avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.