Dan
Dan

Reputation: 760

How to define values specific to a connection of two nodes in GraphQL?

I have two types in my schema:

type Resident = {            type Visitor = {
  id                           id
  name                         name
}                            }

In my database:

Residents and Visitors Tables:

+--------+-------+   +--------+---------+
| res_id | name  |   | vis_id | name    |
+--------+-------+   +--------+---------+
|  1     | Alice |   |  1     | Charlie |
|  2     | Bob   |   +--------+---------+
+--------+-------+

And then a table that shows which visitor belongs to which resident:

+--------+--------+--------------+
| res_id | vis_id | relationship |
+--------+--------+--------------+
|      1 |      1 | fam/fri      |
|      2 |      1 | contractor   |
+--------+--------+--------------+

Each visitor could either be a "fam/fri" or a "contractor" to a resident. So Charlie is Alice's visitor as her family or friend. However, Charlie is also a visitor to Bob, but instead as a contractor.

Question: How do I structure my schema so that when I query Alice, Charlie returns as a fam/fri, and when I query Bob, Charlie is returned as a contractor? I imagine this:

{
  Resident(id: 1) {             "Resident" {
    name                           "Alice"
    Visitor {                      "Visitor" {
      id                ===>          "1"
      name                            "Charlie"
      relationship                    "fam/fri"
    }                              }
  }                             }
}

and also:

{
  Resident(id: 2) {             "Resident" {
    name                           "Bob"
    Visitor {                      "Visitor" {
      id                ===>          "1"
      name                            "Charlie"
      relationship                    "contractor"
    }                              }
  }                             }
}

Upvotes: 0

Views: 36

Answers (1)

Daniel Rearden
Daniel Rearden

Reputation: 84707

Something like:

type Query {
  resident(id: Int): Resident
}

type Resident {
  id: Int!
  name: String!
  visitors: [Visitor!]!
}

type Vistor {
  id: Int!
  name: String!
  relationship: VisitorRelationship!
}

enum VisitorRelationship {
  CONTRACTOR
  FAMILY_OR_FRIEND
}

Note that by convention field names should be camelCase and type names should be in PascalCase. If the data returned from your data source (whether that's a database, API, or whatever) is not in the same shape as what you want to return from your GraphQL service, then you should transform the data before returning it inside your resolver, for example:

const relationshipMap = {
  'fam/fri': 'FAMILY_OR_FRIEND',
  'contractor': 'CONTRACTOR',
}

const resolvers = {
  Query: {
    resident: (root, args) => {
      const resident = await Resident.findById(args.id)
      // assuming resident has a property named joinTable that's
      // an array and each relationship has a property named visitor
      return {
        ...resident,
        visitors: resident.joinTable.map(relationship => {
          return {
            ...joinTable.visitor,
            relationship: relationshipMap[joinTable.relationship],
          }
        })
      }
    },
  },
}

You can also map enums to custom values this way.

Upvotes: 1

Related Questions