Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GraphQL: How nested to make schema?

This past year I converted an application to use Graphql. Its been great so far, during the conversion I essentially ported all my services that backed my REST endpoints to back grapqhl queries and mutations. The app is working well but would like to continue to evolve my object graph.

Lets consider I have the following relationships.

User -> Team -> Boards -> Lists -> Cards -> Comments

I currently have two different nested schema: User -> team:

    type User {
  id: ID!
  email: String!
  role: String!
  name: String!
  resetPasswordToken: String
  team: Team!
  lastActiveAt: Date
}

type Team {
  id: ID!
  inviteToken: String!
  owner: String!
  name: String!
  archived: Boolean!
  members: [String]
}

Then I have Boards -> Lists -> Cards -> Comments

type Board {
  id: ID!
  name: String!
  teamId: String!
  lists: [List]
  createdAt: Date
  updatedAt: Date
}

type List {
  id: ID!
  name: String!
  order: Int!
  description: String
  backgroundColor: String
  cardColor: String
  archived: Boolean
  boardId: String!
  ownerId: String!
  teamId: String!
  cards: [Card]
}

type Card {
  id: ID!
  text: String!
  order: Int
  groupCards: [Card]
  type: String
  backgroundColor: String
  votes: [String]
  boardId: String
  listId: String
  ownerId: String
  teamId: String!
  comments: [Comment]
  createdAt: Date
  updatedAt: Date
}

type Comment {
  id: ID!
  text: String!
  archived: Boolean
  boardId: String!
  ownerId: String
  teamId: String!
  cardId: String!
  createdAt: Date
  updatedAt: Date
}

Which works great. But I'm curious how nested I can truly make my schema. If I added the rest to make the graph complete:

type Team {
      id: ID!
      inviteToken: String!
      owner: String!
      name: String!
      archived: Boolean!
      members: [String]
      **boards: [Board]**
    }

This would achieve a much much deeper graph. However I worried how much complicated mutations would be. Specifically for the board schema downwards I need to publish subscription updates for all actions. Which if I add a comment, publish the entire board update is incredibly inefficient. While built a subscription logic for each create/update of every nested schema seems like a ton of code to achieve something simple.

Any thoughts on what the right depth is in object graphs? With keeping in mind the every object beside a user needs to be broadcast to multiple users.

Thanks

like image 266
sauce Avatar asked Dec 27 '18 21:12

sauce


2 Answers

GraphQL's purpose is to avoid a couple of queries, so I'm sure that making the nested structure is the right way. With security in mind, add some GraphQL depth limit libraries.

GraphQL style guides suggest you have all complex structures in separate Object Types ( as you have, Comment, Team, Board... ). Then making a complex query/mutation is up to you.

I'd like you to expand this sentence

Which if I add a comment, publish the entire board update is incredibly inefficient

I'm not sure about this as you have your id of the Card. So adding new comment will trigger mutation which will create new Comment record and update Card with the new comment.

So your structure of data on the backend will define the way you fetch it but not so much the way you mutate it.

Take a look at the GitHub GraphQL API for example:

  • each of the mutations is a small function for updating/creating piece of the complex tree even if they have nested structure of types on the backend.

In addition for general knowledge of what are approaches for designing the mutations, I'd suggest this article.

like image 91
Yevhenii Herasymchuk Avatar answered Sep 21 '22 23:09

Yevhenii Herasymchuk


You can use nesting in GraphQL like

type NestedObject {
  title: String
  content: String
}

type MainObject {
  id: ID!
  myObject: [NestedObject]
}

In the above code, the type definition of NestObject gets injected into the myObject array. To understand better you can see it as:

type MainObject {
  id: ID!
  myobject: [
    {
      title: String
      content: String
    }
  ]
}

I Hope this solves your problem!

like image 37
Yogesh Aggarwal Avatar answered Sep 21 '22 23:09

Yogesh Aggarwal