add service layer - #28
Merged
Merged
Conversation
☂️ Python Coverage
Overall Coverage
New Files
Modified Files
|
Contributor
There was a problem hiding this comment.
Pull request overview
Introduces a service layer between FastAPI controllers and SQLAlchemy repositories, centralizes domain-error handling, and cleans up model relationships and FK column loading. Controllers now delegate business logic (entity construction, country existence checks, transaction commits) to PersonService/CountryService/ContinentService, and not-found cases are converted to a uniform {"detail": ...} JSON response via a global DomainError exception handler.
Changes:
- New
pyfastapi/services/layer pluspyfastapi/libs/exceptions.pydomain errors and a global handler inmain.py. - Repositories no longer commit; commits/refreshes moved to services. Controllers stripped of
HTTPException/try/tracebackboilerplate. - Model relationships pluralized (
persons,countries), FK columns no longerdeferred(); unit and e2e tests updated (invalid-country create now expects 404; base repository SQL fixtures updated for the un-deferred FKs).
Reviewed changes
Copilot reviewed 17 out of 19 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pyfastapi/main.py | Registers DomainError exception handler returning standardized JSON. |
| pyfastapi/libs/exceptions.py | Defines DomainError and Person/Country/Continent not-found subclasses. |
| pyfastapi/services/{person,country,continent}.py | New services orchestrating repositories, validating FKs, and managing commits. |
| pyfastapi/services/init.py | Empty package marker. |
| pyfastapi/controllers/{person,country,continent}.py | Switch from repositories+HTTPException to service delegation. |
| pyfastapi/repositories/person.py | create_new_person uses flush (no commit); update_or_create_person no longer commits. |
| pyfastapi/models/person.py | Removes deferred from country_code; relationship back_populates="persons". |
| pyfastapi/models/country.py | Removes deferred from continent_code; adds persons collection and continent back_populates fix. |
| pyfastapi/models/continent.py | Renames relationship to countries: List[Country]. |
| tests/unit_tests/services/{init,test_person_service,test_country_service,test_continent_service}.py | New unit tests covering service success, not-found, and transaction interactions. |
| tests/unit_tests/repositories/test_base.py | Reference SQL updated to include now-undeferred country_code / continent_code columns. |
| tests/api_tests/test_e2e.py | Replaces SQLite-FK-permissive test with one asserting 404 from the service-layer validation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Introduced a dedicated service layer to the
pyfastapiproject to separate business logic from the HTTP layer and repository data access. This change includes refactoring transaction management, standardized error handling, and adding comprehensive unit tests for the new service components.Why?
Previously, controllers were directly interacting with repositories and handling business logic, entity construction, and transaction commits. This made the code difficult to reuse, hard to test in isolation, and prone to data inconsistency if a workflow spanned multiple repositories.
How?
pyfastapi/services/withPersonService,CountryService, andContinentService. These services now orchestrate repository calls and manage domain rules.db.commit()anddb.refresh()calls from repositories to the service layer, allowing for future atomic operations across multiple repositories.pyfastapi/libs/exceptions.py(e.g.,PersonNotFoundError,CountryNotFoundError).pyfastapi/main.pyforDomainErrorto return clean, standardized JSON responses.pyfastapi/controllers/to delegate all business logic to the services.Listtypes) and removed unnecessarydeferred()loading on foreign key columns to prevent N+1 query issues during serialization.Testing?
tests/unit_tests/services/usingunittest.mockto verify service logic in isolation.tests/api_tests/to ensure end-to-end functionality remains intact.poe lint(flake8 + mypy --strict).Screenshots (optional)
N/A
Anything Else?
The next suggested steps involve implementing transactional rollbacks for tests to improve performance.
AI Summary (optional)
Refactored the core architecture to include a Service Layer, improving separation of concerns and transaction boundaries. Centralized error handling via domain exceptions and added comprehensive unit tests for business logic.