Module 29: TypeScript with GraphQL
Build type-safe GraphQL APIs with TypeScript, covering schema definition, resolvers, and code generation.
1. Setup GraphQL with TypeScript
npm install graphql apollo-server
npm install --save-dev @graphql-codegen/cli @graphql-codegen/typescript
2. Schema Definition
import { gql } from "apollo-server";
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
type Query {
user(id: ID!): User
users: [User!]!
post(id: ID!): Post
}
type Mutation {
createUser(name: String!, email: String!): User!
createPost(title: String!, content: String!, authorId: ID!): Post!
}
`;
3. Type-Safe Resolvers
interface User {
id: string;
name: string;
email: string;
}
interface Post {
id: string;
title: string;
content: string;
authorId: string;
}
interface Context {
dataSources: {
userAPI: UserAPI;
postAPI: PostAPI;
};
}
const resolvers = {
Query: {
user: async (
_parent: any,
{ id }: { id: string },
context: Context
): Promise<User | null> => {
return context.dataSources.userAPI.getUser(id);
},
users: async (
_parent: any,
_args: {},
context: Context
): Promise<User[]> => {
return context.dataSources.userAPI.getAllUsers();
}
},
Mutation: {
createUser: async (
_parent: any,
args: { name: string; email: string },
context: Context
): Promise<User> => {
return context.dataSources.userAPI.createUser(args);
}
},
User: {
posts: async (
parent: User,
_args: {},
context: Context
): Promise<Post[]> => {
return context.dataSources.postAPI.getPostsByAuthor(parent.id);
}
}
};
4. Code Generation
# codegen.yml
schema: "./src/schema.graphql"
generates:
./src/generated/graphql.ts:
plugins:
- typescript
- typescript-resolvers
npx graphql-codegen
5. Apollo Server Setup
import { ApolloServer } from "apollo-server";
import { typeDefs } from "./schema";
import { resolvers } from "./resolvers";
const server = new ApolloServer({
typeDefs,
resolvers,
context: () => ({
dataSources: {
userAPI: new UserAPI(),
postAPI: new PostAPI()
}
})
});
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
6. Client-Side with Apollo Client
import { ApolloClient, InMemoryCache, gql } from "@apollo/client";
const client = new ApolloClient({
uri: "http://localhost:4000/graphql",
cache: new InMemoryCache()
});
// Type-safe query
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
interface GetUserData {
user: {
id: string;
name: string;
email: string;
};
}
interface GetUserVariables {
id: string;
}
const { data } = await client.query<GetUserData, GetUserVariables>({
query: GET_USER,
variables: { id: "1" }
});
7. React with Apollo
import { useQuery, useMutation } from "@apollo/client";
function UserProfile({ id }: { id: string }) {
const { data, loading, error } = useQuery<GetUserData, GetUserVariables>(
GET_USER,
{ variables: { id } }
);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h1>{data?.user.name}</h1>
<p>{data?.user.email}</p>
</div>
);
}
Key Takeaways
✅ GraphQL provides type-safe APIs
✅ Code generation creates TypeScript types
✅ Apollo Server for backend
✅ Apollo Client for frontend
✅ Strong typing across client and server
Practice Exercises
Exercise 1: Build a Blog API
Create a complete GraphQL API for a blog with users, posts, and comments.
Exercise 2: Implement Subscriptions
Add real-time subscriptions to your GraphQL API.
Next Steps
In Module 30, we'll explore Monorepo with TypeScript using tools like Nx and Turborepo.