Getting Started with GraphQL & Type-GraphQL: A Modern TypeScript API Guide

TheGeekPlanetsTheGeekPlanets
5 min read

Are you a JavaScript or TypeScript developer looking to dive into the world of GraphQL with clear, practical steps? This tutorial will walk you through building a type-safe GraphQL API from scratch using Type-GraphQL and Apollo Server without using a database. so you can focus on mastering the fundamentals with engaging, hands-on code.

Traditional REST APIs have long served as the backbone of web and mobile applications, but they often fall short when dealing with complex queries, over-fetching, or under-fetching of data.

GraphQL is an open-source query language for APIs and a runtime for executing those queries. Developed by Facebook in 2012 and open-sourced in 2015, GraphQL has become a game-changer for developers who want precise control over the data their applications consume.

Why GraphQL and Type-GraphQL?

Before jumping into the nitty-gritty, let’s answer the “why”:

  • GraphQL allows you to request only the data you need, making APIs more efficient and flexible than traditional REST.

  • Type-GraphQL brings the power of TypeScript decorators and classes to schema design, allowing you to build your GraphQL API with full type safety and much less boilerplate.

  • Pairing Apollo Server with Type-GraphQL creates a fast, modern developer experience.

How GraphQL Differs from REST APIs

While both REST and GraphQL serve the same purpose communication between client and server. their approaches are fundamentally different:

  1. Data Fetching
  • REST: Multiple endpoints return predefined responses, often forcing the client to fetch extra data (over-fetching) or make multiple calls (under-fetching).

  • GraphQL: A single endpoint lets the client specify exactly what fields and nested resources are required.

2. Flexibility

  • REST: The server dictates the response structure.

  • GraphQL: The client defines the query, gaining flexibility and reducing unnecessary payloads.

3. Versioning

  • REST: Requires versioning (v1, v2, etc.) to accommodate changes.

  • GraphQL: Evolves without versioning by adding new fields and types, leaving old ones intact.

4. Performance

  • REST: May require multiple round trips to fetch related resources.

  • GraphQL: Resolves multiple resources in a single query.

Project Setup: Laying a Solid Foundation

Prerequisites

  • Node.js (v16+ recommended)

  • Basic TypeScript knowledge

Step 1: Initialize Your Project

npm init -y

Step 2: Install Dependencies

npm install type-graphql reflect-metadata graphql @apollo/server
npm install --save-dev ts-node-dev typescript ts-node

Step 3: TypeScript Configuration

In tsconfig.json, enable decorators, emit type metadata, and target modern JS:

{
  "compilerOptions": {
    "target": "ES2021",
    "module": "commonjs",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "outDir": "build",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}

Core GraphQL Concepts (In Action!)

1. Object & Input Types via Type-GraphQL

Say goodbye to repetitive schema code! Use TypeScript classes and decorators instead:

@ObjectType()
export class Product {
  @Field(() => ID)
  id: string;

  @Field()
  name: string;

  @Field(() => Float)
  price: number;
}

@InputType()
export class ProductInput {
  @Field()
  name: string;

  @Field(() => Float)
  price: number;
}

2. Query, Mutation & Field Resolver

  • A query is how clients fetch data from your API. In Type-GraphQL, you define queries with the @Query decorator, associating them with a return type. This is similar to a GET request in REST, but much more flexible, as clients decide exactly what data (and nested fields) they want.

  • A mutation represents data changes like creating or deleting records. It’s similar to POST, PUT, or DELETE requests in REST. Defined with the @Mutation decorator, mutations let clients perform actions and, typically, receive the updated or created data as a response.

  • A field resolver dynamically calculates or fetches a specific field on an object whenever it’s requested in a query. In Type-GraphQL, this is done with the @FieldResolver decorator. This means you don’t need to store every value directly—some data can be computed on the fly.

@Resolver(Product)
export class ProductResolver {
  private products: Product[] = [];

  @Query(() => [Product])
  getAllProducts(): Product[] {
    return this.products;
  }

  @Mutation(() => Product)
  addProduct(@Arg("data") data: ProductInput): Product {
    const product = { id: String(this.products.length + 1), ...data };
    this.products.push(product);
    return product;
  }

  // Example Field Resolver: compute a value on the fly!
  @FieldResolver(() => Float)
  discountedPrice(@Root() product: Product): number {
    return product.price * 0.9; // 10% discount
  }
}

What’s exciting here? Field resolvers let you expose computed fields (like discountedPrice) without storing them!

3. Relationship Resolvers (Tying Your Data Together)

Field resolvers also let you dynamically connect related types:

@ObjectType()
export class User { ... }

@ObjectType()
export class Product {
  // ...
  @Field(() => User)
  owner: User;
}

@Resolver(Product)
export class ProductResolver {
  // ...

  @FieldResolver(() => User)
  owner(@Root() product: Product): User {
    return users.find(user => user.id === product.ownerId);
  }
}

Explore the Full Example on GitHub

Want to see all the code in action or dig deeper into the details?
Check out the complete project on GitHub:

https://github.com/thegeekplanets/graphql-typescript-example

You’ll find the full implementation, step-by-step setup instructions, example queries and mutations, and more.
Feel free to explore, open issues for questions or suggestions, and star the repository if you find it helpful!

Final Thoughts

GraphQL can seem intimidating at first, but with tools like Type-GraphQL and Apollo Server, building powerful and flexible APIs becomes much more approachable — even fun! By combining TypeScript’s safety with GraphQL’s flexibility, you can shape exactly the API your project needs, all while writing modern, readable code.

Try customizing this example, play with queries in your browser, and see how easy and satisfying GraphQL development can be. Happy coding, and enjoy the journey ahead!

Thank you for reading! Please like ❤️, share ✉, and subscribe 👍 to my blog for more helpful insights. Stay tuned for more updates.🚀

0
Subscribe to my newsletter

Read articles from TheGeekPlanets directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

TheGeekPlanets
TheGeekPlanets

👋 Hi there! I'm a tech enthusiast with a passion for programming and all the exciting things that come with it. ✍️ I’m passionate about giving back to the tech community and regularly write articles sharing insights and best practices based on my experiences. 📚