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