Introduction
Have you ever wanted to build your own backend API but felt overwhelmed by terms like GraphQL, resolvers, and databases? Good news — you’re in the right place!
In the world of APIs, REST has been the traditional choice for a long time. However, GraphQL is becoming increasingly popular because it allows clients to request exactly the data they need — no more, no less. Instead of multiple endpoints like in REST, GraphQL gives you one smart endpoint that does exactly what you ask.
Why Choose GraphQL Over REST?
Traditional REST APIs can become bulky with multiple endpoints and overfetching data. GraphQL solves this by providing a single flexible endpoint where clients can ask for exactly what they need, making APIs more efficient and developer-friendly. Companies like GitHub, Shopify, and Facebook use GraphQL in production for this very reason.
In this article, I'll walk you through what I learned while building my first GraphQL API using Node.js, Prisma ORM, and SQLite. Whether you're new to GraphQL or just curious about a different way to build APIs, this guide is for you.
By the end, you’ll have a running GraphQL server that can create and fetch task data — and you'll truly understand the core concepts behind it. Even better, you’ll walk away with a working backend that you can connect to a frontend project later!
Let's dive in and make backend development fun and simple!
Why This Project Matters
Learning GraphQL and Prisma together is a superpower for modern developers. Many real-world applications — from simple todo apps to complex booking systems — rely on APIs to manage and share data.
By mastering how to build a GraphQL API with Prisma, you're opening the door to:
- Building fullstack applications faster
- Writing cleaner and more efficient backend code
- Creating projects you can showcase in your portfolio
We’ll keep it practical by building a simple "Task Manager" API. You’ll be able to:
- Create new tasks
- Mark them as completed
- Fetch all tasks easily
What I Learned
Building this project was not just about writing code; it was about understanding the underlying architecture and how modern APIs function.
Here are some of the key lessons I took away:
GraphQL is powerful because it gives clients control. Instead of relying on multiple endpoints like REST, I could get exactly the data I needed.
Prisma makes database operations simpler. Defining models and generating a client in just a few commands felt incredibly efficient.
SQLite is perfect for quick prototyping. I didn’t need a heavy setup, and yet I had a real database running within minutes.
Error messages like Unexpected end of input are common when a script is incomplete — in my case, I had missed a closing bracket in server.js. Debugging is part of the process!
This hands-on experience helped me appreciate the modern tools that simplify backend development.
Prerequisites
Before we dive in, make sure you have the following:
- Node.js installed (v16 or higher) ➔ Download Node.js
- Basic command-line knowledge
- Code editor (like VS Code)
- Postman or GraphQL Playground installed (or VS Code extension)
- (Optional) SQLite Browser ➔ Download SQLite Browser Don't worry — I’ll explain every step so you can follow along easily!
Project Setup
- Create a new project folder
mkdir graphql-prisma-api
cd graphql-prisma-api
- Initialize a Node.js project
npm init -y
- Install dependencies
npm install express graphql express-graphql prisma @prisma/client sqlite3 dotenv
- Initialize Prisma
npx prisma init
This will create a new prisma folder and a .env file.
Your project folder should now look like:
graphql-prisma-api/
├── node_modules/
├── prisma/
│ └── schema.prisma
├── .env
├── package.json
└── package-lock.json
Setting Up the Database with Prisma and SQLite
- Configure your .env file Replace the value of DATABASE_URL with:
DATABASE_URL="file:./dev.db"
- Define your Prisma model Replace the contents of prisma/schema.prisma with:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model Task {
id Int @id @default(autoincrement())
title String
description String
completed Boolean @default(false)
createdAt DateTime @default(now())
}
- Migrate the database and generate the client
npx prisma migrate dev --name init
This creates a dev.db SQLite file and generates the Prisma client for database access.
You now have a real database ready to store tasks!
Building the GraphQL Server
- Create a server.js file
touch server.js
- Add the following code to server.js
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
const app = express();
const schema = buildSchema(`
type Task {
id: Int!
title: String!
description: String!
completed: Boolean!
createdAt: String!
}
type Query {
getTasks: [Task!]!
}
type Mutation {
createTask(title: String!, description: String!): Task!
completeTask(id: Int!): Task!
}
`);
const root = {
getTasks: async () => await prisma.task.findMany(),
createTask: async ({ title, description }) => {
return await prisma.task.create({
data: { title, description },
});
},
completeTask: async ({ id }) => {
return await prisma.task.update({
where: { id },
data: { completed: true },
});
},
};
app.use('/graphql', graphqlHTTP({
schema,
rootValue: root,
graphiql: true,
}));
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
console.log(`🚀 Server running at http://localhost:${PORT}/graphql`);
});
- Run the server
node server.js
Visit: http://localhost:4000/graphql
Testing the API
You can test your API using GraphiQL in your browser.
1.Fetch all tasks
{
getTasks {
id
title
description
completed
createdAt
}
}
mutation {
createTask(title: "Write article", description: "Finish GraphQL tutorial") {
id
title
completed
}
}
3.Complete a task
mutation {
completeTask(id: 1) {
id
title
completed
}
}
Why GraphQL Is So Efficient
One of the coolest things I learned while building this project is how GraphQL optimizes data fetching. Unlike REST APIs that use multiple endpoints, GraphQL uses a single smart endpoint that serves as the parent node. From there, it dynamically moves to fetch only the specific child nodes (fields) you request.
GraphQL operates kind of like a breadth-first search algorithm, scanning through the structure of your schema tree level by level. It doesn’t fetch unnecessary data — just what you ask for. This makes responses faster, reduces payload size, and improves performance overall.
Conclusion
Congratulations! You've just built your first GraphQL API using Node.js, Prisma, and SQLite. You now have:
- A working GraphQL server
- A real SQLite database
- The ability to create and fetch tasks
This is a great foundation for fullstack development. In the next part, we’ll improve this setup with TypeScript, Prisma validation, and real-time subscriptions.
Coming Next:
Level Up Your GraphQL Server: TypeScript, Prisma, and Real-Time Features
Thanks for reading! 🚀
Learn More
Here are some helpful resources if you'd like to dive deeper:
- GraphQL Official Docs
- Prisma Documentation
- SQLite Documentation
- Node.js Docs
- Express GraphQL
Top comments (0)