Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fastapi cleanchat endpoint #15

Merged
merged 4 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/chatcleaner/adapters/entrypoints/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def start_application():
app_.container = container
include_router(app_)
configure_cors(app_)

# start orm mappers
try:
start_mappers()
Expand Down
30 changes: 26 additions & 4 deletions src/chatcleaner/adapters/entrypoints/api/v1/route_cleaning.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import json
from typing import Any
from typing import Any, Union

from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends, Response

from chatcleaner.adapters.entrypoints.api.v1.schemas_cleaning import (
AllCleaningsOut,
CleanedChatOut,
CleaningIn,
CleaningNotFound,
SingleCleaningOut,
)
from chatcleaner.domain.ports.use_cases.clean import CleanUseCaseInterface

router = APIRouter()


@router.get("/cleanings", response_model=None)
@router.get("/cleanings", response_model=AllCleaningsOut)
@inject
async def get_all_cleaning(
use_case: CleanUseCaseInterface = Depends(Provide["cleaning_use_case"]),
Expand All @@ -20,10 +27,25 @@ async def get_all_cleaning(
)


@router.get("/cleanings/{uuid}", response_model=None)
@router.get(
"/cleanings/{uuid}", response_model=Union[SingleCleaningOut, CleaningNotFound]
)
@inject
async def get_cleaning_by_uuid(
uuid: str,
use_case: CleanUseCaseInterface = Depends(Provide["cleaning_use_case"]),
) -> dict[str, Any]:
return use_case.get_by_uuid(uuid)
data = use_case.get_by_uuid(uuid)
return data


@router.post("/cleanings", response_model=Union[CleanedChatOut, None])
@inject
async def clean_chat(
chat: CleaningIn,
use_case: CleanUseCaseInterface = Depends(Provide["cleaning_use_case"]),
):
data = use_case.clean(chat.body)
return Response(
content=json.dumps(data), media_type="application/json", status_code=201
)
32 changes: 32 additions & 0 deletions src/chatcleaner/adapters/entrypoints/api/v1/schemas_cleaning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import datetime

from pydantic import BaseModel


class CleaningIn(BaseModel):
body: str


class CleaningOut(BaseModel):
uuid: str
chat: str
cleaned_chat: str
created_at: datetime.datetime
updated_at: datetime.datetime


class AllCleaningsOut(BaseModel):
result: list[CleaningOut]


class CleaningNotFound(BaseModel):
result: str


class SingleCleaningOut(BaseModel):
result: CleaningOut


class CleanedChatOut(BaseModel):
uuid: str
cleaned_chat: str
1 change: 1 addition & 0 deletions src/chatcleaner/adapters/use_cases/clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def _clean(self, chat: str):
model = cleaning_factory(**data_)
self.uow.cleaning.add(model)
self.uow.commit()
return {"uuid": model.uuid, "cleaned_chat": model.cleaned_chat}

def _get_all(self) -> list[dict[str, list[str]]]:
data_ = {"results": []}
Expand Down
5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ def chat_text_with_times():
return "\n19:05:59 From David to Everyone:\nso far...\n19:35:48 From David to Everyone:\nOur highest priority is to satisfy the customer\nthrough early and continuous delivery\nof valuable software.\n19:36:59 From David to Everyone:\nthe highest, the lowest\n19:55:50 From David to Everyone:\nhttps://agilemanifesto.org/principles.html"


@pytest.fixture(scope="module")
def chat_text_without_times():
return "so far...\nOur highest priority is to satisfy the customer\nthrough early and continuous delivery\nof valuable software.\nthe highest, the lowest\nhttps://agilemanifesto.org/principles.html"


@pytest.fixture(scope="module")
def get_fake_repository():
return FakeCleaningRepository()
Expand Down
33 changes: 33 additions & 0 deletions tests/integrations/test_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import fastapi
import pytest
from fastapi.exceptions import HTTPException
from httpx import AsyncClient

from chatcleaner.adapters.entrypoints.api.app import app
Expand Down Expand Up @@ -59,3 +61,34 @@ async def test_get_cleaning_by_uuid_async_api_with_fake_uuid_return_Not_found(
assert response.status_code == 200
data = response.json()
assert data["result"] == "Not found"


@pytest.mark.anyio
@pytest.mark.integration
async def test_clean_chat_endpoint_returns_201(
get_fake_container,
async_client: AsyncClient,
chat_text_with_times: str,
chat_text_without_times: str,
):
use_case = get_fake_container.cleaning_use_case()
with app.container.cleaning_use_case.override(use_case):
response = await async_client.post(
"/clean/cleanings", json={"body": chat_text_with_times}
)
assert response.status_code == 201
assert response.json()["uuid"] is not None
assert response.json()["cleaned_chat"] == chat_text_without_times


@pytest.mark.anyio
@pytest.mark.integration
async def test_clean_chat_endpoint_returns_error_if_max_length_is_exceeded(
get_fake_container, async_client: AsyncClient
):
use_case = get_fake_container.cleaning_use_case()
with app.container.cleaning_use_case.override(use_case):
response = await async_client.post(
"/clean/cleanings", json={"chat": "a" * 2001}
)
assert response.status_code == 422
15 changes: 5 additions & 10 deletions tests/integrations/test_cleaning_use_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
def test_clean_use_case_clean(get_fake_container, get_clean_use_case):
with Container.cleaning_uow.override(get_fake_container.cleaning_uow):
with Container.chat_service.override(get_fake_container.chat_service):
get_clean_use_case.clean("\n19:10:00 from David to Everyone:\ntest")
result = get_clean_use_case.clean(
"\n19:10:00 from David to Everyone:\ntest"
)
assert result["uuid"] is not None
assert result["cleaned_chat"] == "test"
uow_ = get_fake_container.cleaning_uow()
with uow_:
result = uow_.cleaning.get_all()
Expand All @@ -28,15 +32,6 @@ def test_clean_use_case_get_all(get_fake_container, get_clean_use_case):
result = get_clean_use_case.get_all()
# fixtures are scopes to module, so this should be 4
assert len(result["results"]) == 4
# breakpoint()
# assert result[0].chat == "\n19:10:00 from David to Everyone:\ntest"
# assert result[0].cleaned_chat == "test"
# assert result[1].chat == "\n19:10:00 from David to Everyone:\ntest 1"
# assert result[1].cleaned_chat == "test 1"
# assert result[2].chat == "\n19:10:00 from David to Everyone:\ntest 2"
# assert result[2].cleaned_chat == "test 2"
# assert result[3].chat == "\n19:10:00 from David to Everyone:\ntest 3"
# assert result[3].cleaned_chat == "test 3"


@pytest.mark.integration
Expand Down