GraphQL Getting Started Guide: What It Is, How It Works, and How to Create Modern APIs

  



GraphQL is a query language for APIs and a runtime for running those queries against your data. Created by Facebook in 2012 and open sourced in 2015, GraphQL is designed to give clients exactly the data they need, nothing more, nothing less.

Unlike traditional REST APIs, which expose multiple endpoints for different resources, GraphQL exposes a single endpoint and allows the client to define exactly the form of the desired response.

๐Ÿ”— Do you like Techelopment? Check out the site for all the details!


๐Ÿš€ What is GraphQL?

GraphQL is a query language for APIs that allows clients to specify exactly what data they want to receive. It was developed by Facebook to overcome the limitations of traditional REST APIs.

  • Over-fetching: getting more data than you need.
  • Under-fetching: having to make multiple calls to get the complete data.

With GraphQL, you send a query to a single endpoint and get back only the data you requested.


๐Ÿ“ The Fundamentals of a GraphQL API (with examples)

1. Single Endpoint

All operations pass through a single endpoint, for example /graphql.

In REST:

  • /api/users, /api/products, etc. → many endpoints.

In GraphQL:

  • Only one: for example /graphql.

๐Ÿ’ก Example (POST to /graphql):

POST /graphql
Content-Type: application/json

{
    "query": "{ listUsers { name age } }"
}

2. Typed Schema

Each API has a typed schema that defines the available data and the allowed operations. The schema defines the types, queries (available data), and mutations available (allowed operations):

type User {
    id: Int
    name: String
    age: Int
}

3. Precise Query

The client decides which fields it wants to receive:

{
    listUsers {
        name
    }
}

Response:

{
    "data": {
    "listUsers": [
            { "name": "Alice" },
            { "name": "Bob" }
        ]
    }
}

4. Introspection

The schema is self-describing. You can ask for it with a special query:

{
    __schema {
        types {
            name
        }
    }
}

5. Strong Typing

Each field and argument has a specific type. Errors like this are blocked:

{
    getUser(id: "not-a-number") {
        name
    }
}

๐Ÿšซ Error: id must be an integer.


๐Ÿ” What are Queries in GraphQL?

In GraphQL, Queries are the equivalent of GET requests in REST APIs. They are used to read data from the server without modifying it.

✨ Query Characteristics:

  • They do not cause side effects (they are "safe").
  • The client specifies exactly the fields it wants.
  • They are the starting point for reading complex relationships between entities.

๐Ÿงช Query Example

{
    listUsers {
        name
        age
    }
}

Call in Postman:

{ 
    "query": "{ listUsers { name age } }"
}

Answer:

{ 
    "date": { 
        "listUsers": [ 
            { "name": "Alice", "age": 30 }, 
            { "name": "Bob", "age": 25 } 
        ] 
    }
}

๐ŸŽฏ Query with Arguments

{ 
    getUser(id: 2) { 
        name 
        age 
    }
}

Postman:

{ 
    "query": "{ getUser(id: 2) { name age } }"
}

Answer:

{ 
    "date": { 
        "getUser": { 
            "name": "Bob", 
            "age": 25 
        } 
    }
}


✏️ What is a Mutation and When Is It Used?

In GraphQL, Mutation is used for edit data: create, update or delete. It is the equivalent of POST, PUT or DELETE in REST APIs.

๐Ÿ“ฆ When is it needed?

Anytime you want to write or modify something on the server.

๐Ÿ”จ Full Example: Mutation

1. Definition in the schema

type Mutation { 
    createUser(name: String!, age: Int!): User
}

2. Client Call Example

mutation { 
    createUser(name: "Charlie", age: 40) { 
        id 
        name 
    }
}

๐Ÿ“ฆ Response:

{ 
    "date": { 
        "createUser": { 
            "id": 3, 
            "name": "Charlie" 
        } 
    }
}

๐Ÿ”„ Difference between Query and Mutation

TypePurposeSide effects?Example
QueryRead data❌ NogetUser, listUsers
MutationModify data✅ YescreateUser, deleteUser


๐Ÿงช How to Call a GraphQL API with Postman

๐Ÿ“– Query Call

  • Method: POST
  • URL: http://localhost:4000/graphql

Headers:

Content-Type:application/json

Body:

{ 
    "query": "{ listUsers { id name age } }"
}

Answer:

{ 
    "date": { 
        "listUsers": [ 
            { "id": 1, "name": "Alice", "age": 30 }, 
            { "id": 2, "name": "Bob", "age": 25 } 
        ] 
    }
}

✏️Call by Mutation

  • Method: POST
  • URL: http://localhost:4000/graphql

Headers:

Content-Type:application/json

Body:

{ 
    "query": "mutation { createUser(name: \"Charlie\", age: 40) { id name age } }"
}

Answer:

{ 
    "date": {
        "createUser": {
            "id": 3,
            "name": "Charlie",
            "age": 40
        }
    }
}

Using Postman allows you to explore GraphQL APIs in a clean and visual way, even if you are used to the REST paradigm. The important thing to remember is that:

  • Everything happens on a single endpoint

  • Query to read, Mutation to write

  • The client decides what to receive: the server responds only with the requested data

For more information on using Postman with GraphQL you can take a look at https://blog.postman.com/how-to-implement-a-graphql-mutation/.

๐Ÿ› ️ Complete Code of a GraphQL Server

Seenow how to expose a GraphQL API on a local server.

Install dependencies:

npm install express express-graphql graphql

Complete code (server.js):

const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');

// Define GraphQL schema
const schema = buildSchema(` 
    type User { 
        id: Int 
        name: String 
        age: Int 
    } 

    type Query { 
        listUsers: [User] 
        getUser(id: Int!): User 
    } 

    type Mutation { 
        createUser(name: String!, age: Int!): User 
    }
`);


// Sample in-memory data
let users = [ 
    { id: 1, name: 'Alice', age: 30 }, 
    { id: 2, name: 'Bob', age: 25 }
];

// Root resolver
const root = { 
    listUsers: () => users, 
    getUser: ({ id }) => users.find(u => u.id === id), 
    createUser: ({ name, age }) => { 
        const newUser = { id: users.length + 1, name, age }; 
        users.push(newUser); 
        return newUser; 
    }
};

const app = express();
app.use('/graphql', graphqlHTTP({ 
    scheme, 
    rootValue: root, 
    graphiql: true // Enables GraphiQL UI
}));

app.listen(4000, () => console.log('GraphQL API running at http://localhost:4000/graphql'));

Here is the server code with explanation point by point:

const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');

๐Ÿ”น We import the necessary libraries: Express for the HTTP server, GraphQL and the express-graphql middleware.


// Define GraphQL schema
const schema = buildSchema(` 
    type User { 
        id: Int 
        name: String 
        age: Int 
    } 

    type Query { 
        listUsers: [User] 
        getUser(id: Int!): User 
    } 

    type Mutation { 
        createUser(name: String!, age: Int!): User
    }
`);

๐Ÿ”น Here we define the GraphQL schema, which is the contract that describes:

  • the types (User)

  • the available queries (listUsers, getUser)

  • the available mutations (createUser)


// Sample in-memory data
let users = [
    { id: 1, name: 'Alice', age: 30 },
    { id: 2, name: 'Bob', age: 25 }
];

๐Ÿ”น A list of users in memory (no database yet). We use this array to simulate real data.


// Root resolver
const root = {
    listUsers: () => users,
    getUser: ({ id }) => users.find(u => u.id === id), 
    createUser: ({ name, age }) => { 
        const newUser = { id: users.length + 1, name, age }; 
        users.push(newUser); 
        return newUser; 
    }
};

๐Ÿ”น The resolver is the object that implements the logic for each schema operation:

  • listUsers: Returns all users.

  • getUser: Search for a user by ID.

  • createUser: Create a new user with incremental ID and add it to the list.


const app = express();
app.use('/graphql', graphqlHTTP({ 
    scheme, 
    rootValue: root, 
    graphiql: true // Enables GraphiQL UI
}));

๐Ÿ”น Let's create the Express app and define a single endpoint /graphql where we handle all requests using the graphqlHTTP middleware.
The graphiql: true option activates the integrated graphical interface to test queries from a browser.


app.listen(4000, () => console.log('GraphQL API running at http://localhost:4000/graphql'));

๐Ÿ”น The server starts on port 4000. Opening http://localhost:4000/graphql you access GraphiQL, a useful UI for testing queries and mutations.


๐Ÿ”น To launch server.js run the command:

node server.js 

✅ Best Practices in API Design GraphQL

  1. Clearly define the schema: it is the contract between client and server.

  2. Avoid over-fetching and under-fetching: it is one of the major advantages of GraphQL.

  3. Authorization and Authentication: Implement middleware to protect sensitive data.

  4. Rate Limiting: Useful to avoid expensive queries.

  5. Versioning: GraphQL has no API versions. Use field deprecation when needed.


๐Ÿงช Useful Tools

  • GraphiQL / Apollo Studio: IDE for exploring APIs.

  • Apollo Server: alternative to express-graphql, more complete.

  • GraphQL Code Generator: to generate types and queries starting from the schema.


✅ Conclusion

GraphQL offers a modern, flexible and powerful way to build APIs. Its main advantages are:

  • ๐Ÿ›‚ Greater client-side control
  • ๐Ÿ” Avoid over-fetching and under-fetching
  • ๐Ÿ’ช Strongly typed schema
  • ๐Ÿฅ‡ One endpoint for everything

You can easily test your API with Postman or GraphiQL and quickly develop interactive and performant interfaces.




Follow me #techelopment

Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment