With Relay
Using pg_grapqhl with Relay.
pg_graphql implements the GraphQL Global Object Identification Specification (Node interface) and the GraphQL Cursor Connections Specification to be compatible with Relay.
Relay Setup
Pre-requisites
Follow the Relay Installation Guide.
Configuring the Relay Compiler
Modify your relay.config.js file to reflect the following:
1. = {2 // standard relay config options3 : './src',4 : 'typescript',5 : './data/schema.graphql',6 : ['**/node_modules/**', '**/__mocks__/**', '**/__generated__/**'],7 // pg_graphql specific options8 : {9 : 'nodeId',10 : 'nodeId',11 },12 : {13 : 'string',14 : 'string',15 : 'string',16 : 'string',17 : 'string',18 : 'any',19 },20}schemaConfigtells the Relay compiler where to find thenodeIdfield on thenodeinterfacecustomScalarTypeswill improve Relay's type emission
For Relay versions older than v16.2.0, it should be named customScalars instead.
Configuring your Relay Environment
This example uses Supabase for the GraphQL server, but pg_graphql can be used independently.
1import {2 Environment,3 FetchFunction,4 Network,5 RecordSource,6 Store,7} from 'relay-runtime'89import supabase, { SUPABASE_ANON_KEY, SUPABASE_URL } from './supabase'1011const fetchQuery: FetchFunction = async (operation, variables) => {12 const {13 data: { session },14 } = await supabase.auth.getSession()1516 const response = await fetch(`${SUPABASE_URL}/graphql/v1`, {17 method: 'POST',18 headers: {19 'Content-Type': 'application/json',20 apikey: SUPABASE_ANON_KEY,21 Authorization: `Bearer ${session?.access_token ?? SUPABASE_ANON_KEY}`,22 },23 body: JSON.stringify({24 query: operation.text,25 variables,26 }),27 })2829 return await response.json()30}3132const network = Network.create(fetchQuery)33const store = new Store(new RecordSource())3435const environment = new Environment({36 network,37 store,38 getDataID: (node) => node.nodeId,39 missingFieldHandlers: [40 {41 handle(field, _record, argValues) {42 if (field.name === 'node' && 'nodeId' in argValues) {43 // If field is node(nodeId: $nodeId), look up the record by the value of $nodeId44 return argValues.nodeId45 }4647 return undefined48 },49 kind: 'linked',50 },51 ],52})5354export default environmentgetDataIDis the most important option to add, as it tells Relay how to store data correctly in the cache.missingFieldHandlersis optional in this example but helps with Rendering Partially Cached Data.
Pagination
Say you are working on a Todo app and want to add pagination. You can use @connection and @prependNode to do this.
Fragment passed to usePaginationFragment()
1fragment TodoList_query on Query2@argumentDefinitions(3 cursor: { type: "Cursor" }4 count: { type: "Int", defaultValue: 20 }5)6@refetchable(queryName: "TodoListPaginationQuery") {7 todosCollection(after: $cursor, first: $count)8 @connection(key: "TodoList_query_todosCollection") {9 pageInfo {10 hasNextPage11 endCursor12 }13 edges {14 cursor15 node {16 nodeId17 ...TodoItem_todos18 }19 }20 }21}Mutation to create a new Todo
1mutation TodoCreateMutation($input: TodosInsertInput!, $connections: [ID!]!) {2 insertIntoTodosCollection(objects: [$input]) {3 affectedCount4 records @prependNode(connections: $connections, edgeTypeName: "TodosEdge") {5 ...TodoItem_todos6 }7 }8}Code to call the mutation
1import { ConnectionHandler, graphql, useMutation } from 'react-relay'23// inside a React component4const [todoCreateMutate, isMutationInFlight] =5 useMutation<TodoCreateMutation>(CreateTodoMutation)67// inside your create todo function8const connectionID = ConnectionHandler.getConnectionID(9 'root',10 'TodoList_query_todosCollection'11)1213todoCreateMutate({14 variables: {15 input: {16 // ...new todo data17 },18 connections: [connectionID],19 },20})