How to deal with relationship attributes?

From the relational model to the GraphQL schema.

Yuleidy González
Prodigy Engineering
7 min readAug 9, 2021

--

Photo by pixabay from Pexels

The Story

Yes. There is always a story behind a blog article, so I might as well just tell mine.

A few days ago, I was doing a pairing session about a Pull Request review with a couple of colleagues when the idea of writing this article suddenly hit me. “This is amazing, so simple and easy, intuitive even. I have to share this.” I thought to myself. And it was easy and intuitive, after someone pointed it out, of course.

I won’t be calling names here, but you know who you are, and you’re amazing. Thank you for teaching me this.

We were discussing an attribute that was placed in the GraphQL schema in the wrong place. I’ll be using a different example that will recreate the same scenario to explain how to deal with those attributes that do not belong to the Node or Entity but belong to their relationship instead.

We will be talking about GraphQL and the relational database model.

The General Problem

As a GraphQL beginner myself, I struggle daily to think in a “graphical way.” I like to think that this is normal. And it might be. More often than not, we developers tend to think relational when representing or modeling data. After all, we have been doing it for a few decades now. Entities and their relationships are “translated” into a GraphQL schema very quickly in our minds in a very intuitive way. Often, we do not stop to think about what is happening or why we’re doing it that way.

In this article, we will be deconstructing the steps our mind goes through when “translating” from the relational model to the GraphQL schema. There are mechanisms and patterns we can follow to improve our schema designing skills, like the example I’ll illustrate here.

The Specific Problem

Normally, we make the relational Entities into the GraphQL Nodes and their relationships into the graph’s Edges. And I say normally because sometimes we have cases when we need to “break the norm” (pun intended!). For example, we know that when designing a relational database, we want it to be normalized and in the highest normal form possible. Remember Boyce-Codd? No? Well, short version: Normalization is the process of successive transformations to relationships to make them into a more restrictive way or form. So, we have the First Normal Form aka 1NF, the 2NF, the 3NF, and finally Boyce–Codd normal form (or BCNF), a slightly stronger version of the 3NF. Voilà!

And that is how I just traveled in time, back to the classroom. I have vivid memories of those days. I can remember the teacher going through relational algebra, which I remember little to nothing about; theory of database design and such things that I never had the chance to put into practice on the job. Because who has ever been so lucky to work on a project with the need to design a database from scratch? Not me, sadly.

But, despite all the benefits of normalization, there are cases when we need to “break the norm” and de-normalize a table(s) for performance purposes. That is okay, even recommended sometimes. This being said, let’s go back to our “normal” scenario.

Illustrative Example

Speaking of going back in time to the classroom, I’ll use this example from a typical student-to-student relationship to illustrate the specific problem. Let’s say we have some advanced students, very good at relational calculus, that have signed up to help their not-so-advanced peers in this and other subjects. We need the students’ Ids and names, and probably their email addresses, to send them some good tutoring advice because we do that very well at Prodigy, and we love to share. And of course to thank them for all the hard work of both tutors and tutees. But to keep things simple, we will only keep the Id and Name. We would also need to keep track of who is tutoring whom and the date when the tutoring started.

The relational schema

We made it into step one of the database design process: the relational conceptual model, aka conceptual design. We are lucky after all; we got to do this!

We even made it to step two in our designing process: transforming this design into a relational schema. So lucky!

From here, we can quickly write the SQL code to create the actual tables and get down to business. However, we’re not doing that because it’s out of scope here. Let’s instead move into the graph.

The Solution

As we “normally” do, we will have our relational Entities as GraphQL Nodes and our relationships as GraphQL Edges. We set the attributes of the Entity as the fields of the Node.

Then, and this is the answer we’ve been waiting for and the solution to our design problem, we set the attributes of the relationship as fields of the Edge. As promised, easy and intuitive!

The Illustrated Graph

The following graph diagram is not required, but I added it for visual aid. As far as I know, there is no formalization about what visual elements to use. I guess it is all inferred from the graph theory? In any case, I have borrowed the attribute design element from the relational model because I’m original like that.

As weird as it might look in the visualized graph, the data should be where it belongs. The starting date (StartedAt) of the tutoring relationship does not make sense in the student node. Think about it for a second, and you will agree with me.

It belongs to the relationship because this StartedAt marks the date the tutoring relationship between two students began. If we put it on the Student side, then it loses the context of the other party in the relationship and its meaning. One student StartedAt what? Started being a student at school on that date? Even if we change the name to something more meaningful to the student, like StartedTutoringAt date, some students might never be tutors. Others might be tutoring more than one peer. This approach is not suitable for us because this date field belongs to the relationship.

Maybe someday, someone will come up with a more remarkable design element for the Edge than just a simple line. Maybe something cool like a diamond shape?

The GraphQL Schema

After having a visualization of the graph, we can intuitively come up with the definition of our student node and the Edge, that we will name after the relationship like this:

It would look like this is all we need, but it isn’t.

For this schema to be complete and correct, we will be adding another type, a Connection type. Connections are a more abstract concept. They are a list of edges. They come to the rescue when it comes to pagination, and they are a good way of reflecting our graph data. We won’t be talking about pagination here or go any more profound in the Connection types area. Nevertheless, if you would like to, I would suggest starting here.

For this second iteration of our schema, we will add the Connection type, again named after the relationship it represents, followed by the word Connection reserved for this specific purpose. Furthermore, we will also add the reference to that Connection as part of our student type. This way, we can query for the tutoring data right at the student level.

TL;DR

This section would have been called “Conclusion” in the old days, but I’m cool like that.

Takeaway number one from this article: follow that relational gut and add all the attributes (or fields) that belong in the relationship to the edge type.

Take also this quick legend away as number two.

Test Time

In school, we would always get a test after the lesson, so here it is yours. It has two questions. Let me know in the comments how easy or hard you find the answers.

  1. After the finals are over and students are done studying, we want to add the tutor student’s score to the tutoring experience as part of the feedback process. Where would be the best place to add it?
  2. We have analyzed here a unitary relationship from Student to Student, also known as the Parent-Child relationship. What if we wanted to do the same with a binary relationship? Use this relational model provided as an example.

The End

Alas, this is the end, and I leave paraphrasing the words of my favorite poet, “GraphQL; divine, and wild beast. When would I be able to mark your haunches with my iron?

--

--