Skip to content

Flatten API module structure, add session management, consolidate DI#7451

Open
galvana wants to merge 17 commits intomainfrom
flatten-api-structure
Open

Flatten API module structure, add session management, consolidate DI#7451
galvana wants to merge 17 commits intomainfrom
flatten-api-structure

Conversation

@galvana
Copy link
Contributor

@galvana galvana commented Feb 22, 2026

Summary

Structural refactoring to flatten the nested api/api/ package, introduce shared session management infrastructure in common/session, consolidate dependency injection, and break a circular import cycle.

API module flatten

  • Move api/api/deps.pyapi/deps.py and api/api/v1/api/v1/, eliminating the redundant nested api/ package
  • Update all imports across src/ and tests/

Session management (common/session)

  • Create common/session/session_management.py as the canonical owner of:
    • get_api_session() — engine singleton + session factory (moved from deps.py)
    • get_autoclose_db_session() — context-managed session lifecycle
    • @with_optional_sync_session / @with_optional_async_session — composable transaction-boundary decorators (ported from the fidesplus v3 layer)
  • Migrate all consumers (graph_task, saas_connector, sql_connector, middleware, identity_salt, memory_watchdog, hash_migration_job, encrypted_large_data, connector_registry_service, app_setup) to import session utilities from fides.common.session instead of fides.api.deps
  • Break the circular import between deps.pyprivacy_request_service.py by having the service import from common.session

DI consolidation

  • Consolidate service factory functions from api/service/deps.py into api/deps.py as the single canonical DI location
  • api/service/deps.py remains as a re-export shim for backward compatibility
  • Promote all service imports to top-level (no TYPE_CHECKING block or deferred in-body imports)

Break circular import cycle

  • Extract get_messaging_config_status() and is_email_invite_enabled() business logic from messaging_endpoints.py route handlers into MessagingService
  • Thin route handlers to delegate to MessagingService via Depends(get_messaging_service)
  • Compose MessagingService into UserService (injected via get_user_service factory) to replace the service→route import of user_email_invite_status
  • This breaks the deps.pyUserServicemessaging_endpointsdeps.py cycle

Code Changes

  • Moved/renamed api/api/deps.pyapi/deps.py and api/api/v1/api/v1/ (46 endpoint files)
  • Added common/session/session_management.py (~127 lines) with engine singleton, session factory, and transaction decorators
  • Moved get_api_session + engine singleton from deps.py to common/session (single connection pool)
  • Migrated 10 source files from fides.api.depsfides.common.session for session imports
  • Extracted messaging config status logic into MessagingService.get_messaging_config_status() and is_email_invite_enabled()
  • Composed MessagingService into UserService to eliminate service→route import
  • Updated imports across ~77 source and test files

Steps to Confirm

  1. nox -s static_checks passes
  2. nox -s pytest — all existing tests pass
  3. Verify fidesplus companion PR [fidesplus#807] adds fides_user_device_id to ProvidedIdentityType Enum #3131 imports align

Pre-Merge Checklist

  • All CI pipelines succeeded
  • CHANGELOG.md updated
  • No UX review needed
  • No database migrations
  • No documentation updates required

@vercel
Copy link
Contributor

vercel bot commented Feb 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
fides-plus-nightly Ignored Ignored Preview Feb 28, 2026 1:39am
fides-privacy-center Ignored Ignored Feb 28, 2026 1:39am

Request Review

@galvana galvana changed the title Flatten api/api/, add session management, domain exceptions, consolid… Flatten API module structure, add session management, consolidate DI Feb 22, 2026
@galvana galvana marked this pull request as ready for review February 25, 2026 16:13
@galvana galvana requested a review from a team as a code owner February 25, 2026 16:13
@galvana galvana requested review from adamsachs and removed request for a team February 25, 2026 16:13
@galvana galvana requested a review from a team as a code owner February 25, 2026 16:16
@galvana galvana requested review from gilluminate and removed request for a team and gilluminate February 25, 2026 16:16
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 25, 2026

Greptile Summary

This PR performs a structural refactoring of the Fides API module layout, session management, and dependency injection:

  • Flattens the nested api/api/ package to api/, eliminating the redundant directory layer and updating all import paths across ~77 source and test files
  • Introduces common/session/session_management.py as the canonical location for the database engine singleton, get_api_session(), get_autoclose_db_session(), and two composable transaction-boundary decorators (with_optional_sync_session, with_optional_async_session)
  • Consolidates DI by merging service factory functions from api/service/deps.py into api/deps.py, with the former retained as a re-export shim
  • Breaks a circular import cycle (deps.pyUserServicemessaging_endpointsdeps.py) by extracting get_messaging_config_status() and is_email_invite_enabled() into MessagingService and composing MessagingService into UserService via DI

The refactoring is largely mechanical (import path updates) with focused architectural changes in the service and session layers. One test mock target (test_memory_watchdog.py:74) was not updated to match the new import path, which will cause the mock to silently fail to intercept the actual call.

This PR changes 78 files, which exceeds the recommended 15-file limit for a single PR. While this is understandable given the nature of a structural refactoring (most changes are mechanical import updates), it does make review more difficult.

Confidence Score: 4/5

  • This PR is a well-executed structural refactoring with one test bug — safe to merge after the mock target fix.
  • The vast majority of changes are mechanical import path updates from the package flatten. The architectural changes (session extraction, DI consolidation, circular import break) are well-designed and faithful to the original logic. One test mock target mismatch was found that needs fixing. No production logic bugs identified.
  • Pay close attention to tests/ops/util/test_memory_watchdog.py — the mock target at line 74 does not match the actual import path used in the code under test.

Important Files Changed

Filename Overview
src/fides/common/session/session_management.py New module providing session management utilities (engine singleton, autoclose session context manager, and optional session decorators). Well-structured with clear docstrings. The decorators properly handle session lifecycle — committing owned sessions and flushing borrowed ones.
src/fides/api/deps.py Consolidated DI module combining session utilities (re-exported from common.session) and service factory functions (moved from service/deps.py). Clean structure with explicit re-exports and clear organization.
src/fides/api/service/deps.py Converted to a re-export shim pointing to the canonical fides.api.deps module. Maintains backward compatibility for any existing consumers.
src/fides/service/messaging/messaging_service.py Business logic for get_messaging_config_status() and is_email_invite_enabled() extracted from route handlers into the service layer. Logic is preserved faithfully from the original endpoints.
src/fides/service/user/user_service.py Constructor updated to accept MessagingService as a dependency, replacing the direct import from messaging_endpoints. Cleanly breaks the circular import cycle.
src/fides/service/privacy_request/privacy_request_service.py Replaced inline deferred imports (from fides.api.api.deps import ...) with a top-level import from fides.common.session, eliminating the circular import workaround.
src/fides/api/v1/endpoints/messaging_endpoints.py Route handlers thinned to delegate to MessagingService for config status and email invite checks. get_messaging_status and user_email_invite_status now use DI properly. Import paths updated for the flattened structure.
tests/ops/util/test_memory_watchdog.py Mock target at line 74 patches fides.api.deps.get_autoclose_db_session but the actual code imports from fides.common.session — the mock will not intercept the call, causing the test to pass for the wrong reason.

Last reviewed commit: 41499ac

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

78 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@erosselli erosselli self-requested a review February 26, 2026 13:16
Comment on lines +1 to +15
"""
Re-export shim -- canonical location is fides.api.deps.
"""

from fides.api.deps import ( # noqa: F401
get_connection_service,
get_dataset_config_service,
get_dataset_service,
get_event_audit_service,
get_messaging_service,
get_privacy_request_service,
get_system_service,
get_taxonomy_service,
get_user_service,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

are we moving these in a follow up PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, just added this temporarily

Copy link
Contributor

Choose a reason for hiding this comment

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

didn't Adam also add this file in his PR?

Base automatically changed from ENG-2213-remove-dsr-2.0-code to main February 26, 2026 23:31
@github-actions github-actions bot requested a review from a team as a code owner February 26, 2026 23:31
@github-actions github-actions bot requested review from eastandwestwind and removed request for a team February 26, 2026 23:31
Copy link
Contributor

@erosselli erosselli left a comment

Choose a reason for hiding this comment

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

Approving with a comment

Copy link
Contributor

Choose a reason for hiding this comment

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

I now see two new files src/fides/common/session/session_management.py and src/fides/common/session_management.py -- but this file should already be added by Adam's PR , can you check to make sure the merge was handled ok? :)

Adrian Galvan and others added 10 commits February 27, 2026 17:01
…ate deps

- Flatten api/api/ into api/ (move deps.py and v1/ up one level)
- Create common/session/session_management.py with composable
  transaction boundary decorators (ported from fidesplus v3)
- Add service/exceptions.py with base domain exception hierarchy
- Consolidate service factory functions from api/service/deps.py
  into api/deps.py as the single canonical DI location
- Convert api/service/deps.py to a re-export shim
- Update all imports across src/ and tests/

Co-authored-by: Cursor <cursoragent@cursor.com>
DSR 3.0 is now the only execution path. This removes the deprecated
DSR 2.0 sequential/Dask-based execution model including:

- deprecated_graph_task.py and scheduler_utils.py modules
- Redis caching methods from TaskResources
- DSR 2.0 fallback paths in privacy_request model methods
- to_mock_execution_node() from traversal.py
- use_dsr_2_0 test fixture and all DSR version parameterization
- Deleted test files: test_deprecated_graph_task, test_task_resources,
  test_dsr_3_0_default

Moved format_data_use_map_for_caching() to create_request_tasks.py
as it is still used by DSR 3.0.

Co-authored-by: Cursor <cursoragent@cursor.com>
DSR 3.0 is the only execution path. Remove all dsr_version/use_dsr_3_0
test parameterization, conditional DSR version logic, and the no-op
use_dsr_3_0 fixture and config setting across 44 files.

Co-authored-by: Cursor <cursoragent@cursor.com>
service/exceptions.py was added but never imported anywhere — removing
to keep the PR focused on the structural refactoring.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Move get_api_session + engine singleton and get_autoclose_db_session
  from deps.py to common/session/session_management.py
- Migrate all consumers to import from fides.common.session
- Remove TYPE_CHECKING block and deferred imports from deps.py;
  promote service imports to top-level
- Remove unused domain exceptions module
- Break circular import between deps.py and privacy_request_service.py

Co-authored-by: Cursor <cursoragent@cursor.com>
Extract messaging config status logic into MessagingService, compose
MessagingService into UserService to eliminate service-to-route import,
and promote all service imports to top-level in deps.py.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use the 'import X as X' pattern so mypy recognizes these as
explicit re-exports from fides.api.deps.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Eliana Rosselli <67162025+erosselli@users.noreply.github.com>
@galvana galvana force-pushed the flatten-api-structure branch from 09f6ccf to b6baf7c Compare February 28, 2026 01:09
Copy link
Contributor

@adamsachs adamsachs left a comment

Choose a reason for hiding this comment

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

👍 generally looks good to me, thanks for continuing to push this forward!

only one question really, i'm not sure i agree with the DI consolidation - not that this is worse than before, but i just think another approach may be better, if we're updating that anyway? maybe i'm not thinking about it correctly though, open to hear a different POV or continue to iterate as needed.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK - so common will be like lib/shared utils, i think that's probably better...and core will be for core 'features', e.g. Systems, etc? or do we want to get rid of core?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm treating common as shared utils (session management, encryption, constants, etc). I think core originally referred to the actions that could be taken by fidesctl through the CLI. Not sure if core is a concept that we want to apply any meaning to now. Fides will just have a base set of "domains" (privacy requests, systems, datasets) but I'm deferring the decision as to what is considered core functionality.

Comment on lines +79 to +81
# ---------------------------------------------------------------------------
# Service factory functions for FastAPI dependency injection.
# ---------------------------------------------------------------------------
Copy link
Contributor

Choose a reason for hiding this comment

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

you think this is better here, rather than a deps.py module within each 'feature'/service package?

i feel like coupling them all together in a single module here gives us this central deps.py module with a huge dependency tree, and that doesn't seem great. whereas each 'feature' exposing its own deps.py allows those dependencies to be pulled in selectively by the endpoints that need them.

Copy link
Contributor Author

@galvana galvana Feb 28, 2026

Choose a reason for hiding this comment

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

I agree that this file could get huge, but I also think that Depends is an API-layer concern. I've been thinking about keeping the routes under a root-level api directory along cli. These are just two different ways that we expose features/services. Something like this:

api -> deps -> services
cli -> services

We can chat about this more.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think I tend to agree with Adam about having module-level deps. Even though they're an API-layer concern, the api endpoints themselves are also going to be defined within each module right?

lmk if you're meeting to chat about this, can I join?

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.

3 participants