Search code examples
reactjsreact-nativeapolloapollo-client

How to populate client-side schema on Apollo 3.0 using typePolicies


I'm asking this question because I wasn't able to find any ressource on the web (including SO, but also the documentation of Apollo-Client which is quite laconic on the subject), and I'm a out of solution.

I've got this client-side schema :

const typeDefs = gql'

    extend type Query @client {
        getMessageSliceByIdMessaging(id_messaging: String!): [MESSAGE_SLICE]!,
    }

    type MESSAGE_SLICE {
        _id: String!,
        __typename: String!,
        newest_date_creation: String!,
        oldest_date_creation: String!,
        list_id_message: [MESSAGE]!,
    },

'

I've made this typePolicies in the InMemoryCache

typePolicies: {
   Query: {
      fields: {
         getMessageSliceByIdMessaging : {
            merge(existing = [], incoming = [], {cache}) {
               //Doing some shenanigans
               return some_shenanigans
            },
            read(existing = []) {
               return [...existing] //existing properly return "some_shenanigans" generate in merge function
            },
         }
      }
   }
}

But, despite the read function returning the correct "some_shenanigans", when I'm calling :

///FRAGMENT OF MESSAGE_SLICE
const MESSAGE_SLICE_FRAGMENT = gql`
    fragment MessageSliceFragment on MESSAGE_SLICE {
        _id,
        newest_date_creation,
        oldest_date_creation,
        list_id_message {
            ...messageFragment,
        },
    },
    ${MESSAGE_FRAGMENT}
`

///QUERY TO GET A LIST OF MESSAGE_SLICE
const GET_MESSAGE_SLICE_BY_ID_MESSAGING = gql`
    query getMessageSliceByIdMessaging (
        $id_messaging: String!,
    ) {
        getMessageSliceByIdMessaging @client (
            id_messaging: $id_messaging,
        ) {
            ...MessageSliceFragment,
        },
    },
    ${MESSAGE_SLICE_FRAGMENT}
`

///CALL OF THE QUERY
const messageSliceListData = useQuery(GET_MESSAGE_SLICE_BY_ID_MESSAGING, {
   variables: {
      id_messaging: route.id_messaging,
   },
})

///CALLING THIS ALLOW TO PAST DATA TO THE MERGER (missing context, but work properly)
await client.writeQuery({
   query: GET_MESSAGE_SLICE_BY_ID_MESSAGING,
      variables: {
         id_messaging,  
      }, 
   data: {getMessageSliceByIdMessaging: [...SOME_ARRAY_DATA_THAT_NEED_TO_BE_MERGE_IN_THE_TYPE_POLICIES]}
})

messageSliceListData?.data always return [{}] or undefined, and I don't get any Error.

Some thing that I've tried :

  • Returning some_shenanigans as a reference (using toReference),
  • Returning some_shenanigans as raw data.

I wasn't able to find a tutorial or other sources treating this question with Apollo 3.0 and typePolicies (apart from this link: https://www.apollographql.com/tutorials/fullstack-quickstart/10-managing-local-state, but it's using reactives variables, not typePolicies)

So what is the proper way to implement such a solution ?

N.B : I'm using this in a React-Native App, and I'm not in capacity to use the Apollo Developer Tools.


Solution

  • So, I've resolved my problem, and had succeed in getting my data properly.

    There was a typo in my code elsewhere, and sometime the result of useQuery(GET_MESSAGE_SLICE_BY_ID_MESSAGING) return an undefined at the second call (easy turnaround with useEffect).

    Howerver, I've test some things and I want to share it if someone else struggle with the populate of local Schema :

    You need to return the Schema with raw data for the inner props and with ref for relations.

    Example :

    For this Schema :

    type MESSAGE_SLICE {
       _id: String!,   
       __typename: String!,
       newest_date_creation: String!,
       oldest_date_creation: String!,
       list_id_message: [MESSAGE]!,
    },
    

    You need to return an object of this type :

    CORRECT_FORMAT_FOR_MESSAGE_SLICE_TO_RETURN = [{
       _id: SOME_ID,
       __typename: "MESSAGE_SLICE",
       newest_date_creation,
       oldest_date_creation,
       list_id_message: [
          {__ref: "MESSAGE:ID_OF_MESSAGE_,"}, 
          {__ref: "MESSAGE:ID_OF_MESSAGE_2"},
       ] 
    }]
    

    Returning only the apollo ref of MESSAGE_SLICE will not work :

    WRONG_FORMAT_FOR_MESSAGE_SLICE_TO_RETURN = [
       {__ref: "MESSAGE_SLICE:ID_OF_MESSAGE_SLICE_1"},
       {__ref: "MESSAGE_SLICE:ID_OF_MESSAGE_SLICE_2"},
    ]
    

    And returning raw data for all MESSAGE_SLICE and relation will not work either:

    WRONG_FORMAT_FOR_MESSAGE_SLICE_TO_RETURN = [{
       _id: SOME_ID,
       __typename: "MESSAGE_SLICE",
       newest_date_creation,
       oldest_date_creation,
       list_id_message: [
          {
             _id: SOME_ID,
             __typename: "MESSAGE",
             id_user: "SOME_ID",
             content_message: "SOME_CONTENT"
          }, 
          {
             _id: SOME_ID,
             __typename: "MESSAGE",
             id_user: "SOME_ID",
             content_message: "SOME_CONTENT"
          },
       ] 
    }]
    

    An another thing, in the defintion of Schema, __typename isn't mandatory BUT (see below):

    type MESSAGE_SLICE {
       _id: String!,   
       __typename: String!, //this line is optionnal, BUT (see below again).
       newest_date_creation: String!,
       oldest_date_creation: String!,
       list_id_message: [MESSAGE]!,
    },
    

    BUT, you need to init a __typename in some way.

    It's possible to proceed in this way:

    CORRECT_FORMAT_FOR_MESSAGE_SLICE_TO_RETURN = [{
       _id: SOME_ID,
       __typename: "MESSAGE_SLICE", //Init this props in the merger function when creating a new MESSAGE_SLICE
       newest_date_creation,
       oldest_date_creation,
       list_id_message: [
          {__ref: "MESSAGE:ID_OF_MESSAGE_,"}, 
          {__ref: "MESSAGE:ID_OF_MESSAGE_2"},
       ] 
    }]
    

    Or in this way, using typePolicies :

    typePolicies: {
        MESSAGE_SLICE: {
            fields: {
                __typename: {
                    read() {
                        return "MESSAGE_SLICE"
                    }
                },
            },
        },
    }
    

    Hoping that this will help someone.