0

If an existing service supporting the following GraphQL queries respectively:

query to a person's bank account:

query {
    balance(id: "1") {
      checking
      saving
    }
}

result

{
  "data": {
    "balance": {
      "checking": "800",
      "saving": "3000"
    }
  }
}

query to a person's pending order:

query {
    pending_order(id: "1") {
      books
      tickets
    }
}

result

{
  "data": {
    "pending_order": {
      "books": "5",
      "tickets": "2"
    }
  }
}

The source code achieving the above functionality is something like this:

module.exports = new GraphQLObjectType({
  name: 'Query',
  description: 'Queries individual fields by ID',

  fields: () => ({
    balance: {
      type: BalanceType,
      description: 'Get balance',
      args: {
        id: {
          description: 'id of the person',
          type: GraphQLString
        }
      },
      resolve: (root, { id }) => getBalance(id)
    },
    pending_order: {
      type: OrderType,
      description: 'Get the pending orders',
      args: {
        id: {
          description: 'id of the person',
          type: GraphQLString
        }
      },
      resolve: (root, { id }) => getPendingOrders(id)
    }
  })
});

Now, I want to make my GraphQL service schema support person level schema, i.e.,

query {
    person (id: "1") {
      balance
      pending_order
    }
}

and get the following results:

{
  "data": {
     "balance": {
       "checking": "800",
       "saving": "3000"
    }
    "pending_order": {
      "books": "5",
      "tickets": "2"
    }
  }
}

How can I re-structure the schema, and how can I reuse the existing query service?

EDIT (after reading Daniel Rearden's answer):

Can we optimize the GraphQL service so that we make service call based upon the query? i.e., if the incoming query is

query {
    person (id: "1") {
      pending_order
    }
}

my actually query becomes

person: {
  ...
  resolve: (root, { id }) => Promise.all([
    getBalance(id)
  ]) => ({ balance})
}
chen
  • 4,302
  • 6
  • 41
  • 70

1 Answers1

1

You're going to have to define a separate Person type to wrap the balance and pending_order fields.

module.exports = new GraphQLObjectType({
  name: 'Person',
  fields: () => ({
    balance: {
      type: BalanceType,
      resolve: ({ id }) => getBalance(id)
    },
    pending_order: {
      type: OrderType,
      resolve: ({ id }) => getPendingOrders(id)
    }
  })
});

And you're going to need to add a new field to your Query type:

person: {
  type: PersonType,
  args: {
    id: {
      type: GraphQLString
    }
  },
  // We just need to return an object with the id, the resolvers for
  // our Person type fields will do the result
  resolve: (root, { id }) => ({ id })
}

There's not much you can do to keep things more DRY and reuse your existing code. If you're looking for a way to reduce boilerplate, I would suggest using graphql-tools.

Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183