commit 472469c913ec1f1527274676b29dd2ff95700e14 Author: Diva Gupta <91871618+GuptaDiva@users.noreply.github.com> Date: Sun May 12 00:16:58 2024 +0530 Initial API diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..112f331 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +.env diff --git a/README.md b/README.md new file mode 100644 index 0000000..bde4373 --- /dev/null +++ b/README.md @@ -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 + ``` + +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= + ``` + +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 +} +``` diff --git a/src/api/db.py b/src/api/db.py new file mode 100644 index 0000000..93a995b --- /dev/null +++ b/src/api/db.py @@ -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 diff --git a/src/api/endpoints/comments.py b/src/api/endpoints/comments.py new file mode 100644 index 0000000..9df1044 --- /dev/null +++ b/src/api/endpoints/comments.py @@ -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"} diff --git a/src/api/endpoints/posts.py b/src/api/endpoints/posts.py new file mode 100644 index 0000000..800fbee --- /dev/null +++ b/src/api/endpoints/posts.py @@ -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"} diff --git a/src/api/models/comment.py b/src/api/models/comment.py new file mode 100644 index 0000000..17f9c86 --- /dev/null +++ b/src/api/models/comment.py @@ -0,0 +1,7 @@ +from pydantic import BaseModel + +class Comment(BaseModel): + post_id: str + text: str + likes: int = 0 + dislikes: int = 0 diff --git a/src/api/models/post.py b/src/api/models/post.py new file mode 100644 index 0000000..e8b4c99 --- /dev/null +++ b/src/api/models/post.py @@ -0,0 +1,5 @@ +from pydantic import BaseModel + +class Post(BaseModel): + title: str + content: str diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..fffe64c --- /dev/null +++ b/src/main.py @@ -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"])