diff --git a/docs/src/dependencies/tutorial001.py b/docs/src/dependencies/tutorial001.py index 32ef351da..131a471a1 100644 --- a/docs/src/dependencies/tutorial001.py +++ b/docs/src/dependencies/tutorial001.py @@ -10,3 +10,8 @@ async def common_parameters(q: str = None, skip: int = 0, limit: int = 100): @app.get("/items/") async def read_items(commons: dict = Depends(common_parameters)): return commons + + +@app.get("/users/") +async def read_users(commons: dict = Depends(common_parameters)): + return commons diff --git a/docs/tutorial/dependencies/first-steps-functions.md b/docs/tutorial/dependencies/first-steps-functions.md deleted file mode 100644 index f736a9163..000000000 --- a/docs/tutorial/dependencies/first-steps-functions.md +++ /dev/null @@ -1,91 +0,0 @@ -Let's see a very simple example of the **Dependency Injection** system. - -It will be so simple that it is not very useful, for now. - -But this way we can focus on how the **Dependency Injection** system works. - -In the next chapters we'll extend it to see how can it be so useful. - -## Create a dependency, or "dependable" - -Let's first focus on the dependency. - -It is just a function that can take all the same parameters that a path operation function can take: - -```Python hl_lines="6 7" -{!./src/dependencies/tutorial001.py!} -``` - -That's it. - -**2 lines**. - -And it has the same shape and structure that all your path operation functions. - -You can think of it as a path operation function without the "decorator" (without the `@app.get("/some-path")`). - -And it can return anything you want. - -In this case, this dependency expects: - -* An optional query parameter `q` that is a `str`. -* An optional query parameter `skip` that is an `int`, and by default is `0`. -* An optional query parameter `limit` that is an `int`, and by default is `100`. - -And then it just returns a `dict` containing those values. - -## Import `Depends` - -```Python hl_lines="1" -{!./src/dependencies/tutorial001.py!} -``` - -## Declare the dependency, in the "dependant" - -The same way you use `Body`, `Query`, etc. with your path operation function parameters, use `Depends` with a new parameter: - -```Python hl_lines="11" -{!./src/dependencies/tutorial001.py!} -``` - -Although you use it in the parameters of your function too, `Depends` works a bit differently. - -You only give `Depends` a single parameter. - -This parameter must be a function with the same parameters that can be taken by a path operation function. - -Whenever a new request arrives, **FastAPI** will take care of: - -* Calling your dependency ("dependable") function with the correct parameters. -* Get the result from your function. -* Assign that result to the parameter in your path operation function. - -!!! note - Notice that you don't have to create a special class and pass it somewhere to **FastAPI** or anything similar. - - You just pass it to `Depends` and **FastAPI** knows how to do the rest. - -## To `async` or not to `async` - -As dependencies will also be called by **FastAPI** (the same as your path operation functions), the same rules apply while defining your functions. - -You can use `async def` or normal `def`. - -And you can declare dependencies with `async def` inside of normal `def` path operation functions, or `def` dependencies inside of `async def` path operation functions. - -It doesn't matter. **FastAPI** will know what to do. - -!!! note - If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. - -## Integrated wiht OpenAPI - -All the request declarations, validations and requirements of your dependencies (and sub-dependencies) will be integrated in the same OpenAPI schema. - -So, the interactive docs will have all the information they need, while you keep all the flexibility of the dependencies: - - - -## Recap - -Create Dependencies with **2 lines** of code. \ No newline at end of file diff --git a/docs/tutorial/dependencies/first-steps.md b/docs/tutorial/dependencies/first-steps.md new file mode 100644 index 000000000..7a19618a3 --- /dev/null +++ b/docs/tutorial/dependencies/first-steps.md @@ -0,0 +1,167 @@ +**FastAPI** has a very powerful but intuitive **Dependency Injection** system. + +It is designed to be very simple to use, and to make it very easy for any developer to integrate other components with **FastAPI**. + +## "Dependency Injection"? + +**"Dependency Injection"** means, in programming, that there is a way for your code (in this case, your path operation functions) to declare things that it requires to work and use: "dependencies". + +And then, that system (in this case **FastAPI**) will take care of doing whatever is needed to provide your code with those needed dependencies ("inject" the dependencies). + +This is very useful when you need to: + +* Have shared logic (the same code logic again and again). +* Share database connections. +* Enforce security, authentication, role requirements, etc. +* etc. + +All these, while minimizing code repetition. + + +## First Steps + +Let's see a very simple example. It will be so simple that it is not very useful, for now. + +But this way we can focus on how the **Dependency Injection** system works. + + +### Create a dependency, or "dependable" + +Let's first focus on the dependency. + +It is just a function that can take all the same parameters that a path operation function can take: + +```Python hl_lines="6 7" +{!./src/dependencies/tutorial001.py!} +``` + +That's it. + +**2 lines**. + +And it has the same shape and structure that all your path operation functions. + +You can think of it as a path operation function without the "decorator" (without the `@app.get("/some-path")`). + +And it can return anything you want. + +In this case, this dependency expects: + +* An optional query parameter `q` that is a `str`. +* An optional query parameter `skip` that is an `int`, and by default is `0`. +* An optional query parameter `limit` that is an `int`, and by default is `100`. + +And then it just returns a `dict` containing those values. + +### Import `Depends` + +```Python hl_lines="1" +{!./src/dependencies/tutorial001.py!} +``` + +### Declare the dependency, in the "dependant" + +The same way you use `Body`, `Query`, etc. with your path operation function parameters, use `Depends` with a new parameter: + +```Python hl_lines="11 16" +{!./src/dependencies/tutorial001.py!} +``` + +Although you use `Depends` in the parameters of your function the same way you use `Body`, `Query`, etc, `Depends` works a bit differently. + +You only give `Depends` a single parameter. + +This parameter must be something like a function. + +And that function takes parameters in the same way that path operation functions do. + +!!! tip + You'll see what other "things", apart from functions, can be used as dependencies in the next chapter. + +Whenever a new request arrives, **FastAPI** will take care of: + +* Calling your dependency ("dependable") function with the correct parameters. +* Get the result from your function. +* Assign that result to the parameter in your path operation function. + +!!! note + Notice that you don't have to create a special class and pass it somewhere to **FastAPI** to "register" it or anything similar. + + You just pass it to `Depends` and **FastAPI** knows how to do the rest. + +## To `async` or not to `async` + +As dependencies will also be called by **FastAPI** (the same as your path operation functions), the same rules apply while defining your functions. + +You can use `async def` or normal `def`. + +And you can declare dependencies with `async def` inside of normal `def` path operation functions, or `def` dependencies inside of `async def` path operation functions, etc. + +It doesn't matter. **FastAPI** will know what to do. + +!!! note + If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. + + +## Integrated with OpenAPI + +All the request declarations, validations and requirements of your dependencies (and sub-dependencies) will be integrated in the same OpenAPI schema. + +So, the interactive docs will have all the information from these dependencies too: + + + + +## Simple usage + +If you look at it, *path operation functions* are declared to be used whenever a *path* and *operation* matches, and then **FastAPI** takes care of calling the function with the correct parameters and use the response. + +Actually, all (or most) of the web frameworks work in this same way. + +You never call those functions directly. They are called by your framework (in this case, **FastAPI**). + +With the Dependency Injection system, you can also tell **FastAPI** that your path operation function also "depends" on something else that should be executed before your *path operation function*, and **FastAPI** will take care of executing it and "injecting" the results. + +Other common terms for this same idea of "dependency injection" are: + +* resources +* providers +* services +* injectables +* components + +## **FastAPI** plug-ins + +Integrations and "plug-in"s can be built using the **Dependency Injection** system. But in fact, there is actually **no need to create "plug-ins"**, as by using dependencies it's possible to declare an infinite number of integrations and interactions that become available to your path operation functions. + +And dependencies can be created in a very simple and intuitive way that allow you to just import the Python packages you need, and integrate them with your API functions in a couple of lines of code, _literally_. + +You will see examples of this in the next chapters, about relational and NoSQL databases, security, etc. + +## **FastAPI** compatibility + +The simplicity of the dependency injection system makes **FastAPI** compatible with: + +* all the relational databases +* NoSQL databases +* external packages +* external APIs +* authentication and authorization systems +* API usage monitoring systems +* response data injection systems +* etc. + + +## Simple and Powerful + +Although the hierarchical dependency injection system is very simple to define and use, it's still very powerful. + +You can define dependencies that in turn can define dependencies themselves. + +In the end, a hierarchical tree of dependencies is built, and the **Dependency Injection** system takes care of solving all these dependencies for you (and your dependencies) and providing (injecting) the results at each step. + +## Integrated with **OpenAPI** + +All these dependencies, while declaring their requirements, add parameters, validations, etc. to your path operations. + +**FastAPI** will take care of adding it all to the OpenAPI schema, so that it is shown in the interactive documentation systems. diff --git a/docs/tutorial/dependencies/intro.md b/docs/tutorial/dependencies/intro.md deleted file mode 100644 index 486d9a7f0..000000000 --- a/docs/tutorial/dependencies/intro.md +++ /dev/null @@ -1,58 +0,0 @@ -**FastAPI** has a very powerful but intuitive **Dependency Injection** system. - -It is designed to be very simple to use, and to make it very easy for any developer to integrate other components with **FastAPI**. - -## "Dependency Injection"? - -**"Dependency Injection"** means, in programming, that there is a way for your code (in this case, your path operation functions) to declare things that it requires to work and use. - -And then, that system (in this case **FastAPI**) will take care of doing whatever is needed to provide your code with that thing that it needs. - -If you look at it, path operation functions are declared to be used whenever a path and operation matches, and then **FastAPI** will take care of calling the function with the correct parameters and use the response. - -Actually, all (or most) of the web frameworks work in this same way. - -You never call those functions directly. They are called by your framework (in this case, **FastAPI**). - -With the Dependency Injection system, you can also tell **FastAPI** that your path operation function also "depends" on something else that should be executed before your path operation function, and **FastAPI** will take care of executing it and "injecting" the results. - -Other common terms for this same idea are: - -* resources -* providers -* services -* injectables - -## **FastAPI** plug-ins - -Integrations and "plug-in"s can be built using the **Dependency Injection** system. But in fact, there is actually **no need to create "plug-ins"**, as by using dependencies it's possible to declare an infinite number of integrations and interactions that become available to your path operation functions. - -And dependencies can be created in a very simple and intuitive way that allow you to just import the Python packages you need, and integrate them with your API functions in a couple of lines of code, _literally_. - -## **FastAPI** compatibility - -The simplicity of the dependency injection system makes **FastAPI** compatible with: - -* all the relational databases -* NoSQL databases -* external packages -* external APIs -* authentication and authorization systems -* API usage monitoring systems -* response data injection systems -* etc. - - -## Simple and Powerful - -Although the hierarchical dependency injection system is very simple to define and use, it's still very powerful. - -You can define dependencies that in turn can define dependencies themselves. - -In the end, a hierarchical tree of dependencies is built, and the **Dependency Injection** system takes care of solving all these dependencies for you (and your dependencies) and providing the results at each step. - -## Integrated with **OpenAPI** - -All these dependencies, while declaring their requirements, might have been adding parameters, validations, etc. to your path operations. - -**FastAPI** will take care of adding it all to the OpenAPI schema, so that it is shown in the interactive documentation systems. diff --git a/mkdocs.yml b/mkdocs.yml index 4a9eb9974..6fe4d9763 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,8 +23,8 @@ nav: - Path Parameters: 'tutorial/path-params.md' - Query Parameters: 'tutorial/query-params.md' - Request Body: 'tutorial/body.md' - - Query Parameters - String Validations: 'tutorial/query-params-str-validations.md' - - Path Parameters - Numeric Validations: 'tutorial/path-params-numeric-validations.md' + - Query Parameters and String Validations: 'tutorial/query-params-str-validations.md' + - Path Parameters and Numeric Validations: 'tutorial/path-params-numeric-validations.md' - Body - Multiple Parameters: 'tutorial/body-multiple-params.md' - Body - Schema: 'tutorial/body-schema.md' - Body - Nested Models: 'tutorial/body-nested-models.md' @@ -40,8 +40,7 @@ nav: - Path Operation Advanced Configuration: 'tutorial/path-operation-advanced-configuration.md' - Custom Response: 'tutorial/custom-response.md' - Dependencies: - - Dependencies Intro: 'tutorial/dependencies/intro.md' - - First Steps - Functions: 'tutorial/dependencies/first-steps-functions.md' + - First Steps: 'tutorial/dependencies/first-steps.md' - Classes as Dependencies: 'tutorial/dependencies/classes-as-dependencies.md' - Sub-dependencies: 'tutorial/dependencies/sub-dependencies.md' - Advanced Dependencies: 'tutorial/dependencies/advanced-dependencies.md' diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001.py b/tests/test_tutorial/test_dependencies/test_tutorial001.py index 94c164f4e..b15ceb901 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001.py @@ -50,7 +50,49 @@ openapi_schema = { }, ], } - } + }, + "/users/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "summary": "Read Users Get", + "operationId": "read_users_users__get", + "parameters": [ + { + "required": False, + "schema": {"title": "Q", "type": "string"}, + "name": "q", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Skip", "type": "integer", "default": 0}, + "name": "skip", + "in": "query", + }, + { + "required": False, + "schema": {"title": "Limit", "type": "integer", "default": 100}, + "name": "limit", + "in": "query", + }, + ], + } + }, }, "components": { "schemas": { @@ -97,6 +139,7 @@ def test_openapi_schema(): ("/items?q=foo", 200, {"q": "foo", "skip": 0, "limit": 100}), ("/items?q=foo&skip=5", 200, {"q": "foo", "skip": 5, "limit": 100}), ("/items?q=foo&skip=5&limit=30", 200, {"q": "foo", "skip": 5, "limit": 30}), + ("/users", 200, {"q": None, "skip": 0, "limit": 100}), ("/openapi.json", 200, openapi_schema), ], )