Skip to content
GraphQL Introduction Explained: Schema, Queries & Resolvers for Beginners

GraphQL Introduction Explained: Schema, Queries & Resolvers for Beginners

DodaTech Updated Jun 6, 2026 7 min read

GraphQL is a query language and runtime for APIs developed by Facebook in 2012 that lets clients request exactly the data they need through a single endpoint.

What You’ll Learn

  • What GraphQL is and the problems it solves
  • Schema Definition Language (SDL) basics
  • How queries, mutations, and subscriptions work
  • Running a GraphQL server with Apollo Server
  • Using GraphiQL to explore and test queries

Why GraphQL Matters

REST APIs have a fundamental mismatch: the server decides what data to return, but the client knows what data it needs. GraphQL flips this — the client describes its data requirements, and the server fulfills them. DodaTech’s Durga Antivirus Pro dashboard has 12+ UI components, each needing different data from the same entities. With GraphQL, the dashboard fetches everything in one request, and each component’s data needs are explicit in the query.

    flowchart LR
    A["REST:\n/GET users\n/GET users/1/posts\n/GET users/1/posts/1/comments"] --> C["3 HTTP Requests\nOver-fetching at each"]
    B["GraphQL:\nquery { user(id:1) {\n  name\n  posts { title\n    comments { body } } } }"] --> D["1 Request\nExact data"]
    style B fill:#dbeafe,stroke:#2563eb
    style A fill:#fef3c7,stroke:#d97706
  
Prerequisites: Basic REST knowledge. JavaScript familiarity for resolver examples.

The Problem GraphQL Solves

Imagine building a mobile dashboard for Durga Antivirus Pro. The dashboard needs to show:

  • User’s name and plan (from GET /users/me)
  • List of devices (from GET /devices)
  • Latest threats (from GET /threats?limit=5)
  • For each device, its last scan time (from GET /devices/{id})

With REST, this requires 4+ HTTP requests and returns more data than needed. With GraphQL:

query DashboardData {
  me { name plan }
  devices { id name os lastScan { completedAt } }
  threats(limit: 5, orderBy: detectedAt_DESC) { id name severity }
}

One request, one response, exactly the fields specified.

Schema Definition Language (SDL)

The schema is the heart of every GraphQL API. It defines what data is available and how to access it.

# Types define the shape of data
type Device {
  id: ID!
  name: String!
  os: String!
  lastScan: DateTime
  threats: [Threat!]!
}

type Threat {
  id: ID!
  name: String!
  severity: ThreatSeverity!
  detectedAt: DateTime!
}

# Enums define a fixed set of values
enum ThreatSeverity {
  LOW
  MEDIUM
  HIGH
  CRITICAL
}

# The Query type defines entry points for reading data
type Query {
  devices: [Device!]!
  device(id: ID!): Device
  threats(severity: ThreatSeverity, limit: Int): [Threat!]!
}

Key symbols:

  • ! means non-nullable — the field will always return a value
  • [Threat!]! means a non-nullable array of non-nullable Threat objects
  • ID is a unique identifier (serialized as a string)
  • DateTime is a custom scalar for date/time values

Writing Your First GraphQL Server

const { ApolloServer, gql } = require('apollo-server');

// 1. Define the schema
const typeDefs = gql`
  type Device {
    id: ID!
    name: String!
    os: String!
  }

  type Query {
    devices: [Device!]!
    device(id: ID!): Device
  }
`;

// 2. Mock data
const devices = [
  { id: '1', name: 'Office-PC', os: 'Windows 11' },
  { id: '2', name: 'Dev-Macbook', os: 'macOS 14' },
];

// 3. Define resolvers
const resolvers = {
  Query: {
    devices: () => devices,
    device: (parent, args) => devices.find(d => d.id === args.id),
  },
};

// 4. Start the server
const server = new ApolloServer({ typeDefs, resolvers });
server.listen(4000).then(() => {
  console.log('GraphQL server at http://localhost:4000');
});

Run this with node server.js and open http://localhost:4000 — you’ll see GraphiQL, an in-browser IDE for testing queries.

Queries with Arguments

# Query with required and optional arguments
query GetDevice {
  device(id: "1") {
    name
    os
  }
}

query GetCriticalThreats {
  threats(severity: CRITICAL, limit: 10) {
    id
    name
    detectedAt
  }
}

Resolver Arguments

Every resolver receives four arguments:

const resolvers = {
  Query: {
    threats: (parent, args, context, info) => {
      // parent: result of the parent resolver (unused for top-level queries)
      // args: { severity: 'CRITICAL', limit: 10 }
      // context: shared context (auth user, database connection)
      // info: query execution details (field names, selections)
      
      let results = threats;
      if (args.severity) {
        results = results.filter(t => t.severity === args.severity);
      }
      return args.limit ? results.slice(0, args.limit) : results;
    },
  },
};

Common Mistakes

1. Not Using a Schema-First Approach

Writing resolvers before defining types leads to inconsistent APIs. Always define your schema first — it’s the contract between client and server.

2. Ignoring the N+1 Problem

Nested resolvers (devices → threats) without DataLoader make N+1 database queries. Always batch child queries.

3. Returning Entire Database Objects

Resolvers should return API types, not database rows. Map database columns to GraphQL fields explicitly.

4. Not Handling Errors Properly

GraphQL returns errors alongside data. Always handle partial success — some resolvers may fail while others succeed.

Practice Questions

  1. What does the ! symbol mean in GraphQL schema?
  2. What are the four arguments a resolver receives?
  3. Why does GraphQL use a single endpoint instead of multiple like REST?
  4. What is the N+1 problem and how do you solve it?
  5. How does GraphQL handle partial errors?

Answers:

  1. Non-nullable — the field will always return a value and can’t be null.
  2. parent (parent resolver result), args (query arguments), context (shared app state), info (execution metadata).
  3. A single endpoint lets the client describe exactly what data it needs. The server provides one URL; the query determines the response shape.
  4. With nested resolvers, fetching N parent items triggers N additional queries for children. Solved with DataLoader to batch child queries.
  5. GraphQL responses include both data (partial results) and errors (failed resolvers). Clients should check for both.

Challenge: Write a GraphQL schema and resolvers for a simple Durga Antivirus Pro API with User, Device, and Scan types. The User type should have a devices field that returns all devices owned by that user. Write a query that fetches a user with their devices and latest scan for each device.

FAQ

Is GraphQL a database query language like SQL?
: No — GraphQL is an API query language. It doesn’t interact with databases directly. Resolvers implement the data fetching logic, which can call databases, REST APIs, or other services.
Do I need to use Apollo to use GraphQL?
: No — Apollo is the most popular GraphQL server implementation, but there are alternatives: GraphQL Yoga, express-graphql, Hasura (auto-generates from database), and Relay for clients.
Can I use GraphQL with TypeScript?
: Yes — GraphQL and TypeScript work well together. Tools like GraphQL Code Generator can auto-generate TypeScript types from your GraphQL schema, ensuring type safety across the stack.
How does authentication work in GraphQL?
: Authentication is handled in the context — verify the JWT token in the context function and attach the user to context.auth. Resolvers check context.auth for authorization.

Try It Yourself

# Create a GraphQL server in 5 lines
mkdir graphql-demo && cd graphql-demo
npm init -y
npm install apollo-server graphql

cat > server.js << 'EOF'
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`type Query { hello: String }`;
const resolvers = { Query: { hello: () => 'Hello GraphQL!' } };
new ApolloServer({ typeDefs, resolvers }).listen(4000)
  .then(() => console.log('Server running at http://localhost:4000'));
EOF

node server.js

Visit http://localhost:4000 and run { hello } in GraphiQL.

What’s Next

TopicDescription
Types & Schema DesignObjects, scalars, enums, and relationships
Queries & Resolvers Deep DiveArguments, context, and data batching
Mutations & Input TypesCreating and modifying data
RESTful APIsCompare GraphQL with REST for your use case

What’s Next

Congratulations on completing this Graphql Introduction tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro