Deep merging fragments

870 Views Asked by At

I'm using a GraphQL API (which I do not own) to access data. I make extensive use of fragments and one problem I've run into more than once is that fragments don't seem to deep-merge. Consider the following query:

fragment BasicInfo on Person {
    id
    name
    address {
        city
        country
    }
}

query ProfileCard($id: ID) {
    personById(id: $id) {
        ...BasicInfo
        id
        age
        address {
            streetName
            streetNumber
        }
    }
}

Here we run a basic query to get some information from a profile card including the person's age and some of their address (street name and number). Another component used by the profile card also wants some info which can be found in the BasicInfo fragment. This includes their name as well as their city and country.

Running this query returns an object that contains the following fields: id, name, age, address.streetName and address.streetNumber.

address.city and address.country are both missing - it appears that the query did not deep-merge the fragment in and only inserted it at a shallow level.

Is it possible to force my fragments to deep-merge? Is this even the expected behavior? Do I have to get in contact with the API owners to correct this?

I've had trouble finding documentation that says it should be one way or the other.

2

There are 2 best solutions below

1
Corey Kovalik On

I have just run into a similar issue using @apollo/client, and funny enough it's also related to an address model. My second fragment seems to be completely disregarded and not merged. I wrote up a foobar code sample below:

type Request = {
  id: string
  stops: Array<Stop>
}

type Stop = {
  id: string;
  address: Address;
}

type Address = {
  id: string;
  address1: string;
  name: string;
}

const ROOT_FRAGMENT = gql`
  fragment foo_Request on Request {
    id
    stops {
    ...bar_Stop
    ...qux_Stop
    }
    ${STOP_FRAGMENT_1}
    ${STOP_FRAGMENT_2}
}
`;

const STOP_FRAGMENT_1 = gql`
  fragment bar_Stop on Stop {
    id
    address {
      id
      address1
    }
  }
}
`;

const STOP_FRAGMENT_2 = gql`
  fragment qux_Stop on Stop {
    id
    address {
      id
      name
    }
  }
}
`;

/*

expected: 
{
  id: "request-1"
  stops: [
    {
      id: "stop-1",
      address: {
        id: "address-1",
        address1: "123 my way",
        name: "Home",
      },
    },
  ],
}

actual: 
{
  id: "request-1"
  stops: [
    {
      id: "stop-1",
      address: {
        id: "address-1",
        address1: "123 my way",
      },
    },
  ],
}

*/

0
Brian Pham On

Try using alias instead. Something like

fragment BasicInfo on Person {
      id
      name
      cityCountryAddress: address {
          city
          country
      }
  }