This project, developed as part of the Odin Project, is a full-stack blog platform featuring a React frontend and a RESTful API. Users can create, read, update, and delete blog posts and comments with secure JWT authentication.
- Overview
- Features
- Demo
- Project Structure
- Technologies
- Getting Started
- API Documentation
- Authorisation
- Error Handling
- Contributing
A modern blog platform built with React and Express.js, featuring:
- Clean, responsive UI built with React and Vite
- Secure REST API with JWT authentication
- CRUD operations for posts and comments
- Role-based authorisation
- PostgreSQL database with Prisma ORM
- π Secure user authentication
- βοΈ Create and manage blog posts
- π¬ Engage through comments
- π€ User profiles
- π‘οΈ Role-based access control
- π± Responsive design
The website is live. Log in with the demo credentials to explore the features of the full-stack application:
- username: guest
- password: iamaguest
blog-api/
βββ client/ # React frontend
βββ public/ # Static assets (e.g., icons, images)
βββ src/
βββ components/ # React components
βββ pages/ # Page components
βββ services/ # API service calls
βββ .env files # Environment configuration
βββ .gitignore # Git ignore file
βββ eslint.config.js # ESLint configuration
βββ index.html # HTML entry point
βββ package-lock.json # Dependency lock file
βββ package.json # Node.js project manifest
βββ vite.config.js # Vite configuration
βββ server/ # Express backend
βββ config/ # Custom middleware
βββ controllers/ # Route controllers
βββ bin/ # Server entry point
βββ routes/ # API routes
βββ prisma/ # Database schema and migrations
βββ .env files # Environment configuration
βββ .gitignore # Git ignore file
βββ app.js # Server entry point
βββ package-lock.json # Dependency lock file
βββ package.json # Node.js project manifest
- React 18
- Vite
- React Router
- Express.js
- Prisma (ORM)
- Passport JWT
- Node.js
- PostgreSQL
- Node.js (v18 or higher)
- npm or yarn
- PostgreSQL database
-
Clone the repository:
git clone git@github.com:kiffoh/blog-api.git cd blog-api
-
Install dependencies:
# Install backend dependencies cd server npm install # Install frontend dependencies cd ../client npm install
To set up your environment, create a .env
file in the root folders of your project (e.g. in the client and server folder). These files should contain the following required environment variables, along with descriptions for each:
- VITE_ENV: Set to
development
orproduction
to specify the environment. - VITE_SERVER_URL: URL for your backend application
- NODE_ENV: Set to
development
orproduction
to specify the environment. - JWT_SECRET: Secret key for signing tokens
- FRONTEND_URL: URL for your frontend application
- DATABASE_URL: Connection string for your database
If you want to have separate environment files for production and development, you can create .env.production
and .env.development
. You will also need to set the NODE_ENV
variable in the command line or use the cross-env
package (already a dependency) for Windows users.
NODE_ENV=development
DATABASE_URL=database-url
FRONTEND_URL=api-url
JWT_SECRET='your-secret-key'
- Ensure that you replace the placeholder values with your actual configuration.
- Keep your
.env
file out of version control by adding it to your.gitignore
.
The schema is implemented using Prisma with PostgreSQL as the database provider.
To apply the database schema migrations, run the following command:
npx prisma migrate dev
Alternatively, you can use the commands defined in the package.json, which allow specifying the development or production database:
"migrate:dev": "cross-env DATABASE_URL=development-url npx prisma migrate dev",
"migrate:prod": "cross-env DATABASE_URL=production-url npx prisma migrate dev",
- Environment-specific migrations: Ensure that you set the
NODE_ENV
to eitherdevelopment
orproduction
before running the migration commands. - Windows users: You must use
cross-env
to set environment variables, as shown in thepackage.json
commands. - macOS/Linux users: You can remove
cross-env
from the commands, as environment variables can be set directly in the terminal.
Run the backend:
npm run dev
Run the frontend:
cd ../client
npm run dev
All protected routes require a JWT token in the Authorisation header:
Authorization: Bearer <your_jwt_token>
Endpoint | Method | Auth Required | Description |
---|---|---|---|
/users |
GET | Yes | Get all users |
/users/sign-up |
POST | No | Create new user account |
/users/log-in |
POST | No | Authenticate user and get token |
/users/:userId |
GET | Yes | Get specific user details |
/users/:userId |
PUT | Yes | Update user details (user can only update their own profile) |
/users/:userId |
DELETE | Yes | Delete user account (user can only delete their own account) |
Endpoint | Method | Auth Required | Description |
---|---|---|---|
/posts |
GET | No | Get all blog posts |
/posts |
POST | Yes | Create new blog post |
/posts/:postId |
GET | No | Get specific post |
/posts/:postId |
PUT | Yes | Update post (author only) |
/posts/:postId |
DELETE | Yes | Delete post (author only) |
Endpoint | Method | Auth Required | Description |
---|---|---|---|
/posts/:postId/comments |
POST | Yes | Add comment to post |
/posts/:postId/comments/:commentId |
GET | Yes | Get specific comment |
/posts/:postId/comments/:commentId |
PUT | Yes | Update comment (author only) |
/posts/:postId/comments/:commentId |
DELETE | Yes | Delete comment (author only) |
Example API usage:
// Sign up a new user
fetch('http://localhost:3000/users/sign-up', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: 'newuser',
password: 'password123',
email: 'user@example.com'
})
});
// Create a new blog post (authenticated)
fetch('http://localhost:3000/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
title: 'My First Post',
content: 'Hello, world!'
})
});
The API implements three levels of authorisation middleware:
-
ofUser
: Ensures users can only modify their own profiles// Required for: - PUT /users/:userId - DELETE /users/:userId
-
ofPost
: Ensures users can only modify their own posts// Required for: - PUT /posts/:postId - DELETE /posts/:postId
-
ofComment
: Ensures users can only modify their own comments// Required for: - PUT /posts/:postId/comments/:commentId - DELETE /posts/:postId/comments/:commentId
The API returns standard HTTP status codes:
- 200: Success
- 201: Created
- 400: Bad Request
- 401: Unauthorized
- 403: Forbidden
- 404: Not Found
- 500: Internal Server Error
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request