2

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.

Sandy Gifford
  • 7,219
  • 3
  • 35
  • 65
  • what client? apollo? .... address is a separate entity - no id, no address cache entity merging – xadm Apr 21 '21 at 22:28
  • @xadm Using Apollo on the client end but it didn't even occur to me that that would matter. I assumed that how fragments merge would be defined in specs and handled the same across implementations. – Sandy Gifford Apr 22 '21 at 20:31
  • 1
    ah, API only problem? tested in playground?... I'd expect data to be merged, too ... but don't know how exactly fragments are processed/executed ... if resolved earlier (sadly fields resolving order is not guaranteed) fragment contains address then no need to resolve address type, only subfields (adding to existing) ... or fragment required fields are 1st merged to current fields in `info` (GraphQLResolveInfo) but [badly] overwritten by following defs ... I doubt it (overlapped fields from misc fragments and type fields behaviour) is defined in specs ... interesting problem, I'd ask API owners – xadm Apr 22 '21 at 22:20

2 Answers2

0

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",
      },
    },
  ],
}

*/

  • 3
    Hey, thanks for contributing! Buuuuut you should probably read up on the way things work here. You just posted an "answer" but it appears to be a little bit more of a "this happens to me too" – Sandy Gifford Apr 22 '21 at 20:34
0

Try using alias instead. Something like

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