Repository navigation
Description
Hi, maintainers.
Context
I'm working on an API that involves file extraction. The system architecture includes several layers:
FileExtractionControllerFileExtractionServiceFileExtractor(an internal engine)
Current Implementation
The FileExtractor class is instantiated within the FileExtractionService without dependency injection. However, FileExtractor requires a repository implementation to be passed in its constructor.
Problem Statement
I want to inject dependencies that my API uses indirectly, specifically for the FileExtractor class. The challenge is to avoid passing these dependencies through each layer (Controller -> Service -> FileExtractor).
Desired Solution
Implement a mechanism to auto-inject the required dependency (repository) into the FileExtractor object without explicitly passing it through intermediary layers.
Current Code Structure
class FileExtractor(CPrototype):
"""
Abstract class for extracting content from files.
This should be used as a base class for specific file extractors.
"""
file: Annotated[
UploadFile, Meta(title="File", description="The file to extract content from")
]
repository: Annotated[
Optional[FileExtAPIKeyRepository],
Meta(
title="API Key Repository",
description="Repository for storing API keys that may be used by external services for the file extraction process",
),
] # Note: I will move this to subclasses that needs a repository, placed here because it's easy to understand
@classmethod
def from_file(cls, file: UploadFile) -> FileExtractor:
"""Factory method to create a FileExtractor from a file."""
return cls(file=file)
async def extract_contents(self) -> ExtractedFile:
"""Extracts content from the file."""
raise NotImplementedError("This method should be implemented by subclasses.")Additional Notes
- The
FileExtractorclass is not directly related to the API; it's an internal component for file content extraction. - The API needs to pass certain dependencies to this class.
- I'm uncertain about the correct placement of the
@injectdecorator (class level or method level).
Questions
- How can I implement dependency injection for the
repositoryin theFileExtractorclass without modifying the entire object creation chain? - Are there best practices or design patterns for handling dependency injection in deeply nested object structures?
- What are the implications of using dependency injection at different levels (class vs. method) in this context?
Any insights or code examples demonstrating a clean, maintainable solution would be greatly appreciated. I didn't find this kind of thing in the documentation, only things I've found is an @Inject decorator, but all of these decorators are located in the integrations module.. Do I have to call container.get everywhere I need it? Having to import it everywhere I need it
Activity
Tishka17 commentedon Aug 30, 2024
As for now, I can suggest reading this: https://dishka.readthedocs.io/en/stable/di_intro.html
I'llt think about your question later and maybe add more details
arthurbrenno commentedon Aug 30, 2024
Okay. Thanks.
Tishka17 commentedon Sep 3, 2024
FileExtractorhere depends on the file it is called with. So, probably, have an Abstract Factory is a good idea. I do not see you logic of creating extractors, so I suppose that you might want to have several of them in one service. It would be something likeThat
FileExtractorFactoryimplementation will know how to create concreteFileExtractor, passing all necessary objects like repositories. So, they will be its' dependencies.So, you have classes like
FileExtractionService,FileExtractorFactory,Repositryand maybe some others. They have clear lifespan like REQUEST-scope, so all of them can be moved to dishka container.