GraphQL with Node.js: Build a Type-Safe API with Express
Backend

GraphQL with Node.js: Build a Type-Safe API with Express

Sagar Yenkure
August 15th, 2025

Getting Started with GraphQL in Node.js & Express

GraphQL is a powerful query language for your API that allows clients to request exactly the data they need. In this guide, you'll learn how to build a GraphQL API using Node.js, Express, and Apollo Server, with Prisma for database access and Apollo Client for frontend integration.


Tech Stack Overview

  • Express – Web server framework
  • Apollo Server – GraphQL server integration for Node.js
  • GraphQL – Query language for APIs
  • Prisma – ORM for database access
  • TypeScript – Optional, improves DX with type safety
  • Apollo Client – React client for GraphQL APIs

Step 1: Initialize the Backend Project

Set up your backend project with necessary packages:

mkdir graphql-api && cd graphql-api npm init -y # Install server packages npm install express @apollo/server graphql body-parser cors # Install TypeScript and types npm install -D typescript ts-node @types/node @types/express
Click to Copy

Create a basic tsconfig.json for TypeScript:

{ "compilerOptions": { "target": "ES6", "module": "commonjs", "rootDir": "./src", "outDir": "./dist", "strict": true, "esModuleInterop": true } }
Click to Copy

Step 2: Create the Apollo GraphQL Server

Define Your Schema and Resolvers

// src/lib/apolloServer.ts import { ApolloServer } from '@apollo/server'; import prisma from './prisma'; // Ensure Prisma is properly configured const typeDefs = ` type User { id: ID! name: String! email: String! image: String address: String } type Query { hello: String users: [User] } type Mutation { createUser(name: String!, email: String!): User } `; const resolvers = { Query: { hello: () => 'Hello from GraphQL!', users: async () => await prisma.user.findMany(), }, Mutation: { createUser: async (_: any, args: { name: string; email: string }) => { return await prisma.user.create({ data: { name: args.name, email: args.email, }, }); }, }, }; export const server = new ApolloServer({ typeDefs, resolvers });
Click to Copy

Step 3: Set Up Express Server

// src/server.ts import express from 'express'; import { expressMiddleware } from '@apollo/server/express4'; import bodyParser from 'body-parser'; import cors from 'cors'; import { server } from './lib/apolloServer'; const startServer = async () => { const app = express(); await server.start(); app.use(bodyParser.json()); app.use(cors()); app.use('/graphql', expressMiddleware(server)); app.listen(8081, () => { console.log('🚀 Server is running at http://localhost:8081/graphql'); }); }; startServer();
Click to Copy

Step 4: Setup Apollo Client in the Frontend

Install dependencies:

npm install @apollo/client graphql
Click to Copy

Create the Apollo client instance

// lib/apolloClient.ts import { ApolloClient, InMemoryCache } from '@apollo/client'; const client = new ApolloClient({ uri: 'http://localhost:8081/graphql', cache: new InMemoryCache(), }); export default client;
Click to Copy

Wrap your application with ApolloProvider

// src/app/layout.tsx import { ApolloProvider } from '@apollo/client'; import client from '../lib/apolloClient'; export default function RootLayout({ children }) { return ( <html lang="en"> <ApolloProvider client={client}> <body>{children}</body> </ApolloProvider> </html> ); }
Click to Copy

Step 5: Query GraphQL Data in Your Page

// src/app/page.tsx import { useQuery, gql } from '@apollo/client'; const GET_USERS = gql` query { users { id name email } } `; const Home = () => { const { data, loading, error } = useQuery(GET_USERS); if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error.message}</p>; return ( <div> <h1>User List</h1> <ul> {data.users.map((user) => ( <li key={user.id}> {user.name}{user.email} </li> ))} </ul> </div> ); }; export default Home;
Click to Copy

We can also add authentication in graphql api

// src/lib/auth.ts export const getLoggedInUser = async (req: any) => { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith("Bearer ")) return null; const token = authHeader.split(" ")[1]; // Simulate token verification and user fetch if (token === "mock-token") { return { id: "user_123", name: "Demo User", email: "demo@example.com" }; } return null; };
Click to Copy
// src/server.ts import express from 'express'; import { expressMiddleware } from '@apollo/server/express4'; import bodyParser from 'body-parser'; import cors from 'cors'; import { server } from './lib/apolloServer'; import prisma from './lib/prisma'; import { getLoggedInUser } from './lib/auth'; const startServer = async () => { const app = express(); await server.start(); app.use( '/graphql', cors(), bodyParser.json(), expressMiddleware(server, { context: async ({ req }) => { const user = await getLoggedInUser(req); return { user }; }, }) ); app.listen(8081, () => { console.log('Server is running at http://localhost:8081/graphql'); }); }; startServer();
Click to Copy
const resolvers = { Query: { hello: () => 'Hello from GraphQL!', users: async (_: any, __: any, context: any) => { return await context.prisma.user.findMany(); }, }, Mutation: { createUser: async (_: any, args: { name: string; email: string }, context: any) => { if (!context.user) { throw new Error("Unauthorized: User not logged in."); } return await context.prisma.user.create({ data: { name: args.name, email: args.email, }, }); }, }, };
Click to Copy

Benefits of Using GraphQL

  • Fetch only the data you need
  • Use a single endpoint for all queries & mutations
  • Strongly typed schema & auto-generated docs
  • Great developer experience with tools like GraphiQL
  • Scales well with growing frontend needs

Final Thoughts

GraphQL is an excellent choice for modern APIs. Combined with Node.js, Express, and Prisma, it gives you a clean and powerful stack that’s easy to scale and integrate with frontend frameworks like React or Next.js.

You can enhance this base with:

  • Auth (JWT, OAuth, Sessions)
  • Type generation using GraphQL Code Generator
  • Real-time features with subscriptions
  • Deploy on Vercel, Render, or Railway

Start small. Evolve your API as your app grows. Happy coding! 👨‍💻🚀