Why Exposing Foreign Keys in GraphQL is Bad

There are many pitfalls in GraphQL development, and I believe exposing Foreign Keys is one. We have to start this topic with what a foreign key is and give some background on how foreign keys commonly are used in non-GraphQL environments.

Foreign Keys

A foreign key is a field where an entity's primary key is referenced from within another entity. An example of a foreign key could be an Article having an authored_by field referencing a User by its primary key. The use of foreign key describes relations between entities to answer questions like "which articles have a specific user authored".

Usage in Non-GraphQL Environments

It is common to request data based on the entitys primary key in REST and REST-like endpoints towards a specific URL, e.g. /users/[user_id] or /articles/[article_id].

The data returned to get information about a specific User could look something like this:

{
  id: "user_id",
  name: "some name",
  authored_articles: ["article_id1", "article_id2"]
}

Moreover, it could look like this for an Article:

{
  id: "article_id",
  title: "some title",
  authored_by: "user_id"
}

Suppose these are the endpoints we have available, and the user_id is the only thing known. In that case, it requires us to start fetching the User information through /users/[user_id] and then, per each article_id in authored_articles, fetch information about said Article through /articles/[article_id]. After fetching this information, we can list the titles of all Articles the User has authored.

Optimizations of cases like this are possible. We could create a specific endpoint only returning the titles a User has authored. The endpoint could be defined as /authored_titles/[user_id], which could return data as follows:

{
  titles: ["some title", "some other title"]
}

Developing and maintaining a large set of endpoints is not an easy task. Changes to client behaviour can require much rework to keep it optimized. This is where GraphQL comes with all its upsides.

GraphQL

There are many advantages to using GraphQL. One of them is solving the issues described in the "Usage in Non-GraphQL Environments" section above. A well-implemented GraphQL server should make it easy to fetch all the needed information. I believe the GraphQL query we should be able to ask our GraphQL server looks like this.

query User_Articles($userId: ID!) {
  user(id: $userId) {
    id
    articles {
      id
      title
    }
  }
}

This results in data returned looking like the following:

{
  data: {
    user {
      id: "user_id",
      articles: [
        {
          id: "article_id1",
          title: "some title"
        },
        {
          id: "article_id2",
          title: "some other title"
        }
      ]
    }
  }
}

The issue here is if we instead would design the schema to use foreign keys to reference Articles inside a User. That would put us in the same situation as the REST and REST-like environments and prevent us from querying all the data we need in one query.

Conclusion

To benefit from one of GraphQLs most significant advantages, which is to fetch exactly the data needed in one query, we need to stop exposing foreign keys and instead expose the modelled GraphQL type for the foreign entity.

Fredrik Adolfsson
Fredrik Adolfsson