GraphQL

With Apollo

Using pg_grapqhl with Apollo.


This guide will show you how to use pg_graphql with Apollo and GraphQL Code Generator for type-safe GraphQL queries in your React application.

Apollo Setup

Pre-requisites

  1. Follow the Apollo Getting Started Guide.
  2. Follow the GraphQL Code Generator Installation Guide.

Configuring GraphQL Code Generator

Modify your codegen.ts file to reflect the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import type { CodegenConfig } from '@graphql-codegen/cli'import { addTypenameSelectionDocumentTransform } from '@graphql-codegen/client-preset'const config: CodegenConfig = { schema: 'http://localhost:54321/graphql/v1', // Using the local endpoint, update if needed documents: 'src/**/*.tsx', overwrite: true, ignoreNoDocuments: true, generates: { 'src/gql/': { preset: 'client', documentTransforms: [addTypenameSelectionDocumentTransform], plugins: [], config: { scalars: { UUID: 'string', Date: 'string', Time: 'string', Datetime: 'string', JSON: 'string', BigInt: 'string', BigFloat: 'string', Opaque: 'any', }, }, }, }, hooks: { afterAllFileWrite: ['npm run prettier'], // optional },}export default config

Configuring Apollo Client

This example uses Supabase for the GraphQL server, but pg_graphql can be used independently.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import { ApolloClient, InMemoryCache, createHttpLink, defaultDataIdFromObject} from '@apollo/client'import { setContext } from '@apollo/client/link/context'import { relayStylePagination } from '@apollo/client/utilities'import supabase from './supabase'const cache = new InMemoryCache({ dataIdFromObject(responseObject) { if ('nodeId' in responseObject) { return `${responseObject.nodeId}` } return defaultDataIdFromObject(responseObject) }, possibleTypes: { Node: ['Todos'] }, // optional, but useful to specify supertype-subtype relationships typePolicies: { Query: { fields: { todosCollection: relayStylePagination(), // example of paginating a collection node: { read(_, { args, toReference }) { const ref = toReference({ nodeId: args?.nodeId, }) return ref }, }, }, }, },})const httpLink = createHttpLink({ uri: 'http://localhost:54321/graphql/v1',})const authLink = setContext(async (_, { headers }) => { const token = (await supabase.auth.getSession()).data.session?.access_token return { headers: { ...headers, Authorization: token ? `Bearer ${token}` : '', }, }})const apolloClient = new ApolloClient({ link: authLink.concat(httpLink), cache,})export default apolloClient
  • typePolicies.Query.fields.node is also optional, but useful for reducing cache misses. Learn more about Redirecting to cached data.

Example Query

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { useQuery } from '@apollo/client'import { graphql } from './gql'const allTodosQueryDocument = graphql(/* GraphQL */ ` query AllTodos($cursor: Cursor) { todosCollection(first: 10, after: $cursor) { edges { node { nodeId title } } pageInfo { endCursor hasNextPage } } }`)const TodoList = () => { const { data, fetchMore } = useQuery(allTodosQueryDocument) return ( <> {data?.thingsCollection?.edges.map(({ node }) => ( <Todo key={node.nodeId} title={node.title} /> ))} {data?.thingsCollection?.pageInfo.hasNextPage && ( <Button onClick={() => { fetchMore({ variables: { cursor: data?.thingsCollection?.pageInfo.endCursor, }, }) }} > Load More </Button> )} </> )}export default TodoList