-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor the API to use a sample in-memory User model
- Loading branch information
1 parent
f475bc3
commit 18348b2
Showing
13 changed files
with
191 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
__all__ = ["User"] | ||
|
||
from app.v1.models.user import User |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from pydantic import BaseModel, EmailStr | ||
|
||
|
||
class User(BaseModel): | ||
username: str | ||
email: EmailStr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
from fastapi import APIRouter | ||
|
||
from app.v1.routers.dummy import router as dummy_router | ||
from app.v1.routers.users import router as users_router | ||
|
||
|
||
router = APIRouter(prefix="/v1") | ||
router.include_router(dummy_router, prefix="/dummy", tags=["Dummy"]) | ||
router.include_router(users_router, prefix="/users", tags=["Users"]) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
from fastapi import APIRouter, Depends, HTTPException, status | ||
|
||
from app.v1.models import User | ||
from app.v1.services import UserManager, get_user_manager | ||
|
||
|
||
router = APIRouter() | ||
|
||
|
||
@router.post("/") | ||
async def create_user(user: User, user_manager: UserManager = Depends(get_user_manager)) -> User: | ||
try: | ||
return user_manager.create_user(user) | ||
except ValueError as ex: | ||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(ex)) | ||
|
||
|
||
@router.get("/{username}") | ||
async def get_user(username: str, user_manager: UserManager = Depends(get_user_manager)) -> User: | ||
try: | ||
return user_manager.get_user(username) | ||
except ValueError as ex: | ||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)) | ||
|
||
|
||
@router.get("/") | ||
async def list_users(user_manager: UserManager = Depends(get_user_manager)) -> list[User]: | ||
return user_manager.list_users() | ||
|
||
|
||
@router.put("/{username}") | ||
async def update_user(username: str, user: User, user_manager: UserManager = Depends(get_user_manager)) -> User: | ||
try: | ||
return user_manager.update_user(username, user) | ||
except ValueError as ex: | ||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)) | ||
|
||
|
||
@router.delete("/{username}") | ||
async def delete_user(username: str, user_manager: UserManager = Depends(get_user_manager)) -> User: | ||
try: | ||
return user_manager.delete_user(username) | ||
except ValueError as ex: | ||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
__all__ = ["get_user_manager", "UserManager"] | ||
|
||
from app.v1.services.user.dependency import get_user_manager | ||
from app.v1.services.user.user_manager import UserManager |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from app.v1.services.user.user_manager import UserManager | ||
|
||
|
||
def get_user_manager() -> UserManager: | ||
return UserManager() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from app.v1.models import User | ||
|
||
|
||
class UserManager: | ||
_users: dict[str, User] = {} | ||
|
||
def create_user(self, user: User) -> User: | ||
if user.username in self._users: | ||
raise ValueError(f"User with username '{user.username}' already exists") | ||
self._users[user.username] = user | ||
return user | ||
|
||
def get_user(self, username: str) -> User: | ||
if username not in self._users: | ||
raise ValueError(f"User with username '{username}' does not exist") | ||
return self._users[username] | ||
|
||
def list_users(self) -> list[User]: | ||
return list(self._users.values()) | ||
|
||
def update_user(self, username: str, user: User) -> User: | ||
if username not in self._users: | ||
raise ValueError(f"User with username '{username}' does not exist") | ||
self._users[username] = user | ||
return user | ||
|
||
def delete_user(self, username: str) -> User: | ||
if username not in self._users: | ||
raise ValueError(f"User with username '{username}' does not exist") | ||
return self._users.pop(username) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
from fastapi.testclient import TestClient | ||
|
||
|
||
def test_create_user(client: TestClient) -> None: | ||
user_data = {"username": "testuser", "email": "[email protected]"} | ||
response = client.post("/v1/users/", json=user_data) | ||
assert response.status_code == 200 | ||
assert response.json() == user_data | ||
|
||
|
||
def test_get_user(client: TestClient) -> None: | ||
# First, create a user | ||
user_data = {"username": "getuser", "email": "[email protected]"} | ||
client.post("/v1/users/", json=user_data) | ||
|
||
# Then, retrieve the user | ||
response = client.get("/v1/users/getuser") | ||
assert response.status_code == 200 | ||
assert response.json() == user_data | ||
|
||
|
||
def test_list_users(client: TestClient) -> None: | ||
# Create two users | ||
user1 = {"username": "user1", "email": "[email protected]"} | ||
user2 = {"username": "user2", "email": "[email protected]"} | ||
client.post("/v1/users/", json=user1) | ||
client.post("/v1/users/", json=user2) | ||
|
||
# List all users | ||
response = client.get("/v1/users/") | ||
assert response.status_code == 200 | ||
assert len(response.json()) >= 2 | ||
assert user1 in response.json() | ||
assert user2 in response.json() | ||
|
||
|
||
def test_update_user(client: TestClient) -> None: | ||
# First, create a user | ||
original_data = {"username": "updateuser", "email": "[email protected]"} | ||
client.post("/v1/users/", json=original_data) | ||
|
||
# Then, update the user | ||
updated_data = {"username": "updateuser", "email": "[email protected]"} | ||
response = client.put("/v1/users/updateuser", json=updated_data) | ||
assert response.status_code == 200 | ||
assert response.json() == updated_data | ||
|
||
|
||
def test_delete_user(client: TestClient) -> None: | ||
# First, create a user | ||
user_data = {"username": "deleteuser", "email": "[email protected]"} | ||
client.post("/v1/users/", json=user_data) | ||
|
||
# Then, delete the user | ||
response = client.delete("/v1/users/deleteuser") | ||
assert response.status_code == 200 | ||
assert response.json() == user_data | ||
|
||
# Verify the user is deleted | ||
response = client.get("/v1/users/deleteuser") | ||
assert response.status_code == 404 | ||
|
||
|
||
def test_create_duplicate_user(client: TestClient) -> None: | ||
user_data = {"username": "duplicate", "email": "[email protected]"} | ||
client.post("/v1/users/", json=user_data) | ||
|
||
# Try to create a user with the same username | ||
response = client.post("/v1/users/", json=user_data) | ||
assert response.status_code == 409 | ||
|
||
|
||
def test_get_nonexistent_user(client: TestClient) -> None: | ||
response = client.get("/v1/users/nonexistent") | ||
assert response.status_code == 404 | ||
|
||
|
||
def test_update_nonexistent_user(client: TestClient) -> None: | ||
user_data = {"username": "nonexistent", "email": "[email protected]"} | ||
response = client.put("/v1/users/nonexistent", json=user_data) | ||
assert response.status_code == 404 | ||
|
||
|
||
def test_delete_nonexistent_user(client: TestClient) -> None: | ||
response = client.delete("/v1/users/nonexistent") | ||
assert response.status_code == 404 |