2

If you are application depends on some objects that needs to be initialized at startup, what's the point of using Depends mechanism to pass them to every route rather than create a global dict at startup?

If the goal of the Depends strategy is to reduce repetitive code then why don't you just write your functions and call them the canonical way when you need them?

I feel like the claimed "Dependency Injection" on the FastAPI documentation is just calling callables and from my point of view the real dependency injection (like Spring for example) can be achievable though the use of global dicts as beans.

I feel like that this type of DI works for stateless classes/callables.

Antonio Santoro
  • 827
  • 1
  • 11
  • 29
  • While this is not really a question and rather opinionated, FastAPIs `Depends` provides a lot of logic behind the scenes - such as caching, isolation, handling async methods, hierarchical dependencies, etc. It allows you to register dependencies globally, for subroutes in your tree, as combinations, etc. You can also use `yield` to have clean-up code for a dependency after it's no longer needed. Of course you can implement DI in different ways, sure you can create the same application with true global state and without any DI at all. It's not about this being the only true way to do something. – MatsLindh Aug 06 '21 at 11:27
  • if you need to initialize stateful objects that needs to used across all routes, you can't use Depends because it will call the dependency every time causing the objects to lose their state. How caching can help in this case? – Antonio Santoro Aug 06 '21 at 11:34
  • Caching refers to the dependency only being evaluated once across a request, even if the dependency is referenced multiple times (for example, having multiple dependencies require the user object). If you have large, heavy objects that are expensive to initialize and doesn't depend on the current request context, initializing them in a `Depends`-call might not be what you want to do. However, you can then depend on a callable that hides where you're retrieving that object from, i.e. you have determined that it can be shared across sessions and kept in "global" (per worker) memory. – MatsLindh Aug 06 '21 at 12:31
  • Having specific cases where per-request initialization might not be what you want doesn't invalidate the rest of the dependency architecture that FastAPI uses. – MatsLindh Aug 06 '21 at 12:32
  • My statements were for large stateful objects – Antonio Santoro Aug 06 '21 at 12:35
  • Then you do `Depends(get_my_large_stateful_object_w_configuration)` and let that callable retrieve and do any per request configuration to the object (for example doing specific stuff for the current user or other things you could depend on). That doesn't go against the dependency injection method, however - it's outside of that; you can implement that method in any way you want, and if you have the option to keep it stateful in some other part of memory and return it - great! Do that through your callable. The code then becomes readable and everything is "right there". – MatsLindh Aug 06 '21 at 12:38
  • Maybe I'm misunderstanding something but returning the large objects through a Depends callable invalidates the state of the object thus you need to keep it global, at this point you can invoke it without using Depends. My use-case implies that the large objects is needed to be have the same state for all requests because initializing it costs resources and memory, so my original question. – Antonio Santoro Aug 06 '21 at 13:37
  • No, it does not invalidate the state of the object. It depends on what your callable does. It's free to return an object from shared memory, from global state, serialized from disk, whatever suits your need. The point is that you avoid explicit global state, and your view function will only depend on the callable to do what's right (so if how you return that object changes in the future, that doesn't change your views/other parts of the dependency chain). It'll be clear what provides the object and which dependencies are required `def foo(large_object = Depends(get_large_object))` – MatsLindh Aug 06 '21 at 15:30
  • Of course you can still just use a global object directly as well if you want to, but that can be said with any abstraction in programming. It helps abstract away how the object is retrieved and how it is being stored - i.e. how the dependency should be resolved. Also be aware that any global state will be created once for each worker - so if you have multiple workers (which you usually have), any global state will be created x amount of times (and uses x amount of memory, etc.). This can be an issue for ML models. – MatsLindh Aug 06 '21 at 15:32
  • What if my large object need to be created using command line arguments? The `get_large_object` approach doesn't work for me because, once the large object is created inside a function at startup, I cannot use Depends on that function because that would cause the object to be instantiated again thus losing its state. I don't like the global approach but I feel having no alternatives. Please correct me if I'm wrong. – Antonio Santoro Aug 06 '21 at 16:31
  • By global I mean declare/init in the global scope so accessible outside functions or via import from other modules – Antonio Santoro Aug 06 '21 at 16:49
  • @MatsLindh I created a new [question](https://stackoverflow.com/questions/68685288/fastapi-depends-use-case-application) to explain my use case – Antonio Santoro Aug 06 '21 at 17:11

0 Answers0