Skip to content
Introduction to APIs with GraphQL
5 min read

Introduction to APIs with GraphQL

I’ll be honest: the first time I used GraphQL, I thought it was over-engineered. “Why do I need a whole query language when REST works fine?” Then I built a mobile app that made 12 different API calls just to render one screen. That’s when GraphQL clicked.

GraphQL is a query language designed for communication between clients and servers. Facebook created it in 2012 to solve a very real problem: their mobile apps were slow, bloated, and making way too many network requests. They needed a better way.

What I love most about GraphQL: the client defines what it receives. No more over-fetching. No more under-fetching. No more chaining requests. Just ask for exactly what you need, and that’s what you get.

And no, GraphQL is nothing like SQL — the name is misleading. It’s a query language for APIs, not databases.


REST vs GraphQL: Why I Switched

Let me walk you through the practical differences that convinced me:

RESTGraphQL
It’s a convention (not a spec)It’s a typed language with a spec
Server decides what data to sendClient defines exactly what it receives
Often sends more data than neededOnly requested fields are sent
Multiple requests per viewOne request per view
Documentation is manual and often outdatedSelf-documenting by definition
Multiple endpoints (/users, /users/:id, /posts, etc.)Single endpoint: /graphql
Versioning required for breaking changesSchema evolution without versions

Here’s a real-world example. Say you’re building a blog and need to show a user’s profile with their latest posts.

With REST:

// Request 1: Get user
GET /api/users/123
// Returns: { id, name, email, bio, avatar, createdAt, updatedAt, ... }

// Request 2: Get user's posts
GET /api/users/123/posts
// Returns: [{ id, title, content, createdAt, ... }, ...]

You made two requests. The first one sent you fields you don’t need (createdAt, updatedAt). The second one might have sent full post content when you only needed titles and dates.

With GraphQL:

query {
  user(id: "123") {
    name
    avatar
    posts(limit: 5) {
      title
      publishedAt
    }
  }
}

One request. Only the fields you need. No over-fetching. No under-fetching. That’s the power.


Core Concepts That Matter

Schema: The Contract

The schema defines your API’s structure. It’s the contract between client and server — written in GraphQL’s type system.

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

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

The ! means the field is non-nullable. [Post!]! means “an array of Post objects, and both the array and its items are non-nullable.” The type system catches errors at query time, not runtime.

Types: Strong Typing Everywhere

GraphQL has built-in scalar types:

  • Int — 32-bit integer
  • Float — Floating-point number
  • String — UTF-8 text
  • Boolean — true/false
  • ID — Unique identifier (serialized as string)

You can also define custom types, enums, and interfaces. The type system makes your API self-validating.

Queries: Reading Data

Queries are how you read data. They look like JSON, but they’re not — they’re GraphQL syntax.

query GetUserProfile {
  user(id: "123") {
    name
    avatar
    posts(limit: 3, orderBy: PUBLISHED_DESC) {
      title
      publishedAt
      comments {
        count
      }
    }
  }
}

The response matches the query structure exactly:

{
  "data": {
    "user": {
      "name": "Sergio Alexander",
      "avatar": "/images/profile.jpg",
      "posts": [
        {
          "title": "Introduction to APIs with GraphQL",
          "publishedAt": "2018-10-20",
          "comments": { "count": 12 }
        }
      ]
    }
  }
}

Mutations: Writing Data

Mutations change data. They’re like POST/PUT/DELETE in REST, but with the same predictable structure as queries.

mutation CreatePost {
  createPost(input: {
    title: "My New Post"
    content: "GraphQL is amazing."
    tags: ["tech", "graphql"]
  }) {
    id
    title
    publishedAt
  }
}

Notice you can request specific fields back after the mutation. Want to know the newly created post’s ID? Just ask for it.

Resolvers: The Magic Behind the Scenes

Resolvers are functions that return data for each field in your schema. This is where your business logic lives.

const resolvers = {
  Query: {
    user: (parent, { id }, context) => {
      return context.db.getUserById(id);
    },
  },
  User: {
    posts: (user, { limit }, context) => {
      return context.db.getPostsByAuthor(user.id, limit);
    },
  },
  Mutation: {
    createPost: (parent, { input }, context) => {
      return context.db.createPost(input);
    },
  },
};

Each resolver gets:

  • parent — The result from the parent field
  • args — The arguments passed to the field
  • context — Shared data (like database connections, auth info)

GraphQL’s execution engine calls these resolvers in the right order, builds the response tree, and returns exactly what was requested.


Why GraphQL Matters to Me

After building APIs with both REST and GraphQL, here’s what changed for me:

1. Developer Experience

The introspection and tooling are incredible. Tools like GraphiQL and Apollo Studio give you autocomplete, inline docs, and query validation as you type. You don’t need Postman or separate documentation — the API documents itself.

2. Frontend Speed

Reducing network requests means faster apps. Mobile users on slow connections notice the difference immediately. One GraphQL request replaces 5-10 REST calls.

3. Backend Flexibility

I can add fields to the schema without breaking existing queries. Clients only request what they need, so adding new data doesn’t affect them. No versioning headaches.

4. Type Safety

The type system catches errors early. Invalid queries fail before they hit the server. TypeScript codegen creates type-safe clients automatically from your schema.

Platform Agnostic

GraphQL has implementations in over 20 languages. I’ve used it with Node.js, Python, Go, and Rust. The concepts stay the same.


Real Example: Star Wars API

If you want to play with GraphQL, try the Star Wars API (SWAPI). It’s a public GraphQL endpoint with data about films, characters, planets, and starships.

Try this query:

query {
  allFilms {
    films {
      title
      director
      releaseDate
      characterConnection {
        characters {
          name
          homeworld {
            name
          }
        }
      }
    }
  }
}

Notice how you traverse relationships (films -> characters -> homeworld) in one query. With REST, that would be multiple requests with complex joins.


Resources I Shared

GraphQL


View slides

Let’s keep building.