Justin Meyer
Justin Meyer

Reputation: 1687

GraphQL - When to use a resolver or an argument with recursive and normalized data?

I'm working with a very large normalized and recursive object. I want to get the list of all recursive items. Should I use an argument or a custom resolver?

My object looks like:

{
  products: [{
    product_id: "car",
    bundle_id: 5
  },{
    product_id: "door"
    bundle_id: 6
  },
  { product_id: "wheel" },
  { product_id: "metal" },
  { product_id: "glass" }],

  bundles: [{
    bundle_id: 5,
    options: [{product_id: "door"},{product_id: "wheel"}]
  },
  {
    bundle_id: 6,
    options: [{product_id: "metal"},{product_id: "glass"}]
  }]

}

You might notice that "car" is a bundle that has a door and a wheel. "door" is also a bundle that has metal and glass. This structure could recurse indefinitely. That is, a bundle could have infinitely more bundle products underneath it.

I want to get a list of all products for a bundle (example: "car"). What is the best approach?

I see two options.

First Option - use a custom resolver, for example child_products that would recurse and resolve to a flat array of all children:

products(product_id: "car") {
  product_id
  bundle {
    options {
      product_id
    }
  }
  child_products {
    product_id
    bundle {
      options {
        product_id
      }
    }
  }
}

Second Option - use an argument that specifies including all children:

products(product_id: "car", include_children: true) {
  product_id
  bundle {
    options {
      product_id
    }
  }
}

I'm going to build a JS library that can take the array of products and options and build the nested structure. Please let me know what you think is the right way. Thanks!

Upvotes: 0

Views: 140

Answers (1)

Daniel Rearden
Daniel Rearden

Reputation: 84697

You should not need an argument like include_children because a client's query will be sufficient to determine whether to include the nodes or not -- if a client doesn't need the nodes, it can simply omit the appropriate field.

Based on the provided JSON object, I would expect a schema that looks something like this:

type Query {
  product(id: ID!): Product
}

type Product {
  id: ID!
  bundle: Bundle
}

type Bundle {
  id: ID!
  options: [Product!]!
}

which would let you make a query like:

query {
  product(id: "car") {
    id
    bundle {
      options {
        id
        bundle {
          id
          # and so on...
        }
      }
    }
  }
}

The actual depth of this query would be left up to the client's needs. Recursive type definitions like this do present a possible attack vector and so you should also look into using a library like graphql-depth-limit or graphql-query-complexity.

Upvotes: 1

Related Questions