Lab 10: GraphQL TypeScript

Time: 40 minutes | Level: Advanced | Docker: docker run -it --rm node:20-alpine sh

Build a type-safe GraphQL API using type-graphql decorators: ObjectType, Resolver, Query, Mutation, custom scalars, and schema execution.


Step 1: Environment Setup

docker run -it --rm node:20-alpine sh
npm install -g typescript ts-node
mkdir lab10 && cd lab10
npm init -y
npm install type-graphql graphql reflect-metadata class-validator
echo '{
  "compilerOptions": {
    "module": "commonjs",
    "target": "ES2020",
    "strict": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "esModuleInterop": true
  }
}' > tsconfig.json

💡 type-graphql generates a GraphQL schema from TypeScript classes and decorators. One definition serves as both the runtime schema and the TypeScript type — eliminating the classic "schema drift" problem.


Step 2: ObjectType — Define GraphQL Types

💡 @Field(() => Type) is required for arrays and circular references. For primitives (string, number, boolean), TypeScript metadata is enough and the type hint is optional.


Step 3: Input Types and Validation


Step 4: Resolvers — Queries


Step 5: Building and Executing the Schema


Step 6: Custom Scalars


Step 7: Field Resolvers and Context

💡 @FieldResolver lets you compute derived fields. The @Root() parameter receives the parent object, and @Ctx() gives access to the request context (auth, db connections, etc.).


Step 8: Capstone — Complete Schema Execution

Run:

📸 Verified Output:


Summary

Decorator
Purpose
Example

@ObjectType()

GraphQL output type

class User

@InputType()

GraphQL input type

class CreateUserInput

@Field()

Expose a field

@Field() name: string

@Resolver()

Define a resolver

class UserResolver

@Query()

Read operation

@Query(() => User)

@Mutation()

Write operation

@Mutation(() => Boolean)

@Arg()

Input argument

@Arg('id') id: string

@FieldResolver()

Computed field

Derive from parent + context

@Ctx()

Request context

Auth, database access

Last updated