Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Blog API — The Odin Project

A RESTful blog API built with Express 5, TypeScript, Prisma, and JWT authentication. Backend-only (no frontend). Supports user registration, role-based authorship requests, blog post CRUD with cover images, threaded comments, and an admin panel for managing authorship.

Tech Stack

Area Choice
Runtime Node.js + TypeScript (compiled with tsc, dev via tsx watch)
Framework Express 5
Database PostgreSQL via Prisma 7 (@prisma/adapter-pg)
Auth JWT (passport-jwt) + bcryptjs for password hashing
Validation express-validator
Image Upload Multer (disk, 5MB limit) → Cloudinary
Rate Limiting express-rate-limit (100 req / 15 min)
Caching apicache (in-memory, 5-min on public post listings)

Data Model

User (id, email, password, role: USER|AUTHOR|ADMIN)
 ├── Profile (firstName, lastName, bio, avatarURL)
 ├── Post (title, content, isPublished, coverImageURL, tags[])
 │    ├── Tag (name)
 │    └── Comment (content, replies[] — self-referencing)
 ├── Comment
 └── AuthorshipRequest (approved: bool)

Users sign up as USER. They submit an AuthorshipRequest which an ADMIN approves to promote them to AUTHOR. Only authors can create posts.

API Endpoints

Auth (/auth)

Method Endpoint Auth Description
POST /auth/sign-up Register (email, password, firstName, lastName)
POST /auth/login Login → returns JWT

Posts (/posts)

Method Endpoint Auth Description
GET /posts List all published posts (cached 5 min)
POST /posts JWT Create post (author only)
GET /posts/:postid Get single post
PUT /posts/:postid JWT Edit post (owner only)
DELETE /posts/:postid JWT Delete post (owner only)
PATCH /posts/:postid/cover JWT Upload cover image (multipart)
DELETE /posts/:postid/cover JWT Remove cover image
PATCH /posts/:postid/publish JWT Publish post
PATCH /posts/:postid/unpublish JWT Unpublish post
GET /posts/:postid/comments Get post comments
POST /posts/:postid/comments JWT Add comment to post

Comments (/comments)

Method Endpoint Auth Description
GET /comments/:commentid Get single comment
PATCH /comments/:commentid JWT Edit comment (owner only)
DELETE /comments/:commentid JWT Delete comment (owner only)
POST /comments/:commentid/replies JWT Reply to a comment (threaded)

Me (/me) — all require JWT

Method Endpoint Description
GET /me Get current user
GET /me/profile Get profile
PATCH /me/profile Edit profile
PATCH /me/profile/avatar Upload avatar (multipart)
DELETE /me/profile/avatar Remove avatar
GET /me/posts List my posts
GET /me/comments List my comments
POST /me/authorship-request Request author role
GET /me/authorship-request Check request status

Users (/users)

Method Endpoint Auth Description
GET /users/:userid/profile View user profile
GET /users/:userid/comments View user's comments

Authors (/authors)

Method Endpoint Auth Description
GET /authors/:authorid/profile View author profile
GET /authors/:authorid/posts View author's posts
GET /authors/:authorid/comments View author's comments

Admin (/admin) — requires ADMIN role

Method Endpoint Description
GET /admin/authorship-requests List all requests
GET /admin/authorship-requests/:requestid View single request
PATCH /admin/authorship-requests/:requestid/approve Approve → promote user to AUTHOR
PATCH /admin/authorship-requests/:requestid/revoke Revoke authorship

Project Structure

src/
├── index.ts                 # Express app setup, route mounting, rate limiter
├── config/passport.ts       # Passport JWT strategy (Bearer token → user lookup)
├── controllers/             # Route handlers (auth, post, comment, me, user, author, admin)
├── routes/                  # Express routers (one per resource)
├── middleware/
│   ├── auth.middleware.ts   # isAuth (passport JWT), isAdmin, isAuthor guards
│   ├── user.middleware.ts   # Attaches current user to res.locals
│   ├── validate.middleware.ts  # express-validator result check
│   ├── error.middleware.ts  # Global error handler
│   └── multererror.middleware.ts  # Multer upload error handling
├── validators/              # express-validator rule chains per resource
├── services/
│   └── upload.service.ts    # Cloudinary upload/delete for avatars & cover images
├── lib/
│   ├── prisma.ts            # Prisma client singleton
│   ├── multer.ts            # Multer config (disk storage, 5MB limit)
│   └── cache.ts             # apicache middleware wrapper
├── generated/prisma/        # Auto-generated Prisma client
prisma/
├── schema.prisma            # Database schema
└── migrations/              # SQL migration history

Environment Variables

PORT=3500
DATABASE_URL="postgresql://user:password@localhost:5432/mydatabase?schema=public"
JWT_SECRET="replace_with_a_secure_secret"
CLOUDINARY_URL="cloudinary://api_key:api_secret@cloud_name"
ClOUDINARY_FOLDER_NAME="folder-name"

Getting Started

npm install
cp .env.example .env        # Fill in values
npx prisma migrate dev      # Apply schema + generate client
npm run dev                  # → http://localhost:3500

Scripts

Command Description
npm run dev Dev server with hot reload (tsx watch)
npm run build prisma generate + tsc
npm run start Run compiled dist/index.js
npm run prod_build prisma migrate deploy + prisma generate + tsc

About

A RESTful blog API built with Express 5, TypeScript, Prisma, and JWT authentication. Backend-only (no frontend). Supports user registration, role-based authorship requests, blog post CRUD with cover images, threaded comments, and an admin panel for managing authorship.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages