Becker
Becker ์˜ TIL
Becker
  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (30)
    • Computer Science (15)
      • Python (7)
      • Java (1)
      • Algorithm (0)
      • Database (3)
      • Network (1)
      • Openstack (2)
      • ETC (1)
    • ์ž๋™ํ™” (3)
      • Github Action (1)
      • Airflow (0)
      • Docker (2)
    • ๋…ผ๋ฌธ ๋ฆฌ๋ทฐ (1)
    • ์„œํ‰ (3)
    • ๋„์ ๋„์  (8)
์ „์ฒด ๋ฐฉ๋ฌธ์ž
์˜ค๋Š˜
์–ด์ œ

์ธ๊ธฐ ๊ธ€

ํ‹ฐ์Šคํ† ๋ฆฌ

hELLO ยท Designed By ์ •์ƒ์šฐ.
Becker

Becker ์˜ TIL

[Python] FastAPI์™€ Dependency Injector
Computer Science/Python

[Python] FastAPI์™€ Dependency Injector

2024. 10. 27. 22:17

๐Ÿš€ ๋“ค์–ด๊ฐ€๋ฉฐ

์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์„ค๊ณ„ํ•˜๋‹ค๋ณด๋ฉด DI ํŒจํ„ด์„ ์ ์šฉํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ ์žˆ์Šต๋‹ˆ๋‹ค. python ๊ธฐ์ค€์œผ๋กœ ๊ฐ์ฒด์˜ ์˜์กด์„ฑ ์ฃผ์ž…์€ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, Python์—์„œ DI ํŒจํ„ด์„ ํ”„๋ ˆ์ž„์›Œํฌ ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ํ•œ Dependency Injector ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ ์ฃผ์ž…๊ณผ ์ œ์–ด์˜ ์—ญ์ „(IoC)๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” FastAPI์™€ Dependency Injector๋ฅผ ํ™œ์šฉํ•ด Layered ์•„ํ‚คํƒ์ฒ˜๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๐Ÿ” ์˜์กด์„ฑ ์ฃผ์ž…์— ๋Œ€ํ•œ ๊ฐ„๋‹จ ์„ค๋ช…

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ ์˜์กด์„ฑ ์ฃผ์ž…์— ๋Œ€ํ•œ ๊ฐœ๋…์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜์ง€ ์•Š์ง€๋งŒ, ๊ฐ„๋‹จํžˆ ์งš๊ณ  ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค. DI, IoC, DIP์™€ ๊ฐ™์€ ๊ฐœ๋…์€ Spring๊ณผ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ฑฐ๋‚˜, ๊ฐ์ฒด ์ง€ํ–ฅ ์„ค๊ณ„์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•˜์…จ๋‹ค๋ฉด ๋งŽ์ด ๋“ค์–ด๋ดค์„ ๋‚ด์šฉ์ผ ๊ฒ๋‹ˆ๋‹ค.

์˜์กด์„ฑ ์ฃผ์ž…์ด๋ž€ ๋ง ๊ทธ๋Œ€๋กœ ํŠน์ • ๊ฐ์ฒด(A)์—์„œ ํ•„์š”ํ•œ ๊ฐ์ฒด(B)๋ฅผ A์—์„œ ํด๋ž˜์Šค๋ฅผ import ํ•ด์„œ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹Œ, A๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด B๊ฐ์ฒด๋ฅผ ์ „๋‹ฌ(์ฃผ์ž…)ํ•ด์ฃผ๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. 

IoC ์ฆ‰ ์˜์กด ์ œ์–ด ์—ญ์ „์˜ ์›์น™์€ ์ด๋Ÿฌํ•œ ์˜์กด์„ฑ์„ ๊ด€๋ฆฌ์™€ ํ๋ฆ„ ์ œ์–ด๋ฅผ A๊ฐ์ฒด, B๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ์ œ 3์˜ ๋ฐฉ์‹(์˜์กด ์ œ์–ด ์ปจํ…Œ์ด๋„ˆ, ํ”„๋ ˆ์ž„์›Œํฌ ๋“ฑ)์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ์Šคํ”„๋ง์—์„œ๋Š” Bean ์ปจํ…Œ์ด๋„ˆ๊ฐ€, ๊ทธ๋ฆฌ๊ณ  python Dependency Injector์—์„œ Container๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ์˜์กด ์ œ์–ด ์—ญ์ „ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


 ๐Ÿ“ฆ Dependency Injector ์†Œ๊ฐœ

Dependency Injector๋Š” python ์ƒํƒœ๊ณ„์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” DI ํ”„๋ ˆ์ž„์›Œํฌ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. DI ํŒจํ„ด์„ ์œ„ํ•œ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ธ IoC ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ๋ฌธ์„œ๋ฅผ ํ†ตํ•ด ์œ ์ฆˆ์ผ€์ด์Šค์— ๋Œ€ํ•œ ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋งŽ์€ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ๋˜์–ด ์•ˆ์ •์„ฑ์ด ๊ฒ€์ฆ๋˜์—ˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 ๐Ÿ“š ์ฃผ์š” ๊ฐœ๋…

Providers: ์ฃผ์ž…ํ•  ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•  ๋ฐฉ๋ฒ•(Singleton, Factory, Callable, Object...)๋“ฑ ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด Singleton์œผ๋กœ ์ •์˜๋œ Provider๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ปจํ…Œ์ด๋„ˆ์— ์ •์˜๋œ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ์ฒด๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ช… Factory๋กœ ์ •์˜๋˜์—ˆ๋‹ค๋ฉด, ์ฃผ์ž…๋œ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

Containers : ์˜์กด์„ฑ์ด ์ •์˜๋œ Provider์˜ ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค. Container๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋“ค์˜ ์˜์กด์„ฑ์„ ๋ช…์‹œ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์˜์กด์„ฑ ์ฃผ์ž…์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์—์„œ Container๋ฅผ ํ†ตํ•ด Provider ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•ด์„œ ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Wiring: ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. Provider๋ฅผ ํ†ตํ•ด ๋ช…์‹œ๋œ ์ฃผ์ž…๋ฐฉ์‹์œผ๋กœ, ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•  Class์˜ ์œ„์น˜๋ฅผ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.

 

 

๐Ÿ”ง ์˜ˆ์‹œ ์ฝ”๋“œ

๊ฐ€๋ น ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค๊ฐ„ ๊ด€๊ณ„๊ฐ€ ์žˆ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ, Dependency Injector๋ฅผ ์‚ฌ์šฉํ•ด ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์˜ˆ์‹œ๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
๊ฐ„๋‹จํ•œ ๋ธ”๋กœ๊ทธ์˜ ๊ธ€์„ ํฌ์ŠคํŒ…ํ•˜๋Š” ํด๋ž˜์Šค์˜ ์˜์กด๊ด€๊ณ„๋ฅผ ๊ทธ๋ ค๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 


BlogService ํด๋ž˜์Šค๋Š” PostRepository์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด ํฌ์ŠคํŒ…์„ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋จผ์ € BlogService ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณผ๊นŒ์š”?

class BlogService: 
    def __init__(self, repository: PostRepository): 
    	self._repository = repository 

    def create_post(self, title, content): 
    	post = Post(title, content)
    	self._repository.add_post(post) 

    def get_posts(self): 
    	return self._repository.list_posts()


BlogService์—์„œ๋Š” Post์˜ ์˜์†์„ฑ์„ ๊ด€๋ฆฌํ•˜๋Š” Repository๋ฅผ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋ฐ›์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น repository ์†์„ฑ์„ ์‚ฌ์šฉํ•ด์„œ post๋ฅผ ์ƒ์„ฑ(create_post), ์กฐํšŒ(get_posts) ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.


PostRepository ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด

class PostRepository: 
    def __init__(self): 
    	self._posts = [] 

    def add_post(self, post): 
    	self._posts.append(post) 

    def list_posts(self): 
    	return self._posts


๊ฐ„๋‹จํ•˜๊ฒŒ listํ˜•ํƒœ๋กœ Post๋ฅผ ๋„˜๊ฒจ๋ฐ›๊ณ  ๊ด€๋ฆฌํ•˜๋Š” repository์ž…๋‹ˆ๋‹ค. add_post๋ฅผ ํ†ตํ•ด _post๋ณ€์ˆ˜์— ์— Post ์ธ์Šคํ„ด์Šค๋ฅผ ์ €์žฅํ•˜๊ณ  list_posts ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

์œ„ ๋‘ ํ•จ์ˆ˜์˜ ์˜์กด๊ด€๊ณ„๋ฅผ Container์— ๋ช…์‹œํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

from dependency_injector import containers, providers

class Container(containers.DeclarativeContainer): 
    post_repository = providers.Singleton(PostRepository) 
    blog_service = providers.Factory(BlogService, repository=post_repository)

 


post_repository๋ฅผ Signleton์œผ๋กœ ์ •์˜ํ–ˆ๊ณ , blog_service์— ์ฃผ์ž…์‹œ์ผœ ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. blog_service๋Š” Factory๋กœ ์ •์˜๋˜์–ด์žˆ์œผ๋‹ˆ Provicer๋ฅผ ํ†ตํ•ด ๋งค๋ฒˆ ๋‹ค๋ฅธ blog_service ์ธ์Šคํ„ด์Šค๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜์กด๊ด€๊ณ„๋ฅผ ๋ช…์‹œํ–ˆ์œผ๋‹ˆ container๋ฅผ ํ†ตํ•ด blog_service๋ฅผ ์ฃผ์ž…ํ•ด๋ณผ๊นŒ์š”? 

 

main ํ•จ์ˆ˜์—์„œ ํ•ด๋‹น ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject

class Container(containers.DeclarativeContainer):
    post_repository = providers.Singleton(PostRepository) 
    blog_service = providers.Factory(BlogService, repository=post_repository)

@inject
def main(blog_service: BlogService = Provide[Container.service]) -> None:
    blog_service.creade_post(Post("์ œ๋ชฉ", "๋‚ด์šฉ"))
    print(blog_service.get_posts()) # Post(์ œ๋ชฉ, ๋‚ด์šฉ)

if __name__ == "__main__":
    container = Container()
    container.wire(modules=[__name__])

    main()


main ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ blog_service๋ฅผ ์ฃผ์ž…ํ•ด ์คฌ์Šต๋‹ˆ๋‹ค. @inject ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฃผ์ž…์ด ๋  main ํ•จ์ˆ˜์˜ ์œ„์น˜๋ฅผ ๋ช…์‹œํ•ด์ฃผ์—ˆ๊ณ , container์—์„œ๋Š” inject๋  ๋ชจ๋“ˆ์˜ ์œ„์น˜๋ฅผ ๋ช…์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.(@inject ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์—†์–ด๋„ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.)

 

์œ„์ฒ˜๋Ÿผ main ํ•จ์ˆ˜์—์„œ ์ธ์ž๋ฅผ Provide ๋””์ŠคํŒจ์ฒ˜๋ฅผ ํ†ตํ•ด ์ฃผ์ž…ํ•ด์ค€๋‹ค๋ฉด, main ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ธ์ž๋กœ blog_service๋ฅผ ๋„˜๊ฒจ์ฃผ์ง€ ์•Š์•„๋„ Provider๊ฐ€ ์ ์ ˆํ•œ blog_service ์ธ์Šคํ„ด์Šค๋ฅผ ์ฃผ์ž…์‹œ์ผœ ์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


๐ŸŒ FastAPI์™€ ์˜์กด์„ฑ ์ฃผ์ž…

FastAPI๋Š” ์ž์ฒด์ ์ธ ์˜์กด์„ฑ ์ฃผ์ž… ๋””์ŠคํŒจ์ฒ˜์ธ Depends๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Depends๋ฅผ ํ†ตํ•ด ์˜์กด๊ด€๊ณ„์— ์žˆ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ฃผ์ž…ํ•˜๊ฑฐ๋‚˜ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ์‹์„ ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ FastAPI์—์„œ Depends๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


์œ„์—์„œ ์‚ฌ์šฉํ•œ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŒ… ์˜ˆ์ œ๋ฅผ FastAPI์˜ Routerํ•จ์ˆ˜์—์„œ BlogService์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์‹œ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

from fastapi import FastAPI, Depends

app = FastAPI()

# ์˜์กด์„ฑ์„ ์ •์˜ํ•˜๋Š” ํ•จ์ˆ˜
def get_post_repository():
    return PostRepository()

def get_blog_service(repository: PostRepository = Depends(get_post_repository)):
    return BlogService(repository)

# ๋ผ์šฐํŠธ ์˜ˆ์‹œ
@app.get("/posts")
def list_blog_posts(blog_service: BlogService = Depends(get_blog_service)):
    return blog_service.list_posts()

@app.post("/posts")
def create_blog_post(post_data: dict, blog_service: BlogService = Depends(get_blog_service)):
    blog_service.add_post(post_data)


FastAPI์˜ ๋ผ์šฐํ„ฐ ํ•จ์ˆ˜์— Depends๋ฅผ ์‚ฌ์šฉํ•ด get_blog_service ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ์ธ์ž์˜ ๋””์ŠคํŒจ์ฒ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. 

get_blog_service ํ•จ์ˆ˜์—์„œ๋Š” BlogService๋ฅผ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ธ์ž์—์„œ๋Š” get_post_repository๋ฅผ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค. ์ธ์ž๋ฅผ ํ†ตํ•ด ๋„˜๊ฒจ๋ฐ›์€ PostRepository์˜ ๊ฐ์ฒด๋ฅผ BlogService์˜ ์ƒ์„ฑ์ž๋กœ ๋„˜๊ฒจ์ฃผ๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

์ด์ฒ˜๋Ÿผ FastAPI์˜ Depends ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, Depends ๋งŒ์œผ๋กœ ์˜์กด์„ฑ์„ ๊ด€๋ฆฌํ–ˆ์„ ๋•Œ ๋А๊ปด์ง€๋Š” ๋ฌธ์ œ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

  1. API์˜ path/query ์ธ์ž๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋˜๋Š” ๊ณต์œ  ๋กœ์ง๊ณผ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ†ตํ•ด ์ƒ์„ฑํ•ด์•ผํ•˜๋Š” ๊ฐ์ฒด ๊ด€๊ณ„๊ฐ€ ์–ฝํžˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  2. ์˜์กด ๊ด€๊ณ„๋ฅผ ํ•œ๋ฒˆ์— ํŒŒ์•…ํ•˜๊ธฐ ํž˜๋“ญ๋‹ˆ๋‹ค. Depends๋ฅผ ๊ณ„์† ์ฐธ์กฐํ•˜๋ฉฐ ํ•จ์ˆ˜๋งˆ๋‹ค ์–ด๋–ค ๊ฐ์ฒด๊ฐ€ ์ฃผ์ž…๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
  3. ์˜์กด๊ด€๊ณ„๋ฅผ ๋ช…์‹œํ•˜๋Š” ๋ถ€๋ถ„๊ณผ ์‹ค์ œ ์ฝ”๋“œ๋กœ์ง์ด ์„ž์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿค FastAPI์™€ Dependency Injector๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด?

FastAPI์™€ ์˜์กด์„ฑ ์ฃผ์ž… ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์œ„์—์„œ ๋ช…์‹œํ•œ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์˜์กด์„ฑ ์ฃผ์ž… Container๋ฅผ ํ†ตํ•ด ์˜์กด๊ด€๊ณ„๋ฅผ ํ•˜๋‚˜์˜ ํŒŒ์ผ์—์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. Depends์™€ ๊ฐ™์€ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ๋””์ŠคํŒจ์ฒ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ˆœ์ˆ˜ํ•œ ํŒŒ์ด์ฌ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ํ•„์š” ์‹œ Container๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ Container๋ฅผ ํ†ตํ•ด ์˜์กด๊ด€๊ณ„๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ FastAPI์˜ ์˜์กด์„ฑ์„ Dependency Injector๋ฅผ ์‚ฌ์šฉํ•ด ์ฃผ์ž…ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŒ… ์˜ˆ์ œ๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“‚ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ 

.
โ”œโ”€โ”€ main.py # ์‹คํ–‰ ์ฝ”๋“œ
โ”œโ”€โ”€ container.py # ์˜์กด์„ฑ ์ปจํ…Œ์ด๋„ˆ
โ”œโ”€โ”€ router.py # fastAPI ๋ผ์šฐํ„ฐ
โ”œโ”€โ”€ service.py # ์„œ๋น„์Šค ํด๋ž˜์Šค ๋ชจ๋“ˆ
โ””โ”€โ”€ repository.py # ์ €์žฅ์†Œ ํด๋ž˜์Šค ๋ชจ๋“ˆ


์˜์กด๊ด€๊ณ„๊ฐ€ ํ˜•์„ฑ๋œ service, repository ํด๋ž˜์Šค ์ž…๋‹ˆ๋‹ค. ์˜์กด๊ด€๊ณ„๋ฅผ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Depends ๊ฐ™์€ ๋””์ŠคํŒจ์ฒ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ˆœ์ˆ˜ํ•œ python ํด๋ž˜์Šค ์ž…๋‹ˆ๋‹ค.

# service.py
class BlogService: 
    def __init__(self, repository: PostRepository): 
    self._repository = repository 

def create_post(self, title, content): 
    post = Post(title, content)
    self._repository.add_post(post) 

def get_posts(self): 
	return self._repository.list_posts()
# repository.py
class PostRepository: 
    def __init__(self): 
    self._posts = [] 

def add_post(self, post):
	self._posts.append(post) 

def list_posts(self):
	return self._posts


๋‹ค์Œ์€ ์˜์กด์„ฑ ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”  Containerํด๋ž˜์Šค ์ž…๋‹ˆ๋‹ค. BlogService์— PostRepository๊ฐ€ ์ฃผ์ž…๋˜์—ˆ์Œ์„ ๋ช…์‹œ์ ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# container.py
from dependency_injector import containers, providers
from repository import PostRepository
from service import BlogService

class Container(containers.DeclarativeContainer):
    post_repository = providers.Singleton(PostRepository) 
    blog_service = providers.Factory(BlogService, repository=post_repository)

 

@inject๋ฅผ ํ†ตํ•ด fastAPI๋กœ ๋งŒ๋“ค์–ด์ง„ Router ํ•จ์ˆ˜์— ํ•„์š”ํ•œ blog_service ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•ด์คฌ์Šต๋‹ˆ๋‹ค.


๋ˆˆ์—ฌ๊ฒจ๋ด์•ผํ•˜๋Š” ๋ถ€๋ถ„์€ fastAPI์˜ Depends์™€ dependency injector์˜ Provide๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ–ˆ๊ณ , Provide๋‚ด์— Container์—์„œ ์ฃผ์ž…๋ฐ›์•„์•ผํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ช…์‹œํ•œ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

# router.py
from fastapi import FastAPI, Depends
from repository import PostRepository
from service import BlogService

from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
from container import Container

router = APIRouter()

# ๋ผ์šฐํŠธ
@router.get("/posts")
@inject
def list_blog_posts(
    blog_service: BlogService = Depends(Provide[Container.blog_service])
):
    return blog_service.list_posts()

@router.post("/posts")
@inject
def create_blog_post(
    post_data: dict, 
    blog_service: BlogService = Depends(Provide[Container.blog_service])
):
    blog_service.add_post(post_data)


๋งˆ์ง€๋ง‰์œผ๋กœ main.py ์— ๋Œ€ํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

# main.py
import uvicorn
from fastAPI import FastAPI
from container import Container
from router import router


if __name__ == "__main__":
    container = Container()
    container.wire(modules=[.router])

    app = FastAPI()
    app.container = container
    app.include_router(router.router)

	uvicorn.run(app, host="0.0.0.0", port=8080)


mainํŒŒ์ผ์—์„œ container๋ฅผ ์ธ์Šคํ„ด์Šคํ™” ์‹œํ‚ค๊ณ  ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•  ๋ถ€๋ถ„์„ wiring ํ•ฉ๋‹ˆ๋‹ค. FastAPI ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ๊ฐ์ฒด์—์„œ ์‚ฌ์šฉ๋˜๋Š” container๋ฅผ Dependency Injector์˜ Container๋กœ ๋ฐ”๊ฟ”์ค๋‹ˆ๋‹ค. 


๐ŸŒŸ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ†ตํ•ด ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ด์ 

์ง€๊ธˆ๊นŒ์ง€ FastAPI์—์„œ Dependency Injector๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์˜์กด์„ฑ ์ฃผ์ž…, ๊ทธ๋ฆฌ๊ณ  ์˜์กด์„ฑ ์ฃผ์ž… ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ด์ ์ด ๋ญ๊ฐ€ ์žˆ์„๊นŒ์š”?

๋‚ฎ์€ ๊ฒฐํ•ฉ๋ ฅ ๋†’์€ ์‘์ง‘๋ ฅ

 

๊ฐ ๊ฐ์ฒด๊ฐ„ ๊ด€๊ณ„๊ฐ€ ๋Šฆ์€ ๊ฒฐํ•ฉ์„ ๊ฐ–๊ฒŒ๋ฉ๋‹ˆ๋‹ค. ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋Š” ์ƒ์„ฑ์ž๋กœ ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ ๊ฐ์ฒด์˜ ๊ตฌํ˜„์— ์˜์กดํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์ „๋‹ฌ๋ฐ›์€ ๊ฐ์ฒด์˜ ์†์„ฑ, ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋ฟ ์ž…๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ๊ฐ ํด๋ž˜์Šค์˜ ์˜์กด๊ด€๊ณ„์— ์–ฝ๋งค์ด์ง€ ์•Š๊ณ  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ

์˜์กด์„ฑ์„ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์ด ์šฉ์ดํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํ…Œ์ŠคํŠธ ์‹œ์— ์‚ฌ์šฉํ•  Container๋ฅผ ๋”ฐ๋กœ ์ •์˜ํ•ด ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์˜์กด์„ฑ ์ฃผ์ž…์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์„ Stub ๊ฐ์ฒด ํ˜น์€ Mock ๊ฐ์ฒด๋กœ ๋ฐ”๊ฟ”์„œ ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋ช…์‹œ์  ์˜์กด์„ฑ ๊ด€๋ฆฌ

DI ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์˜์กด๊ด€๊ณ„๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ•˜๋‚˜์˜ ํŒŒ์ผ๋‚ด์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ํŒŒ์ผ์—์„œ ์ •์˜๋˜์–ด์žˆ๋˜ ์˜์กด๊ด€๊ณ„๋ฅผ ํ•˜๋‚˜์˜ ํŒŒ์ผ์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. Provider๋ฅผ ์‚ฌ์šฉํ•ด ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ์‹๋„ ๋ช…์‹œ์ ์œผ๋กœ ์„ ํƒํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ ๋งˆ์น˜๋ฉฐ

๋™์  ํƒ€์ž… ์–ธ์–ด์ธ python์€ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜์ง€ ์•Š์•„๋„, ๋Ÿฐํƒ€์ž„์— ๊ฐ์ฒด๋ฅผ ๊ฐˆ์•„๋ผ์šธ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— DI ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ง์ ‘ IoC ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , wire ๋กœ์ง์„ ๊ตฌํ˜„ํ•ด ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ์˜์กด์„ฑ ์ฃผ์ž… ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ํ•„์š”ํ•œ์ง€, ํ•„์š”ํ•˜์ง€ ์•Š์€์ง€๋Š” ๊ฐœ์ธ์˜ ์„ ํƒ์ด์ง€๋งŒ ์ €๋Š” ๋ฐ”ํ€ด๋ฅผ ๋‹ค์‹œ ๋ฐœ๋ช…ํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค ์ด๋ฏธ ์กด์žฌํ•˜๋Š” DI ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•ด ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค :)

 

๐Ÿ”— ์ฐธ๊ณ ์ž๋ฃŒ

ํฌ์ŠคํŒ…์„ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด Dependeny Injector ๊ณต์‹๋ฌธ์„œ์™€ ํ•œ๋ฐ”๋ฆ„๋‹˜์˜ ๋ธ”๋กœ๊ทธ ๊ธ€์„ ๋งŽ์ด ์ฐธ๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

https://python-dependency-injector.ets-labs.org/
https://rumbarum.oopy.io/post/review-python-dependency-injector

'Computer Science > Python' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Python] FastAPI ๋ฏธ๋“ค์›จ์–ด๋กœ Sqlalchemy Session ๊ด€๋ฆฌํ•˜๊ธฐ  (2) 2024.11.24
[Python] ๋น„๋™๊ธฐ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋ ค๋ฉด? (a.k.a pytest-asyncio)  (5) 2024.04.28
[Python] UoW(Unit of Work) ํŒจํ„ด์„ ์•Œ์•„๋ณด์ž  (1) 2024.04.14
[Python] SqlAlchemy 1.4 -> 2.0 ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋‹จ๊ณ„๋ณ„ ๊ฐ€์ด๋“œ  (2) 2024.03.31
[Python] Tox๋กœ ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ  (2) 2023.07.02
    'Computer Science/Python' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
    • [Python] FastAPI ๋ฏธ๋“ค์›จ์–ด๋กœ Sqlalchemy Session ๊ด€๋ฆฌํ•˜๊ธฐ
    • [Python] ๋น„๋™๊ธฐ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋ ค๋ฉด? (a.k.a pytest-asyncio)
    • [Python] UoW(Unit of Work) ํŒจํ„ด์„ ์•Œ์•„๋ณด์ž
    • [Python] SqlAlchemy 1.4 -> 2.0 ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋‹จ๊ณ„๋ณ„ ๊ฐ€์ด๋“œ
    Becker
    Becker

    ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”