DEV Community

Cover image for The Complete Guide to Becoming a Web Developer: Part 5
Ahmed Radwan
Ahmed Radwan

Posted on • Originally published at nerdleveltech.com

The Complete Guide to Becoming a Web Developer: Part 5

Welcome back to the series "Becoming a Web Developer" part 5, and continuing with the APIs technologies and what's out there to include in your toolbox and skillset. If you are new here, you can start with this list [ part 1part 2part 3, part 4].

Welcome to your comprehensive guide on GraphQL! This article takes you on a journey from the foundational understanding of GraphQL, its history, and key features, to a deep dive into its mechanics and tooling. We will explore the reasons behind its rising popularity among developers and provide practical examples of queries, mutations, schemas, and more.

Introduction

Hello there! If you're stepping into the fantastic world of APIs, you've probably heard the buzz about GraphQL. This powerful query language is shaking up the way we think about data retrieval, making it a hot topic for developers across the globe. But what exactly is GraphQL, and how did it come about? Grab a cup of coffee and get comfy - we're about to dive into the exciting history of this game-changing technology.

Origins and Development

Believe it or not, GraphQL was born in the hustle and bustle of Facebook's bustling corridors. Back in 2012, Facebook's engineering team faced a huge challenge: the company's mobile applications were lagging behind the fast-evolving user experience of its website. The mobile apps were slow, data-heavy, and a far cry from the speedy, slick service Facebook wanted to deliver.

Lee Byron, Nick Schrock, and Dan Schafer - three Facebook engineers tasked with overhauling the company's mobile tech stack. They realized the core of the problem lay in the way data was fetched from the server. Traditional RESTful APIs were designed for websites where servers dictated what data was sent in response to each request. However, mobile apps needed a more flexible approach, where the client could specify exactly what data it needed.

The solution? A new query language that allowed the client to dictate its data requirements. The team named it GraphQL, a nod to its ability to query data in a graph-like, non-linear manner.

Open Source Release and GraphQL Foundation

After three years of rigorous in-house use and development, Facebook open-sourced GraphQL in 2015. The tech world was excited to see a new player on the field, one that promised to revolutionize data querying. The response was overwhelmingly positive, with companies like Pinterest, Coursera, and Shopify hopping aboard the GraphQL train.

In 2018, Facebook made a significant move by shifting GraphQL to the newly established GraphQL Foundation, hosted by the non-profit Linux Foundation. This change marked GraphQL's transformation from a Facebook-centric technology to a community-driven project. The move to the foundation ensured the future direction of GraphQL would be decided by a broad coalition of companies and individual contributors, further democratizing its development.

And there you have it - a whistle-stop tour of GraphQL's history.

Understanding GraphQL

GraphQL is a powerful open-source data query and manipulation language that provides an efficient, strong-typed, and predictive approach to building APIs. Born from the minds at Facebook in 2012 and open-sourced in 2015, GraphQL is built to streamline the way data is requested and delivered between client and server, enhancing both the developer experience and the performance of web applications

So, what's the magic behind GraphQL, you ask? Well, let's dive into its key features:

  1. Declarative Data Fetching: GraphQL allows the client to specify exactly what data it needs from an API. Instead of multiple endpoints that return separate data, a GraphQL server exposes a single endpoint and responds with precisely the data a client asked for. This is like going to a restaurant and ordering only the food you want, instead of getting a predetermined meal with things you might not eat.
  2. Efficient Data Aggregation: With a REST API, you might need to make several network requests to different endpoints to fetch related data. But with GraphQL, you can get all the related data in a single request. This not only makes data fetching faster but also reduces the load on the network and the server.
  3. Strong Typing: GraphQL APIs are strongly typed. This means every piece of data is associated with a specific type, and all types are defined in the GraphQL schema. This ensures data consistency and makes it easier to catch errors during development.
  4. Real-time Updates: GraphQL supports subscriptions, which allow the client to receive real-time updates from the server. This is particularly useful in applications that need real-time functionality, such as chats or live feeds.
  5. Introspection: GraphQL comes with built-in support for introspection, which means the GraphQL API can query itself for the types it supports. This feature enables powerful tooling and auto-completion during development, making developers' lives easier.

To illustrate GraphQL in action, let's look at a simple example. Imagine you have a webpage that displays a list of pets available for adoption at local animal shelters. Using a REST API, you might need to make one request to get a list of shelters and then a separate request for each shelter to get the pets available there. With GraphQL, you can get all this data in one go:

query GetPetsByShelter {
  shelters {
    name
    pets {
      name
      photoURL
    }
  }
}

The above GraphQL query fetches the name of all shelters and the name and photo URL of all pets in each shelter, all in one request. This is a significant improvement in data fetching efficiency compared to REST APIs.

A Deep Look at GraphQL

Let's consider a simple example. Suppose you're building a blog application. In a traditional RESTful API, you might have separate endpoints for fetching user details, posts, and comments. To display a single blog post with author details and comments, your client would need to make several separate requests, like so:

  1. GET /users/{userId} to fetch the author's details.
  2. GET /posts/{postId} to fetch the post details.
  3. GET /posts/{postId}/comments to fetch the post's comments.

But with GraphQL, you can fetch all these details in a single request! You just need to send a query that describes the exact data you want, like so:

query {
  post(id: "123") {
    title
    content
    author {
      name
      bio
    }
    comments {
      content
      author {
        name
      }
    }
  }
}

As you can see, GraphQL queries are incredibly flexible and precise, allowing you to cut down on unnecessary data transfers and streamline your application's performance. Isn't that neat?

Apollo GraphQL client Example

In a JavaScript application, you can use a GraphQL client library like Apollo to execute this query:

// Define the query
const GET_PETS_BY_SHELTER = gql`
  query GetPetsByShelter {
    shelters {
      name
      pets {
        name
        photoURL
      }
    }
  }
`;

function MainPage() {
  // Execute the query within the component that uses its result
  const { loading, error, data } = useQuery(GET_PETS_BY_SHELTER);

  if (error) return <Error />;
  if (loading || !data) return <Fetching />;

  // Populate the component using the query's result
  return <PetList shelters={data.shelters} />;
}

In this code, the useQuery function from the Apollo Client is used to fetch the data. Once the data is loaded, it is passed to the PetList component to be displayed.

When to use/not use GraphQL?

The decision to use GraphQL should be driven by the specific needs of your application or project. Here are some reasons when GraphQL could be a good fit:

  1. When you need to fetch complex, interrelated data: If your application deals with complex data structures that are interconnected and requires multiple round trips to a REST API to retrieve, GraphQL's ability to fetch related data in one request can be a game-changer.
  2. When different clients have different data needs: If you're building a service that needs to support various front-end clients (web, mobile, IoT, etc.), each with different data requirements, GraphQL's client-specified queries can prevent over-fetching or under-fetching of data.
  3. When you need real-time data: If your application requires real-time updates, the subscription feature in GraphQL can be very useful.
  4. When you want to improve developer experience: The strong type system, introspection capabilities, and developer tooling around GraphQL can significantly improve the developer experience, leading to increased productivity and fewer bugs.

However, GraphQL may not be the best choice for every situation. Here are a few cases where it might not be the best fit:

  1. Simple APIs: If your API is simple, with few entities and relationships, a REST API might be simpler and faster to set up.
  2. Public APIs: If you're building a public API that you want others to use, REST is currently more widely adopted and understood by most developers.
  3. Limited resources: GraphQL can be more resource-intensive on the server than REST, due to its need to process complex queries and aggregate data from various sources. If server resources are a concern, this could be a deciding factor.
  4. Full graph querying needs: GraphQL does not provide a full-fledged graph query language like SPARQL or even dialects of SQL that support transitive closure. For example, a GraphQL interface that reports the parents of an individual cannot return, in a single query, the set of all their ancestors.

Why Developers are Adopting GraphQL

There's an undeniable buzz in the developer community around GraphQL. This powerful query language is making waves and winning hearts, and it's not hard to see why. Let's break it down and see what's got everyone so excited.

Consistency and Predictability of APIs

Imagine you're working on a project that requires fetching data from multiple endpoints. With a traditional RESTful setup, you'd typically have to make multiple requests, each returning a fixed structure of data. This can often lead to either over-fetching (getting more data than you need) or under-fetching (not getting enough data), both of which are far from ideal.

Enter GraphQL, a knight in shining armor. With GraphQL, you can ask for exactly what you need and nothing more. You send a query to a single endpoint detailing the specific data you're after, and the server responds with a JSON object that mirrors your request. You get predictable results and a consistent API to use across all of your clients. It's like ordering à la carte in a restaurant - you get exactly what you order, no more, no less.

Enhanced Developer Experience

GraphQL isn't just practical; it's also a joy to work with. The strong typing, introspection capabilities, and excellent developer tooling around GraphQL significantly improve the developer experience, making it easier to design, develop, and deploy features quickly.

Tools like GraphiQL and Apollo Studio provide a powerful interface for testing your queries, exploring your schema, and understanding your data. And because GraphQL schemas are strongly typed, you can catch potential errors early in the development process, leading to fewer bugs and a smoother development experience.

Managing Data in Modern Applications

In today's digital world, applications are expected to provide real-time updates, work across multiple platforms, and handle complex data. Traditional REST APIs can struggle to meet these demands, but GraphQL shines bright.

GraphQL's subscription feature enables real-time updates right out of the box. When a mutation (an operation to create, update, or delete data) occurs, the server sends an update to all subscribed clients. This feature is incredibly useful for features like live chat, real-time notifications, and any situation where you need to keep the user interface in sync with the server state.

Additionally, GraphQL is a great choice for modern applications that require managing data across multiple platforms. Whether you're building for the web, mobile, IoT, or any other platform, GraphQL's client-specified queries can efficiently serve varied data requirements.

Behind GraphQL

GraphQL is like a well-oiled machine, where each part plays a vital role in achieving the whole. The magic of GraphQL lies in its mechanics - the under-the-hood operations that bring the language to life. Let's dive into the gears and levers of this fascinating language.

Reading, Writing, and Subscriptions

At its core, GraphQL is a query language, that allows clients to read, write, and subscribe to data. Reading data in GraphQL is done via a 'query'. Writing data, whether that's creating, updating, or deleting, is done using a 'mutation'. For real-time updates, GraphQL uses a feature called 'subscriptions'. It's a simple yet powerful trifecta.

Here's a quick example. Let's say you're building a blog. Your GraphQL schema might include queries to fetch posts, mutations to add or edit posts, and subscriptions to get live updates when a new post is published.

type Query {
  posts: [Post]
}

type Mutation {
  addPost(title: String, content: String): Post
}

type Subscription {
  postAdded: Post
}

type Post {
  id: ID
  title: String
  content: String
}

Defining Types and Fields

In the world of GraphQL, everything revolves around the schema. The schema is where you define types and their fields, establishing the shape of the responses that your API can return.

Types can represent objects, scalars (like strings, numbers, and booleans), enums, and more. Each type can have multiple fields, and each field has a specific type. Fields can also be defined as lists (e.g., [Post] for a list of posts) or as non-nullable (e.g., String! for a required string field).

The root type of a GraphQL schema is called Query by default, and it contains all of the fields that can be queried. Here's an example:

type Query {
  post(id: ID!): Post
  posts: [Post]
}

type Post {
  id: ID!
  title: String!
  content: String
}

Role of Resolvers

Resolvers are the heart of a GraphQL server. They are functions that retrieve and return the data for each field in a query. When a client sends a query to the server, the server invokes the corresponding resolver for each field.

Resolvers can fetch data from anywhere - a database, another API, a file on disk - you name it. They provide the flexibility to structure your data sources in a way that makes sense for your application.

Here's an example of what resolvers might look like for our blog schema:

const resolvers = {
  Query: {
    post: (parent, args, context, info) => {
      // Fetch a single post by ID from your data source
    },
    posts: (parent, args, context, info) => {
      // Fetch all posts from your data source
    },
  },
};

Execution of GraphQL Queries

Once a GraphQL query is validated against the schema, it's executed by the server. The server then returns a result that mirrors the shape of the original query, typically as a JSON object. This is one of the unique aspects of GraphQL - the client has control over the shape of the response, making data fetching more efficient.

Here's a simple example. If a client sends the following query:

query {
  posts {
    title
    content
  }
}

The server would respond with a JSON object that mirrors the shape of the query:

{
  "data": {
    "posts": [
      {
        "title": "First Post",
        "content": "This is the content of the first post."
      },
      {
        "title": "Second Post",
        "content": "Here's some content for the second post."
      }
      // More posts...
    ]
  }
}

Writing a GraphQL Schema

Ahh, the GraphQL schema - the beating heart of any GraphQL API. This is where all the magic begins. You see, the schema is the roadmap that describes all the data types and the ways they link up. It's your treasure map, guiding you to the data gems you're seeking. So, let's jump in and learn how to write one!

Understanding the GraphQL Schema

First things first, you need to understand what a GraphQL schema is. Picture a big blueprint of all the data your app has to offer. It's a map showing what's available, how it's structured, and how you can access it. It's also like a contract between the client and the server, ensuring they speak the same language.

In technical terms, a GraphQL schema is a special kind of graph that describes how data is organized and how clients can request that data. It's written in the GraphQL Schema Definition Language (SDL), which might sound intimidating, but don't worry - we'll get to that.

Defining Fields and Types

Alright, time to roll up our sleeves and get to work. A GraphQL schema is made up of types, and each type has fields. Fields are like the properties of the type.

There are several base types, called scalars, to represent things like strings, numbers, and IDs. You can also define custom types. Let's look at an example:

type Author {
  id: ID!
  name: String!
  posts: [Post]
}

type Post {
  id: ID!
  title: String!
  content: String!
  author: Author!
}

In this example, Author and Post are types. Author has fields id, name, and posts. Post has id, title, content, and author. The ID and String are scalar types, and [Post] and Author are custom types that we've defined. The array syntax ([Post]) means that posts is a list of Post objects.

Non-Nullable Fields

You might be wondering what that exclamation mark (!) is all about. That's GraphQL's way of marking a field as non-nullable. In other words, whenever an Author or Post is queried, it must always return a value for id, name, title, content, and author. If, for some reason, it can't return a value, GraphQL will return an error instead of a null value.

Here's an example of a query:

query {
  author(id: 1) {
    name
    posts {
      title
      content
    }
  }
}

This query is asking for the name of the Author with id 1, and the title and content of all of their posts. The server will return a result that matches the structure of the query.

Understanding GraphQL Mutation

Think of a mutation as an action or command. You're telling the server to do something: 'Create a new author', 'Update this post', 'Delete that comment'. And, just like a query, a mutation is a string that the client sends to the server.

But, unlike queries, mutations can change the data on the server. This is why they're called 'mutations' - they mutate (or change) data. Let's look at an example of a mutation to create a new Author:

mutation {
  createAuthor(name: "J.K. Rowling") {
    id
    name
  }
}

In this mutation, we're calling the createAuthor mutation with the name parameter set to "J.K. Rowling". The server will create a new author with that name, and then it will return the id and name of the new author.

Here's another example. This time, we're updating a Post:

mutation {
  updatePost(id: 1, title: "New Title", content: "New Content") {
    id
    title
    content
  }
}

In this mutation, we're calling the updatePost mutation with id, title, and content parameters. The server will find the post with id 1 and update its title and content with the new values. Then, it will return the id, title, and content of the updated post.

But what happens if we try to create a new Author without providing a name, or try to update a Post without providing a title or content, and those fields are marked as non-nullable in the schema? Remember those exclamation marks (!) from the schema? Well, here's where they come into play.

If a field is marked as non-nullable, it means it must always have a value. If you try to create or update data without providing a value for a non-nullable field, GraphQL will return an error. This is a great way to ensure data integrity and consistency in your application.

Tools for Working with GraphQL

Whoo! We've learned about how to define a GraphQL schema, how to query data, and how to mutate data. Now, let's move on to some tools that will make your life working with GraphQL so much easier. Think of these tools as the cherry on top of the delicious GraphQL sundae you've just built.

Testing Tools

First off, let's talk about testing. Testing is key to ensure your GraphQL API behaves as expected, and there are a host of tools to help you do just that. Remember, we're not just testing the server's behavior, but also the shape and contents of the responses. Here are a few of my favorites:

  • Postman: Not just for REST APIs anymore! Postman now supports GraphQL requests and even schema validation. It's like a Swiss Army knife for API testing.
  • GraphiQL: This is an in-browser tool for testing your GraphQL server. It's like a playground where you can write queries, view the schema, and see the results. It even has autocomplete features. So fancy!
  • Apollo Studio: This is a more advanced tool that provides not just testing capabilities, but also things like performance tracing and schema management.

Apollo GraphOS

Speaking of Apollo, let's dive into one of their coolest offerings: Apollo GraphOS. This is a collection of cloud-hosted tools that help you build, measure, and grow your GraphQL implementation. Think of it as mission control for your GraphQL API.

Apollo GraphOS lets you register your schema and inspect all of its types and fields. You can build and run queries against your server, track performance, and even check schema changes. It's a fantastic tool for both development and production environments.

But the coolest thing about Apollo GraphOS is the Apollo Studio Explorer. This powerful tool lets you explore your schema, compose operations with live validation and autocomplete, and even inspect the results of your queries. It's like having a personal tour guide for your GraphQL API.

Conclusion and Resources

After exploring the world of GraphQL, it's clear that it brings significant enhancements to the development process, offering powerful and efficient means of working with data. GraphQL allows for a more declarative and efficient way of fetching data, enabling a consistent, predictable API that can be used across all clients. It is not tied to any specific database or storage engine, and it supports reading, writing (mutating), and subscribing to changes to data (real-time updates)​​.

The GraphQL ecosystem is rich with tools and libraries to make working with it a breeze. For instance, Apollo Client simplifies executing queries and managing the request lifecycle, all while enabling powerful features such as caching, data normalization, and optimistic UI rendering​​.

Now, if you're eager to dive deeper into GraphQL, here are some excellent resources for learning and expanding your knowledge:

  1. Official GraphQL Documentation: A great starting point, this comprehensive guide covers everything from the basics to advanced topics.
  2. Apollo GraphQL Docs: This resource provides detailed information about using Apollo, a popular GraphQL implementation.
  3. GraphQL Foundation: This is the official organization overseeing GraphQL. It provides updates on GraphQL and its associated projects.
  4. GraphQL Tools on GitHub: This repository is a comprehensive set of tools for building, testing, and deploying GraphQL servers and clients.
  5. How to GraphQL: An excellent tutorial-based resource that covers a range of GraphQL topics.
  6. GraphQL Lessons on Egghead.io: Video lessons on GraphQL ranging from beginner to advanced topics.

In conclusion, GraphQL is a powerful tool for modern web development, and the wealth of resources available makes it accessible to developers of all skill levels. Its strengths in data fetching, and the array of powerful tools that come with it, present compelling reasons to adopt GraphQL for your next project. Happy learning!

Top comments (0)