I had to choose between GraphQL and REST to build the API for the gamification app I'm currently working on. I chose GraphQL to start with and possibly add REST endpoints later if needed. At first, I started building API with REST because I don't have a lot of experience with GraphQL but switched to GraphQL after a day.

Why REST?

Laravel makes building REST APIs so much easier, it took me about three hours to set up all the necessary routes, resources & basic CRUD controllers on the main entities of my app which are:

  • User
  • Goal
  • Achievement
  • Metric

It's a lot simpler to start building API with REST than with GraphQL, especially for those who don't have a lot of experience building APIs. In under three hours, I was already able to query users, create goals, attach achievements to goals & configure metrics. This seemed pretty good start given that I only spent three hours. Then I thought about more complex queries that I and the end-user would want to run. For example, select Goal Name, associated achievements' name and icon, & associated metric's progress. To achieve this with REST it would probably take at least three separate requests:

  1. GET /goals/
  2. For each goal: GET /goals/GOAL_ID/achievements
  3. For each goal: GET /goals/GOAL_ID/metric

The issue is that these endpoints would be returning not just the columns that I need but a lot of other stuff. I only need Goal Name, Achievement Name & Icon, and Metric's progress. Of course, I could simply just build a single endpoint & fetch only these columns from there, but I would need a lot of endpoints like this to cover all cases. I could also just add ?fields= parameter or ?only= to specify the columns to select, in short, it's possible to get this working with REST but it did not feel right for me. So, I decided to give GraphQL a try the next day.

Why GraphQL?

The same query I described above could be done via this simple query submitted to a single endpoint /graphql:

query {
    goals {
        id,
        name,
        achievements {
            id,
            name,
            icon
        }
        metric {
            progress
        }
    }
}

Easy right? I was hooked, but it did not turn out to be as simple as I thought which is why probably many others like me hesitate from using GraphQL. The reason is that it requires a bit of setup before you can fully understand & take advantage of GraphQL. Before I wrote that above query I read through the learn docs on the GraphQL website https://graphql.org/learn/. You need to understand what's going on behind the scenes and how it works to get more excited about it & know what to do. I probably hesitated using GraphQL before because I thought it was too complicated, but once you go through the documentation, few tutorials & start working with it, it's not so bad. The benefit definitely outweighs the cost. After spending about a day reading & learning more about GraphQL, I was ready to begin. I had to find the appropriate library that works with Laravel & provides GraphQL implementation. There are two major libraries that I found, graphql-laravel by rebing and Lighthouse by nuwave. I was presented with yet another dilemma, which one do I use?

Rebing GraphQL vs Lighthouse

Both of them are great libraries & a lot of effort was put into both. Each one has its pros & cons, but its too early for me to judge & define the pros & cons, you should pick the one that feels right for your use case. I tried both of them and decided to go with the Lighthouse. I started with rebing first, I had to set up quite some boilerplate, like types. It felt like the code was getting out of hand and was being all over the place. It's very possible that I misused some of its functionality or did not use some of the features it offers. I then tried Lighthouse, the documentation is amazing, it reminds me of Laravel's documentation which is the best documentation I've seen. Lighthouse offers a way to use most of the code created for rebing but I decided to rewrite because I wanted to try it out. Lighthouse is SDL first which is one of the reasons it got my attention. It felt more organized to define types, queries & mutations within the schema file. I will probably write a separate article about Lighthouse & its features, but here is a small part of my schema file:

type User {
    id: ID! @rename(attribute: "uuid")
    name: String!
    email: String!
    role: Role
    created_at: DateTime!
    updated_at: DateTime!
}

input CreateUserInput {
    name: String!,
    email: String!,
    role: UserRole
}

input UpdateUserInput {
    id: ID!
    name: String
    email: String
    role: UserRole
}

input UserRole {
    connect: ID
    create: CreateRoleInput
}

extend type Query {
    users: [User!]! @paginate(defaultCount: 10)
    user(id: ID! @eq(key: "uuid")): User @first
}

extend type Mutation {
    updateUser(input: UpdateUserInput! @spread): User @field(resolver: "User\\UpdateUser")
    createUser(input: CreateUserInput! @spread): User! @field(resolver: "User\\CreateUser")
}

It looks more organized. I don't use a lot of the directives that Lighthouse offers, it may be wrong but to me, it doesn't feel right to have too much business logic be done on the schema. It offers things like @create, @update which can create & update models. It has a lot of other features like handling relationships & even nesting mutations. However, I like to follow the Single Responsibility Principle so I decided to have custom resolvers for each mutation & complex queries. For simple stuff like paginating results or finding model by the id, the @paginate & @eq directives are perfectly fine to use for me.

What's Next?

I've been putting consistently 2-3 hours every day working on the gamification project, yes I did spend time deciding between REST and GraphQL and had to spend more time picking the right library, but this is a learning experience so I don't regret it. I plan on having both GraphQL and REST API endpoints at some point but I'm starting with GraphQL. It's still at the very early stage of the app, I would say just 5-10% overall progress of the project, but I gained a lot of experience and learned a lot the past three weeks. I will be sharing some code soon on how I plan on defining validation rules & re-using the same validations for both GraphQL and REST end-points.

Get notified as soon as new content is published