Initial API
This commit is contained in:
commit
472469c913
8 changed files with 201 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
__pycache__
|
||||||
|
.env
|
77
README.md
Normal file
77
README.md
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
# Blogging Platform API
|
||||||
|
|
||||||
|
This is a RESTful API for a simple blogging platform built using the FastAPI framework in Python. The API allows users to perform CRUD operations on blog posts, comment on posts, and like/dislike comments. Data is stored in a MongoDB database.
|
||||||
|
|
||||||
|
## Setup Instructions
|
||||||
|
|
||||||
|
1. **Clone the Repository:**
|
||||||
|
Clone the repository to your local machine:
|
||||||
|
```
|
||||||
|
git clone <repository_url>
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Install Dependencies:**
|
||||||
|
Navigate to the project directory and install dependencies:
|
||||||
|
```
|
||||||
|
pip install fastapi uvicorn motor python-dotenv
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Create `.env` file:**
|
||||||
|
Create a `.env` file in the project src directory with the following content:
|
||||||
|
```
|
||||||
|
MONGODB_URL=<your_mongodb_url>
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Run the API:**
|
||||||
|
Start the API server using Uvicorn:
|
||||||
|
```
|
||||||
|
uvicorn main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Documentation
|
||||||
|
|
||||||
|
### Posts
|
||||||
|
|
||||||
|
- **Create Post:** `POST /posts/`
|
||||||
|
- Create a new post with a title and content.
|
||||||
|
- **Read Post:** `GET /posts/{post_id}`
|
||||||
|
- Retrieve details of a specific post by ID.
|
||||||
|
- **Read All Posts:** `GET /posts/`
|
||||||
|
- Retrieve details of all posts.
|
||||||
|
- **Update Post:** `PUT /posts/{post_id}`
|
||||||
|
- Update an existing post by ID.
|
||||||
|
- **Delete Post:** `DELETE /posts/{post_id}`
|
||||||
|
- Delete a post by ID.
|
||||||
|
|
||||||
|
### Comments
|
||||||
|
|
||||||
|
- **Create Comment:** `POST /comments/`
|
||||||
|
- Create a new comment associated with a post.
|
||||||
|
- **Read Comments:** `GET /comments/{post_id}`
|
||||||
|
- Retrieve all comments associated with a specific post by ID.
|
||||||
|
- **Update Comment:** `PUT /comments/{comment_id}`
|
||||||
|
- Update an existing comment by ID.
|
||||||
|
- **Like Comment:** `PUT /comments/{comment_id}/like`
|
||||||
|
- Increment the like count of a comment by ID.
|
||||||
|
- **Dislike Comment:** `PUT /comments/{comment_id}/dislike`
|
||||||
|
- Increment the dislike count of a comment by ID.
|
||||||
|
|
||||||
|
## Data Models
|
||||||
|
|
||||||
|
### Post
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"title": str, # Title of the post
|
||||||
|
"content": str # Content of the post
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Comment
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"post_id": str, # ID of the post to which the comment belongs
|
||||||
|
"text": str, # Text content of the comment
|
||||||
|
"likes": int, # Number of likes for the comment
|
||||||
|
"dislikes": int # Number of dislikes for the comment
|
||||||
|
}
|
||||||
|
```
|
13
src/api/db.py
Normal file
13
src/api/db.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
from dotenv import dotenv_values
|
||||||
|
from motor.motor_asyncio import AsyncIOMotorClient
|
||||||
|
|
||||||
|
# Load environment variables from .env
|
||||||
|
env_vars = dotenv_values(".env")
|
||||||
|
|
||||||
|
# Get the MongoDB URL
|
||||||
|
mongodb_uri = env_vars.get("MONGODB_URI")
|
||||||
|
if not mongodb_uri:
|
||||||
|
raise EnvironmentError("MongoDB URI not found in .env file")
|
||||||
|
|
||||||
|
client = AsyncIOMotorClient(mongodb_uri)
|
||||||
|
db = client.blog_db
|
42
src/api/endpoints/comments.py
Normal file
42
src/api/endpoints/comments.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
from bson import ObjectId
|
||||||
|
from ..models.comment import Comment
|
||||||
|
from ..db import db
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/")
|
||||||
|
async def create_comment(comment: Comment):
|
||||||
|
result = await db.comments.insert_one(comment.dict())
|
||||||
|
new_comment = await db.comments.find_one({"_id": result.inserted_id})
|
||||||
|
new_comment['_id'] = str(new_comment['_id'])
|
||||||
|
return new_comment
|
||||||
|
|
||||||
|
@router.get("/{post_id}")
|
||||||
|
async def read_comments(post_id: str):
|
||||||
|
comments = []
|
||||||
|
async for comment in db.comments.find({"post_id": post_id}):
|
||||||
|
comment['_id'] = str(comment['_id'])
|
||||||
|
comments.append(comment)
|
||||||
|
return comments
|
||||||
|
|
||||||
|
@router.put("/{comment_id}")
|
||||||
|
async def update_comment(comment_id: str, comment: Comment):
|
||||||
|
result = await db.comments.update_one({"_id": ObjectId(comment_id)}, {"$set": comment.dict()})
|
||||||
|
if result.modified_count == 0:
|
||||||
|
raise HTTPException(status_code=404, detail="Comment not found")
|
||||||
|
return {"message": "Comment updated successfully"}
|
||||||
|
|
||||||
|
@router.put("/{comment_id}/like")
|
||||||
|
async def like_comment(comment_id: str):
|
||||||
|
result = await db.comments.update_one({"_id": ObjectId(comment_id)}, {"$inc": {"likes": 1}})
|
||||||
|
if result.modified_count == 0:
|
||||||
|
raise HTTPException(status_code=404, detail="Comment not found")
|
||||||
|
return {"message": "Comment liked successfully"}
|
||||||
|
|
||||||
|
@router.put("/{comment_id}/dislike")
|
||||||
|
async def dislike_comment(comment_id: str):
|
||||||
|
result = await db.comments.update_one({"_id": ObjectId(comment_id)}, {"$inc": {"dislikes": 1}})
|
||||||
|
if result.modified_count == 0:
|
||||||
|
raise HTTPException(status_code=404, detail="Comment not found")
|
||||||
|
return {"message": "Comment disliked successfully"}
|
48
src/api/endpoints/posts.py
Normal file
48
src/api/endpoints/posts.py
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
from bson import ObjectId
|
||||||
|
from bson.errors import InvalidId
|
||||||
|
from ..models.post import Post
|
||||||
|
from ..db import db
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/")
|
||||||
|
async def create_post(post: Post):
|
||||||
|
result = await db.posts.insert_one(post.dict())
|
||||||
|
new_post = await db.posts.find_one({"_id": result.inserted_id})
|
||||||
|
new_post['_id'] = str(new_post['_id'])
|
||||||
|
return new_post
|
||||||
|
|
||||||
|
@router.get("/{post_id}")
|
||||||
|
async def read_post(post_id: str):
|
||||||
|
try:
|
||||||
|
post = await db.posts.find_one({"_id": ObjectId(post_id)})
|
||||||
|
if post:
|
||||||
|
post['_id'] = str(post['_id'])
|
||||||
|
return post
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=404, detail="Post not found")
|
||||||
|
except InvalidId:
|
||||||
|
raise HTTPException(status_code=422, detail="Invalid post ID format")
|
||||||
|
|
||||||
|
@router.get("/")
|
||||||
|
async def read_all_posts():
|
||||||
|
posts = []
|
||||||
|
async for post in db.posts.find():
|
||||||
|
post['_id'] = str(post['_id'])
|
||||||
|
posts.append(post)
|
||||||
|
return posts
|
||||||
|
|
||||||
|
@router.put("/{post_id}")
|
||||||
|
async def update_post(post_id: str, post: Post):
|
||||||
|
result = await db.posts.update_one({"_id": ObjectId(post_id)}, {"$set": post.dict()})
|
||||||
|
if result.modified_count == 0:
|
||||||
|
raise HTTPException(status_code=404, detail="Post not found")
|
||||||
|
return {"message": "Post updated successfully"}
|
||||||
|
|
||||||
|
@router.delete("/{post_id}")
|
||||||
|
async def delete_post(post_id: str):
|
||||||
|
result = await db.posts.delete_one({"_id": ObjectId(post_id)})
|
||||||
|
if result.deleted_count == 0:
|
||||||
|
raise HTTPException(status_code=404, detail="Post not found")
|
||||||
|
return {"message": "Post deleted successfully"}
|
7
src/api/models/comment.py
Normal file
7
src/api/models/comment.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
class Comment(BaseModel):
|
||||||
|
post_id: str
|
||||||
|
text: str
|
||||||
|
likes: int = 0
|
||||||
|
dislikes: int = 0
|
5
src/api/models/post.py
Normal file
5
src/api/models/post.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
class Post(BaseModel):
|
||||||
|
title: str
|
||||||
|
content: str
|
7
src/main.py
Normal file
7
src/main.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from api.endpoints import posts, comments
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
app.include_router(posts.router, prefix="/posts", tags=["posts"])
|
||||||
|
app.include_router(comments.router, prefix="/comments", tags=["comments"])
|
Loading…
Reference in a new issue