Search code examples
javascriptgraphqlapolloapollo-clientreact-apollo

How to descibe type for nested object ? How to Describe union types?


I`m trying to write my typeDefs for Queries.

import {gql} from "@apollo/client";

const typeDefs = gql`
    
    type Query{
        rockets:[Rocket]!
        rocket(id:ID):Rocket!
    }
    type Rocket {
        id:ID!
        name:String!
        mass:RocketMass
    }
    type MassInt{
        kg:Int
    }    
    type MassFloat{
        kg:Float
    }
    
    union Mass = MassInt|MassFloat

    type RocketMass {
        kg: Mass
        lb: Mass
    }

`
export {typeDefs}

When i write my "GET_ROCKET" query i get an error in my IDE.

import {gql} from "@apollo/client";

const GET_ROCKETS = gql`
    query GetRockets {
        rockets{
            id,
            name
        }
    }
`
const GET_ROCKET = gql`
    query GetRocket($id:ID!){
        rocket(id: $id){
        mass {
            kg,
            lb
        }
        name
    }
    }
`
export {GET_ROCKETS, GET_ROCKET}

enter image description here

Could anyone explain how I can use properties "kg" and "lb" which are described in my typedefs and why I can't write unions like this ? union Mass2 = Int|Float


Solution

  • You need to give different names for MassInt.kg and MassFloat.kg fields, otherwise, it will throw a conflict error.

    See union types official document.

    The correct typeDefs and GET_ROCKET GraphQL query should be like this:

    import express from 'express';
    import { ApolloServer, gql } from 'apollo-server-express';
    import faker from 'faker';
    const app = express();
    
    const typeDefs = gql`
      type Query {
        rockets: [Rocket]!
        rocket(id: ID): Rocket!
      }
      type Rocket {
        id: ID!
        name: String!
        mass: RocketMass
      }
      type MassInt {
        int: Int
      }
      type MassFloat {
        float: Float
      }
    
      union Mass = MassInt | MassFloat
    
      type RocketMass {
        kg: Mass
        lb: Mass
      }
    `;
    
    const resolvers = {
      Query: {
        rocket: (_, { id }) => {
          return {
            id: 1,
            name: faker.lorem.word(),
            mass: {
              kg: { int: 100 },
              lb: { float: 10.1 },
            },
          };
        },
      },
      Mass: {
        __resolveType: (obj) => {
          if (isInt(obj.int)) {
            return 'MassInt';
          }
          if (isFloat(obj.float)) {
            return 'MassFloat';
          }
          return null;
        },
      },
    };
    
    function isInt(n) {
      return Number(n) === n && n % 1 === 0;
    }
    
    function isFloat(n) {
      return Number(n) === n && n % 1 !== 0;
    }
    const server = new ApolloServer({ typeDefs, resolvers });
    const port = 4000;
    server.applyMiddleware({ app, path: '/graphql' });
    app.listen(port, () => console.log(`Apollo server started at http://localhost:${port}`));
    
    query GetRocket($id: ID){
      rocket(id: $id){
        id
        name
        mass {
          kg {
            ... on MassInt {
              int
            }
            ... on MassFloat {
              float
            }
          }
          lb {
            ... on MassInt {
              int
            }
            ... on MassFloat {
              float
            }
          }
        }
      }
    }
    

    query result:

    {
      "data": {
        "rocket": {
          "id": "1",
          "name": "modi",
          "mass": {
            "kg": {
              "int": 100
            },
            "lb": {
              "float": 10.1
            }
          }
        }
      }
    }