Service locator
Features register replaceable service classes on app.splent_services. Routes look up the current implementation at request time — after all features (including refiners) have loaded.
Table of contents
Base feature registers
# splent_feature_notes/__init__.py
from splent_framework.services.service_locator import register_service
from .services import NotesService
def init_feature(app):
register_service(app, "NotesService", NotesService)
Routes consume via proxy
# splent_feature_notes/routes.py
from splent_framework.services.service_locator import service_proxy
notes_service = service_proxy("NotesService")
@notes_bp.route("/notes/", methods=["GET"])
@login_required
def index():
notes = notes_service.get_by_user(current_user.id)
...
service_proxy resolves the registered class at request time. Same pattern Flask uses with current_app.
Never import the service class directly in routes (
from .services import NotesService). Direct imports create the instance at module load, before refiners have registered overrides. Useservice_proxy()instead.
Refiner overrides
# splent_feature_notes_tags/__init__.py
from splent_framework.refinement import refine_service
from .services import NotesServiceWithTags
def init_feature(app):
refine_service(app, "NotesService", NotesServiceWithTags)
refine_service builds a merged class inheriting from both NotesServiceWithTags and NotesService, so super() works correctly. Routes using service_proxy("NotesService") automatically get the merged class.
See also
- Services — the service layer architecture
- Refinement — the full override mechanism