To create a mini blog using Bun.js, GraphQL, TypeORM, and PostgreSQL, here is a step-by-step guide that walks you through building a simple blog with posts and categories.
Step 1: Set Up Bun.js
Ensure Bun is installed on your system. If not, you can install it:
bun install
Step 2: Create Project Directory
Set up your project directory:
mkdir mini-blog
cd mini-blog
bun init
Step 3: Install Dependencies
You’ll need the following packages:
bun add graphql typeorm pg reflect-metadata
bun add @types/node --dev
Step 4: Configure TypeORM
Set up the ormconfig.ts
to connect with PostgreSQL:
import { DataSource } from 'typeorm';
import { Post } from './entities/Post';
import { Category } from './entities/Category';
export const AppDataSource = new DataSource({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'your_username',
password: 'your_password',
database: 'mini_blog',
synchronize: true,
logging: true,
entities: [Post, Category],
migrations: [],
subscribers: [],
});
Step 5: Create Entities
Define the Post
and Category
entities using TypeORM.
Post.ts
:
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import { Category } from './Category';
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
content: string;
@ManyToOne(() => Category, (category) => category.posts)
category: Category;
}
Category.ts
:
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Post } from './Post';
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(() => Post, (post) => post.category)
posts: Post[];
}
Step 6: Define GraphQL Schema
Create a GraphQL schema in schema.ts
:
import { buildSchema } from 'graphql';
export const schema = buildSchema(`
type Post {
id: ID!
title: String!
content: String!
category: Category
}
type Category {
id: ID!
name: String!
posts: [Post!]
}
type Query {
getPosts: [Post!]
getCategories: [Category!]
}
type Mutation {
createPost(title: String!, content: String!, categoryId: ID!): Post
createCategory(name: String!): Category
}
`);
Step 7: Create Resolvers
Write the resolvers in resolvers.ts
to handle GraphQL queries and mutations:
import { Post } from './entities/Post';
import { Category } from './entities/Category';
import { AppDataSource } from './ormconfig';
export const resolvers = {
getPosts: async () => {
return await AppDataSource.getRepository(Post).find({ relations: ['category'] });
},
getCategories: async () => {
return await AppDataSource.getRepository(Category).find({ relations: ['posts'] });
},
createPost: async ({ title, content, categoryId }) => {
const category = await AppDataSource.getRepository(Category).findOneBy({ id: categoryId });
const post = new Post();
post.title = title;
post.content = content;
post.category = category;
return await AppDataSource.manager.save(post);
},
createCategory: async ({ name }) => {
const category = new Category();
category.name = name;
return await AppDataSource.manager.save(category);
},
};
Step 8: Create Bun Server
Create a simple server using Bun.js to handle GraphQL requests in index.ts
:
import { serve } from "bun";
import { graphql } from "graphql";
import { schema } from './schema';
import { resolvers } from './resolvers';
import { AppDataSource } from './ormconfig';
AppDataSource.initialize().then(() => {
console.log("Data Source initialized");
});
serve({
port: 3000,
fetch: async (req) => {
const { query, variables } = await req.json();
const result = await graphql({ schema, source: query, variableValues: variables, rootValue: resolvers });
return new Response(JSON.stringify(result), {
headers: { "Content-Type": "application/json" },
});
},
});
Step 9: Test the API
Start the server:
bun run index.ts
You can now test your API using a GraphQL client (e.g., Postman or GraphQL Playground):
Create a Category:
mutation {
createCategory(name: "Tech") {
id
name
}
}
Create a Post:
mutation {
createPost(title: "First Post", content: "This is my first post.", categoryId: 1) {
id
title
content
category {
name
}
}
}
Fetch Posts:
query {
getPosts {
id
title
content
category {
name
}
}
}