Skip to content

add service layer - #28

Merged
heinrich10 merged 2 commits into
mainfrom
feat/services_layer
May 31, 2026
Merged

add service layer#28
heinrich10 merged 2 commits into
mainfrom
feat/services_layer

Conversation

@heinrich10

@heinrich10 heinrich10 commented May 31, 2026

Copy link
Copy Markdown
Owner

What?

Introduced a dedicated service layer to the pyfastapi project 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?

  • Service Layer: Created pyfastapi/services/ with PersonService, CountryService, and ContinentService. These services now orchestrate repository calls and manage domain rules.
  • Transaction Management: Moved db.commit() and db.refresh() calls from repositories to the service layer, allowing for future atomic operations across multiple repositories.
  • Error Handling:
    • Defined custom domain exceptions in pyfastapi/libs/exceptions.py (e.g., PersonNotFoundError, CountryNotFoundError).
    • Implemented a global exception handler in pyfastapi/main.py for DomainError to return clean, standardized JSON responses.
  • Controller Refactor: Updated controllers in pyfastapi/controllers/ to delegate all business logic to the services.
  • Model Improvements: Fixed type hints for relationships (plural naming and List types) and removed unnecessary deferred() loading on foreign key columns to prevent N+1 query issues during serialization.

Testing?

  • Unit Tests: Added 13 new unit tests in tests/unit_tests/services/ using unittest.mock to verify service logic in isolation.
  • Integration Tests: Updated and verified all 52 existing integration tests in tests/api_tests/ to ensure end-to-end functionality remains intact.
  • Linting: Ensured all new code passes poe lint (flake8 + mypy --strict).
  • Total Suite: All 65 tests passed successfully.

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.

@github-actions

github-actions Bot commented May 31, 2026

Copy link
Copy Markdown

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
1169 1150 98% 0% 🟢

New Files

File Coverage Status
pyfastapi/libs/exceptions.py 100% 🟢
pyfastapi/services/init.py 100% 🟢
pyfastapi/services/continent.py 100% 🟢
pyfastapi/services/country.py 100% 🟢
pyfastapi/services/person.py 100% 🟢
tests/unit_tests/services/init.py 100% 🟢
tests/unit_tests/services/test_continent_service.py 100% 🟢
tests/unit_tests/services/test_country_service.py 100% 🟢
tests/unit_tests/services/test_person_service.py 100% 🟢
TOTAL 100% 🟢

Modified Files

File Coverage Status
pyfastapi/controllers/continent.py 100% 🟢
pyfastapi/controllers/country.py 100% 🟢
pyfastapi/controllers/person.py 100% 🟢
pyfastapi/main.py 100% 🟢
pyfastapi/models/continent.py 85% 🟢
pyfastapi/models/country.py 86% 🟢
pyfastapi/models/person.py 87% 🟢
pyfastapi/repositories/person.py 100% 🟢
tests/api_tests/test_e2e.py 100% 🟢
tests/unit_tests/repositories/test_base.py 100% 🟢
TOTAL 96% 🟢

updated for commit: ef039a8 by action🐍

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 plus pyfastapi/libs/exceptions.py domain errors and a global handler in main.py.
  • Repositories no longer commit; commits/refreshes moved to services. Controllers stripped of HTTPException/try/traceback boilerplate.
  • Model relationships pluralized (persons, countries), FK columns no longer deferred(); 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.

Comment thread pyfastapi/repositories/person.py
@heinrich10
heinrich10 merged commit 96256d6 into main May 31, 2026
1 check passed
@heinrich10
heinrich10 deleted the feat/services_layer branch May 31, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants