From 6205935323ded4767438ee81623892621b353415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 26 Mar 2020 20:09:53 +0100 Subject: [PATCH] :sparkles: Add support for docs translations (#1168) * :globe_with_meridians: Refactor file structure to support internationalization * :white_check_mark: Update tests changed after i18n * :twisted_rightwards_arrows: Merge Typer style from master * :wrench: Update MkConfig with Typer-styles * :art: Format mkdocs.yml with cannonical form * :art: Format mkdocs.yml * :wrench: Update MkDocs config * :heavy_plus_sign: Add docs translation scripts dependencies * :sparkles: Add Typer scripts to handle translations * :sparkles: Add missing translation snippet to include * :sparkles: Update contributing docs, add docs for translations * :see_no_evil: Add docs_build to gitignore * :wrench: Update scripts with new locations and docs scripts * :construction_worker: Update docs deploy action with translations * :memo: Add note about languages not supported in the theme * :sparkles: Add first translation, for Spanish --- .github/workflows/deploy-docs.yml | 4 +- .gitignore | 1 + docs/contributing.md | 176 ------- .../docs}/advanced/additional-responses.md | 10 +- .../docs}/advanced/additional-status-codes.md | 4 +- .../docs}/advanced/advanced-dependencies.md | 10 +- .../docs}/advanced/async-sql-databases.md | 16 +- .../advanced/custom-request-and-route.md | 14 +- .../{ => en/docs}/advanced/custom-response.md | 24 +- docs/{ => en/docs}/advanced/events.md | 5 +- .../docs}/advanced/extending-openapi.md | 20 +- docs/{ => en/docs}/advanced/graphql.md | 5 +- docs/{ => en/docs}/advanced/index.md | 2 + docs/{ => en/docs}/advanced/middleware.md | 8 +- .../{ => en/docs}/advanced/nosql-databases.md | 18 +- .../docs}/advanced/openapi-callbacks.md | 10 +- .../path-operation-advanced-configuration.md | 10 +- .../advanced/response-change-status-code.md | 4 +- .../docs}/advanced/response-cookies.md | 6 +- .../docs}/advanced/response-directly.md | 6 +- .../docs}/advanced/response-headers.md | 6 +- .../advanced/security/http-basic-auth.md | 8 +- docs/{ => en/docs}/advanced/security/index.md | 2 + .../docs}/advanced/security/oauth2-scopes.md | 18 +- .../docs}/advanced/sql-databases-peewee.md | 36 +- .../docs}/advanced/sub-applications-proxy.md | 8 +- docs/{ => en/docs}/advanced/templates.md | 10 +- .../docs}/advanced/testing-dependencies.md | 4 +- docs/{ => en/docs}/advanced/testing-events.md | 6 +- .../docs}/advanced/testing-websockets.md | 4 +- .../docs}/advanced/using-request-directly.md | 4 +- docs/{ => en/docs}/advanced/websockets.md | 9 +- docs/{ => en/docs}/advanced/wsgi.md | 4 +- docs/{ => en/docs}/alternatives.md | 2 + docs/{ => en/docs}/async.md | 2 + docs/{ => en/docs}/benchmarks.md | 2 + docs/en/docs/contributing.md | 441 ++++++++++++++++++ docs/{ => en/docs}/css/custom.css | 0 docs/{ => en/docs}/css/termynal.css | 0 docs/{ => en/docs}/deployment.md | 2 + docs/{ => en/docs}/external-links.md | 2 + docs/{ => en/docs}/features.md | 9 +- docs/{ => en/docs}/help-fastapi.md | 2 + docs/{ => en/docs}/history-design-future.md | 2 + docs/{ => en/docs}/img/favicon.png | Bin .../docs}/img/github-social-preview.png | Bin .../docs}/img/github-social-preview.svg | 0 .../{ => en/docs}/img/icon-transparent-bg.png | Bin docs/{ => en/docs}/img/icon-white-bg.png | Bin docs/{ => en/docs}/img/icon-white.svg | 0 .../img/index/index-01-swagger-ui-simple.png | Bin .../docs}/img/index/index-02-redoc-simple.png | Bin .../docs}/img/index/index-03-swagger-02.png | Bin .../docs}/img/index/index-04-swagger-03.png | Bin .../docs}/img/index/index-05-swagger-04.png | Bin .../docs}/img/index/index-06-redoc-02.png | Bin .../img/logo-margin/logo-teal-vector.svg | 0 .../docs}/img/logo-margin/logo-teal.png | Bin .../docs}/img/logo-margin/logo-teal.svg | 0 .../docs}/img/logo-margin/logo-white-bg.png | Bin docs/{ => en/docs}/img/logo-teal-vector.svg | 0 docs/{ => en/docs}/img/logo-teal.svg | 0 docs/{ => en/docs}/img/pycharm-completion.png | Bin .../docs}/img/python-types/image01.png | Bin .../docs}/img/python-types/image02.png | Bin .../docs}/img/python-types/image03.png | Bin .../docs}/img/python-types/image04.png | Bin .../docs}/img/python-types/image05.png | Bin .../docs}/img/python-types/image06.png | Bin .../tutorial/additional-responses/image01.png | Bin .../application-configuration/image01.png | Bin .../tutorial/async-sql-databases/image01.png | Bin .../tutorial/bigger-applications/image01.png | Bin .../img/tutorial/body-fields/image01.png | Bin .../tutorial/body-nested-models/image01.png | Bin .../docs}/img/tutorial/body/image01.png | Bin .../docs}/img/tutorial/body/image02.png | Bin .../docs}/img/tutorial/body/image03.png | Bin .../docs}/img/tutorial/body/image04.png | Bin .../docs}/img/tutorial/body/image05.png | Bin .../img/tutorial/custom-response/image01.png | Bin .../docs}/img/tutorial/debugging/image01.png | Bin .../img/tutorial/dependencies/image01.png | Bin .../img/tutorial/dependencies/image02.png | Bin .../tutorial/extending-openapi/image01.png | Bin .../docs}/img/tutorial/graphql/image01.png | Bin .../tutorial/openapi-callbacks/image01.png | Bin .../path-operation-configuration/image01.png | Bin .../path-operation-configuration/image02.png | Bin .../path-operation-configuration/image03.png | Bin .../path-operation-configuration/image04.png | Bin .../path-operation-configuration/image05.png | Bin .../img/tutorial/path-params/image01.png | Bin .../img/tutorial/path-params/image02.png | Bin .../img/tutorial/path-params/image03.png | Bin .../query-params-str-validations/image01.png | Bin .../query-params-str-validations/image02.png | Bin .../img/tutorial/response-model/image01.png | Bin .../img/tutorial/response-model/image02.png | Bin .../tutorial/response-status-code/image01.png | Bin .../tutorial/response-status-code/image02.png | Bin .../docs}/img/tutorial/security/image01.png | Bin .../docs}/img/tutorial/security/image02.png | Bin .../docs}/img/tutorial/security/image03.png | Bin .../docs}/img/tutorial/security/image04.png | Bin .../docs}/img/tutorial/security/image05.png | Bin .../docs}/img/tutorial/security/image06.png | Bin .../docs}/img/tutorial/security/image07.png | Bin .../docs}/img/tutorial/security/image08.png | Bin .../docs}/img/tutorial/security/image09.png | Bin .../docs}/img/tutorial/security/image10.png | Bin .../docs}/img/tutorial/security/image11.png | Bin .../docs}/img/tutorial/security/image12.png | Bin .../img/tutorial/sql-databases/image01.png | Bin .../img/tutorial/sql-databases/image02.png | Bin .../img/tutorial/sub-applications/image01.png | Bin .../img/tutorial/sub-applications/image02.png | Bin .../docs}/img/tutorial/websockets/image01.png | Bin .../docs}/img/tutorial/websockets/image02.png | Bin .../docs}/img/tutorial/websockets/image03.png | Bin .../docs}/img/tutorial/websockets/image04.png | Bin docs/{ => en/docs}/img/vscode-completion.png | Bin docs/{ => en/docs}/index.md | 0 docs/{ => en/docs}/js/custom.js | 0 docs/{ => en/docs}/js/termynal.js | 0 docs/{ => en/docs}/project-generation.md | 2 + docs/{ => en/docs}/python-types.md | 28 +- docs/{ => en/docs}/release-notes.md | 2 + .../tutorial/application-configuration.md | 8 +- .../docs}/tutorial/background-tasks.md | 10 +- .../docs}/tutorial/bigger-applications.md | 20 +- docs/{ => en/docs}/tutorial/body-fields.md | 8 +- .../docs}/tutorial/body-multiple-params.md | 12 +- .../docs}/tutorial/body-nested-models.md | 24 +- docs/{ => en/docs}/tutorial/body-updates.md | 10 +- docs/{ => en/docs}/tutorial/body.md | 14 +- docs/{ => en/docs}/tutorial/cookie-params.md | 6 +- docs/{ => en/docs}/tutorial/cors.md | 4 +- docs/{ => en/docs}/tutorial/debugging.md | 4 +- .../dependencies/classes-as-dependencies.md | 16 +- ...pendencies-in-path-operation-decorators.md | 10 +- .../dependencies/dependencies-with-yield.md | 16 +- .../docs}/tutorial/dependencies/index.md | 8 +- .../tutorial/dependencies/sub-dependencies.md | 8 +- docs/{ => en/docs}/tutorial/encoder.md | 4 +- .../docs}/tutorial/extra-data-types.md | 6 +- docs/{ => en/docs}/tutorial/extra-models.md | 12 +- docs/{ => en/docs}/tutorial/first-steps.md | 18 +- .../{ => en/docs}/tutorial/handling-errors.md | 18 +- docs/{ => en/docs}/tutorial/header-params.md | 10 +- docs/{ => en/docs}/tutorial/index.md | 2 + docs/{ => en/docs}/tutorial/middleware.md | 6 +- .../tutorial/path-operation-configuration.md | 14 +- .../path-params-numeric-validations.md | 16 +- docs/{ => en/docs}/tutorial/path-params.md | 20 +- .../tutorial/query-params-str-validations.md | 30 +- docs/{ => en/docs}/tutorial/query-params.md | 16 +- docs/{ => en/docs}/tutorial/request-files.md | 10 +- .../docs}/tutorial/request-forms-and-files.md | 6 +- docs/{ => en/docs}/tutorial/request-forms.md | 6 +- docs/{ => en/docs}/tutorial/response-model.md | 22 +- .../docs}/tutorial/response-status-code.md | 8 +- .../docs}/tutorial/security/first-steps.md | 8 +- .../tutorial/security/get-current-user.md | 14 +- docs/{ => en/docs}/tutorial/security/index.md | 2 + .../docs}/tutorial/security/oauth2-jwt.md | 10 +- .../docs}/tutorial/security/simple-oauth2.md | 12 +- docs/{ => en/docs}/tutorial/sql-databases.md | 48 +- docs/{ => en/docs}/tutorial/static-files.md | 4 +- docs/{ => en/docs}/tutorial/testing.md | 12 +- docs/en/mkdocs.yml | 147 ++++++ docs/es/docs/index.md | 437 +++++++++++++++++ docs/es/mkdocs.yml | 58 +++ docs/missing-translation.md | 4 + .../additional_responses/tutorial001.py | 0 .../additional_responses/tutorial002.py | 0 .../additional_responses/tutorial003.py | 0 .../additional_responses/tutorial004.py | 0 .../additional_status_codes/tutorial001.py | 0 .../advanced_middleware/tutorial001.py | 0 .../advanced_middleware/tutorial002.py | 0 .../advanced_middleware/tutorial003.py | 0 .../src => docs_src}/app_testing/__init__.py | 0 {docs/src => docs_src}/app_testing/main.py | 0 {docs/src => docs_src}/app_testing/main_b.py | 0 .../src => docs_src}/app_testing/test_main.py | 0 .../app_testing/test_main_b.py | 0 .../app_testing/tutorial001.py | 0 .../app_testing/tutorial002.py | 0 .../app_testing/tutorial003.py | 0 .../application_configuration/tutorial001.py | 0 .../application_configuration/tutorial002.py | 0 .../application_configuration/tutorial003.py | 0 .../async_sql_databases/tutorial001.py | 0 .../background_tasks/tutorial001.py | 0 .../background_tasks/tutorial002.py | 0 .../bigger_applications/__init__.py | 0 .../bigger_applications/app/__init__.py | 0 .../bigger_applications/app/main.py | 0 .../app/routers/__init__.py | 0 .../bigger_applications/app/routers/items.py | 0 .../bigger_applications/app/routers/users.py | 0 {docs/src => docs_src}/body/tutorial001.py | 0 {docs/src => docs_src}/body/tutorial002.py | 0 {docs/src => docs_src}/body/tutorial003.py | 0 {docs/src => docs_src}/body/tutorial004.py | 0 .../body_fields/tutorial001.py | 0 .../body_fields/tutorial002.py | 0 .../body_multiple_params/tutorial001.py | 0 .../body_multiple_params/tutorial002.py | 0 .../body_multiple_params/tutorial003.py | 0 .../body_multiple_params/tutorial004.py | 0 .../body_multiple_params/tutorial005.py | 0 .../body_nested_models/tutorial001.py | 0 .../body_nested_models/tutorial002.py | 0 .../body_nested_models/tutorial003.py | 0 .../body_nested_models/tutorial004.py | 0 .../body_nested_models/tutorial005.py | 0 .../body_nested_models/tutorial006.py | 0 .../body_nested_models/tutorial007.py | 0 .../body_nested_models/tutorial008.py | 0 .../body_nested_models/tutorial009.py | 0 .../body_updates/tutorial001.py | 0 .../body_updates/tutorial002.py | 0 .../cookie_params/tutorial001.py | 0 {docs/src => docs_src}/cors/tutorial001.py | 0 .../custom_request_and_route/tutorial001.py | 0 .../custom_request_and_route/tutorial002.py | 0 .../custom_request_and_route/tutorial003.py | 0 .../custom_response/tutorial001.py | 0 .../custom_response/tutorial001b.py | 0 .../custom_response/tutorial002.py | 0 .../custom_response/tutorial003.py | 0 .../custom_response/tutorial004.py | 0 .../custom_response/tutorial005.py | 0 .../custom_response/tutorial006.py | 0 .../custom_response/tutorial007.py | 0 .../custom_response/tutorial008.py | 0 .../custom_response/tutorial009.py | 0 .../src => docs_src}/debugging/tutorial001.py | 0 .../dependencies/tutorial001.py | 0 .../dependencies/tutorial002.py | 0 .../dependencies/tutorial003.py | 0 .../dependencies/tutorial004.py | 0 .../dependencies/tutorial005.py | 0 .../dependencies/tutorial006.py | 0 .../dependencies/tutorial007.py | 0 .../dependencies/tutorial008.py | 0 .../dependencies/tutorial009.py | 0 .../dependencies/tutorial010.py | 0 .../dependencies/tutorial011.py | 0 .../dependency_testing/tutorial001.py | 0 {docs/src => docs_src}/encoder/tutorial001.py | 0 {docs/src => docs_src}/events/tutorial001.py | 0 {docs/src => docs_src}/events/tutorial002.py | 0 .../extending_openapi/tutorial001.py | 0 .../extending_openapi/tutorial002.py | 0 .../extra_data_types/tutorial001.py | 0 .../extra_models/tutorial001.py | 0 .../extra_models/tutorial002.py | 0 .../extra_models/tutorial003.py | 0 .../extra_models/tutorial004.py | 0 .../extra_models/tutorial005.py | 0 .../first_steps/tutorial001.py | 0 .../first_steps/tutorial002.py | 0 .../first_steps/tutorial003.py | 0 {docs/src => docs_src}/graphql/tutorial001.py | 0 .../handling_errors/tutorial001.py | 0 .../handling_errors/tutorial002.py | 0 .../handling_errors/tutorial003.py | 0 .../handling_errors/tutorial004.py | 0 .../handling_errors/tutorial005.py | 0 .../handling_errors/tutorial006.py | 0 .../header_params/tutorial001.py | 0 .../header_params/tutorial002.py | 0 .../header_params/tutorial003.py | 0 .../middleware/tutorial001.py | 0 .../nosql_databases/tutorial001.py | 0 .../openapi_callbacks/tutorial001.py | 0 .../tutorial001.py | 0 .../tutorial002.py | 0 .../tutorial003.py | 0 .../tutorial004.py | 0 .../tutorial001.py | 0 .../tutorial002.py | 0 .../tutorial003.py | 0 .../tutorial004.py | 0 .../tutorial005.py | 0 .../tutorial006.py | 0 .../path_params/tutorial001.py | 0 .../path_params/tutorial002.py | 0 .../path_params/tutorial003.py | 0 .../path_params/tutorial004.py | 0 .../path_params/tutorial005.py | 0 .../tutorial001.py | 0 .../tutorial002.py | 0 .../tutorial003.py | 0 .../tutorial004.py | 0 .../tutorial005.py | 0 .../tutorial006.py | 0 .../python_types/tutorial001.py | 0 .../python_types/tutorial002.py | 0 .../python_types/tutorial003.py | 0 .../python_types/tutorial004.py | 0 .../python_types/tutorial005.py | 0 .../python_types/tutorial006.py | 0 .../python_types/tutorial007.py | 0 .../python_types/tutorial008.py | 0 .../python_types/tutorial009.py | 0 .../python_types/tutorial010.py | 0 .../query_params/tutorial001.py | 0 .../query_params/tutorial002.py | 0 .../query_params/tutorial003.py | 0 .../query_params/tutorial004.py | 0 .../query_params/tutorial005.py | 0 .../query_params/tutorial006.py | 0 .../query_params/tutorial007.py | 0 .../tutorial001.py | 0 .../tutorial002.py | 0 .../tutorial003.py | 0 .../tutorial004.py | 0 .../tutorial005.py | 0 .../tutorial006.py | 0 .../tutorial007.py | 0 .../tutorial008.py | 0 .../tutorial009.py | 0 .../tutorial010.py | 0 .../tutorial011.py | 0 .../tutorial012.py | 0 .../tutorial013.py | 0 .../request_files/tutorial001.py | 0 .../request_files/tutorial002.py | 0 .../request_forms/tutorial001.py | 0 .../request_forms_and_files/tutorial001.py | 0 .../tutorial001.py | 0 .../response_cookies/tutorial001.py | 0 .../response_cookies/tutorial002.py | 0 .../response_directly/tutorial001.py | 0 .../response_directly/tutorial002.py | 0 .../response_headers/tutorial001.py | 0 .../response_headers/tutorial002.py | 0 .../response_model/tutorial001.py | 0 .../response_model/tutorial002.py | 0 .../response_model/tutorial003.py | 0 .../response_model/tutorial004.py | 0 .../response_model/tutorial005.py | 0 .../response_model/tutorial006.py | 0 .../response_status_code/tutorial001.py | 0 .../response_status_code/tutorial002.py | 0 .../src => docs_src}/security/tutorial001.py | 0 .../src => docs_src}/security/tutorial002.py | 0 .../src => docs_src}/security/tutorial003.py | 0 .../src => docs_src}/security/tutorial004.py | 0 .../src => docs_src}/security/tutorial005.py | 0 .../src => docs_src}/security/tutorial006.py | 0 .../src => docs_src}/security/tutorial007.py | 0 .../sql_databases/__init__.py | 0 .../sql_databases/sql_app/__init__.py | 0 .../sql_databases/sql_app/alt_main.py | 0 .../sql_databases/sql_app/crud.py | 0 .../sql_databases/sql_app/database.py | 0 .../sql_databases/sql_app/main.py | 0 .../sql_databases/sql_app/models.py | 0 .../sql_databases/sql_app/schemas.py | 0 .../sql_databases_peewee/__init__.py | 0 .../sql_databases_peewee/sql_app/__init__.py | 0 .../sql_databases_peewee/sql_app/crud.py | 0 .../sql_databases_peewee/sql_app/database.py | 0 .../sql_databases_peewee/sql_app/main.py | 0 .../sql_databases_peewee/sql_app/models.py | 0 .../sql_databases_peewee/sql_app/schemas.py | 0 .../static_files/tutorial001.py | 0 .../sub_applications/tutorial001.py | 0 .../templates/static/styles.css | 0 .../templates/templates/item.html | 0 .../src => docs_src}/templates/tutorial001.py | 0 .../using_request_directly/tutorial001.py | 0 {docs/src => docs_src}/websockets/__init__.py | 0 .../websockets/tutorial001.py | 0 .../websockets/tutorial002.py | 0 {docs/src => docs_src}/wsgi/tutorial001.py | 0 mkdocs.yml | 150 ------ pyproject.toml | 5 +- scripts/build-docs.sh | 5 +- scripts/docs.py | 340 ++++++++++++++ scripts/format-imports.sh | 2 +- scripts/format.sh | 6 +- scripts/test.sh | 6 +- .../test_tutorial002.py | 2 +- .../test_tutorial004.py | 2 +- .../test_templates/test_tutorial001.py | 4 +- 391 files changed, 1955 insertions(+), 693 deletions(-) delete mode 100644 docs/contributing.md rename docs/{ => en/docs}/advanced/additional-responses.md (97%) rename docs/{ => en/docs}/advanced/additional-status-codes.md (95%) rename docs/{ => en/docs}/advanced/advanced-dependencies.md (91%) rename docs/{ => en/docs}/advanced/async-sql-databases.md (90%) rename docs/{ => en/docs}/advanced/custom-request-and-route.md (91%) rename docs/{ => en/docs}/advanced/custom-response.md (92%) rename docs/{ => en/docs}/advanced/events.md (91%) rename docs/{ => en/docs}/advanced/extending-openapi.md (94%) rename docs/{ => en/docs}/advanced/graphql.md (93%) rename docs/{ => en/docs}/advanced/index.md (95%) rename docs/{ => en/docs}/advanced/middleware.md (95%) rename docs/{ => en/docs}/advanced/nosql-databases.md (91%) rename docs/{ => en/docs}/advanced/openapi-callbacks.md (97%) rename docs/{ => en/docs}/advanced/path-operation-advanced-configuration.md (82%) rename docs/{ => en/docs}/advanced/response-change-status-code.md (93%) rename docs/{ => en/docs}/advanced/response-cookies.md (94%) rename docs/{ => en/docs}/advanced/response-directly.md (95%) rename docs/{ => en/docs}/advanced/response-headers.md (94%) rename docs/{ => en/docs}/advanced/security/http-basic-auth.md (96%) rename docs/{ => en/docs}/advanced/security/index.md (95%) rename docs/{ => en/docs}/advanced/security/oauth2-scopes.md (97%) rename docs/{ => en/docs}/advanced/sql-databases-peewee.md (95%) rename docs/{ => en/docs}/advanced/sub-applications-proxy.md (94%) rename docs/{ => en/docs}/advanced/templates.md (91%) rename docs/{ => en/docs}/advanced/testing-dependencies.md (96%) rename docs/{ => en/docs}/advanced/testing-events.md (67%) rename docs/{ => en/docs}/advanced/testing-websockets.md (72%) rename docs/{ => en/docs}/advanced/using-request-directly.md (96%) rename docs/{ => en/docs}/advanced/websockets.md (94%) rename docs/{ => en/docs}/advanced/wsgi.md (92%) rename docs/{ => en/docs}/alternatives.md (99%) rename docs/{ => en/docs}/async.md (99%) rename docs/{ => en/docs}/benchmarks.md (99%) create mode 100644 docs/en/docs/contributing.md rename docs/{ => en/docs}/css/custom.css (100%) rename docs/{ => en/docs}/css/termynal.css (100%) rename docs/{ => en/docs}/deployment.md (99%) rename docs/{ => en/docs}/external-links.md (99%) rename docs/{ => en/docs}/features.md (96%) rename docs/{ => en/docs}/help-fastapi.md (99%) rename docs/{ => en/docs}/history-design-future.md (99%) rename docs/{ => en/docs}/img/favicon.png (100%) rename docs/{ => en/docs}/img/github-social-preview.png (100%) rename docs/{ => en/docs}/img/github-social-preview.svg (100%) rename docs/{ => en/docs}/img/icon-transparent-bg.png (100%) rename docs/{ => en/docs}/img/icon-white-bg.png (100%) rename docs/{ => en/docs}/img/icon-white.svg (100%) rename docs/{ => en/docs}/img/index/index-01-swagger-ui-simple.png (100%) rename docs/{ => en/docs}/img/index/index-02-redoc-simple.png (100%) rename docs/{ => en/docs}/img/index/index-03-swagger-02.png (100%) rename docs/{ => en/docs}/img/index/index-04-swagger-03.png (100%) rename docs/{ => en/docs}/img/index/index-05-swagger-04.png (100%) rename docs/{ => en/docs}/img/index/index-06-redoc-02.png (100%) rename docs/{ => en/docs}/img/logo-margin/logo-teal-vector.svg (100%) rename docs/{ => en/docs}/img/logo-margin/logo-teal.png (100%) rename docs/{ => en/docs}/img/logo-margin/logo-teal.svg (100%) rename docs/{ => en/docs}/img/logo-margin/logo-white-bg.png (100%) rename docs/{ => en/docs}/img/logo-teal-vector.svg (100%) rename docs/{ => en/docs}/img/logo-teal.svg (100%) rename docs/{ => en/docs}/img/pycharm-completion.png (100%) rename docs/{ => en/docs}/img/python-types/image01.png (100%) rename docs/{ => en/docs}/img/python-types/image02.png (100%) rename docs/{ => en/docs}/img/python-types/image03.png (100%) rename docs/{ => en/docs}/img/python-types/image04.png (100%) rename docs/{ => en/docs}/img/python-types/image05.png (100%) rename docs/{ => en/docs}/img/python-types/image06.png (100%) rename docs/{ => en/docs}/img/tutorial/additional-responses/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/application-configuration/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/async-sql-databases/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/bigger-applications/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/body-fields/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/body-nested-models/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/body/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/body/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/body/image03.png (100%) rename docs/{ => en/docs}/img/tutorial/body/image04.png (100%) rename docs/{ => en/docs}/img/tutorial/body/image05.png (100%) rename docs/{ => en/docs}/img/tutorial/custom-response/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/debugging/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/dependencies/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/dependencies/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/extending-openapi/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/graphql/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/openapi-callbacks/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/path-operation-configuration/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/path-operation-configuration/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/path-operation-configuration/image03.png (100%) rename docs/{ => en/docs}/img/tutorial/path-operation-configuration/image04.png (100%) rename docs/{ => en/docs}/img/tutorial/path-operation-configuration/image05.png (100%) rename docs/{ => en/docs}/img/tutorial/path-params/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/path-params/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/path-params/image03.png (100%) rename docs/{ => en/docs}/img/tutorial/query-params-str-validations/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/query-params-str-validations/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/response-model/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/response-model/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/response-status-code/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/response-status-code/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image03.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image04.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image05.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image06.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image07.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image08.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image09.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image10.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image11.png (100%) rename docs/{ => en/docs}/img/tutorial/security/image12.png (100%) rename docs/{ => en/docs}/img/tutorial/sql-databases/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/sql-databases/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/sub-applications/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/sub-applications/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/websockets/image01.png (100%) rename docs/{ => en/docs}/img/tutorial/websockets/image02.png (100%) rename docs/{ => en/docs}/img/tutorial/websockets/image03.png (100%) rename docs/{ => en/docs}/img/tutorial/websockets/image04.png (100%) rename docs/{ => en/docs}/img/vscode-completion.png (100%) rename docs/{ => en/docs}/index.md (100%) rename docs/{ => en/docs}/js/custom.js (100%) rename docs/{ => en/docs}/js/termynal.js (100%) rename docs/{ => en/docs}/project-generation.md (99%) rename docs/{ => en/docs}/python-types.md (92%) rename docs/{ => en/docs}/release-notes.md (99%) rename docs/{ => en/docs}/tutorial/application-configuration.md (87%) rename docs/{ => en/docs}/tutorial/background-tasks.md (95%) rename docs/{ => en/docs}/tutorial/bigger-applications.md (95%) rename docs/{ => en/docs}/tutorial/body-fields.md (93%) rename docs/{ => en/docs}/tutorial/body-multiple-params.md (93%) rename docs/{ => en/docs}/tutorial/body-nested-models.md (90%) rename docs/{ => en/docs}/tutorial/body-updates.md (94%) rename docs/{ => en/docs}/tutorial/body.md (95%) rename docs/{ => en/docs}/tutorial/cookie-params.md (88%) rename docs/{ => en/docs}/tutorial/cors.md (98%) rename docs/{ => en/docs}/tutorial/debugging.md (97%) rename docs/{ => en/docs}/tutorial/dependencies/classes-as-dependencies.md (93%) rename docs/{ => en/docs}/tutorial/dependencies/dependencies-in-path-operation-decorators.md (89%) rename docs/{ => en/docs}/tutorial/dependencies/dependencies-with-yield.md (96%) rename docs/{ => en/docs}/tutorial/dependencies/index.md (97%) rename docs/{ => en/docs}/tutorial/dependencies/sub-dependencies.md (95%) rename docs/{ => en/docs}/tutorial/encoder.md (95%) rename docs/{ => en/docs}/tutorial/extra-data-types.md (94%) rename docs/{ => en/docs}/tutorial/extra-models.md (95%) rename docs/{ => en/docs}/tutorial/first-steps.md (95%) rename docs/{ => en/docs}/tutorial/handling-errors.md (95%) rename docs/{ => en/docs}/tutorial/header-params.md (92%) rename docs/{ => en/docs}/tutorial/index.md (98%) rename docs/{ => en/docs}/tutorial/middleware.md (96%) rename docs/{ => en/docs}/tutorial/path-operation-configuration.md (88%) rename docs/{ => en/docs}/tutorial/path-params-numeric-validations.md (89%) rename docs/{ => en/docs}/tutorial/path-params.md (94%) rename docs/{ => en/docs}/tutorial/query-params-str-validations.md (87%) rename docs/{ => en/docs}/tutorial/query-params.md (92%) rename docs/{ => en/docs}/tutorial/request-files.md (96%) rename docs/{ => en/docs}/tutorial/request-forms-and-files.md (88%) rename docs/{ => en/docs}/tutorial/request-forms.md (95%) rename docs/{ => en/docs}/tutorial/response-model.md (92%) rename docs/{ => en/docs}/tutorial/response-status-code.md (94%) rename docs/{ => en/docs}/tutorial/security/first-steps.md (97%) rename docs/{ => en/docs}/tutorial/security/get-current-user.md (92%) rename docs/{ => en/docs}/tutorial/security/index.md (99%) rename docs/{ => en/docs}/tutorial/security/oauth2-jwt.md (97%) rename docs/{ => en/docs}/tutorial/security/simple-oauth2.md (97%) rename docs/{ => en/docs}/tutorial/sql-databases.md (95%) rename docs/{ => en/docs}/tutorial/static-files.md (96%) rename docs/{ => en/docs}/tutorial/testing.md (94%) create mode 100644 docs/en/mkdocs.yml create mode 100644 docs/es/docs/index.md create mode 100644 docs/es/mkdocs.yml create mode 100644 docs/missing-translation.md rename {docs/src => docs_src}/additional_responses/tutorial001.py (100%) rename {docs/src => docs_src}/additional_responses/tutorial002.py (100%) rename {docs/src => docs_src}/additional_responses/tutorial003.py (100%) rename {docs/src => docs_src}/additional_responses/tutorial004.py (100%) rename {docs/src => docs_src}/additional_status_codes/tutorial001.py (100%) rename {docs/src => docs_src}/advanced_middleware/tutorial001.py (100%) rename {docs/src => docs_src}/advanced_middleware/tutorial002.py (100%) rename {docs/src => docs_src}/advanced_middleware/tutorial003.py (100%) rename {docs/src => docs_src}/app_testing/__init__.py (100%) rename {docs/src => docs_src}/app_testing/main.py (100%) rename {docs/src => docs_src}/app_testing/main_b.py (100%) rename {docs/src => docs_src}/app_testing/test_main.py (100%) rename {docs/src => docs_src}/app_testing/test_main_b.py (100%) rename {docs/src => docs_src}/app_testing/tutorial001.py (100%) rename {docs/src => docs_src}/app_testing/tutorial002.py (100%) rename {docs/src => docs_src}/app_testing/tutorial003.py (100%) rename {docs/src => docs_src}/application_configuration/tutorial001.py (100%) rename {docs/src => docs_src}/application_configuration/tutorial002.py (100%) rename {docs/src => docs_src}/application_configuration/tutorial003.py (100%) rename {docs/src => docs_src}/async_sql_databases/tutorial001.py (100%) rename {docs/src => docs_src}/background_tasks/tutorial001.py (100%) rename {docs/src => docs_src}/background_tasks/tutorial002.py (100%) rename {docs/src => docs_src}/bigger_applications/__init__.py (100%) rename {docs/src => docs_src}/bigger_applications/app/__init__.py (100%) rename {docs/src => docs_src}/bigger_applications/app/main.py (100%) rename {docs/src => docs_src}/bigger_applications/app/routers/__init__.py (100%) rename {docs/src => docs_src}/bigger_applications/app/routers/items.py (100%) rename {docs/src => docs_src}/bigger_applications/app/routers/users.py (100%) rename {docs/src => docs_src}/body/tutorial001.py (100%) rename {docs/src => docs_src}/body/tutorial002.py (100%) rename {docs/src => docs_src}/body/tutorial003.py (100%) rename {docs/src => docs_src}/body/tutorial004.py (100%) rename {docs/src => docs_src}/body_fields/tutorial001.py (100%) rename {docs/src => docs_src}/body_fields/tutorial002.py (100%) rename {docs/src => docs_src}/body_multiple_params/tutorial001.py (100%) rename {docs/src => docs_src}/body_multiple_params/tutorial002.py (100%) rename {docs/src => docs_src}/body_multiple_params/tutorial003.py (100%) rename {docs/src => docs_src}/body_multiple_params/tutorial004.py (100%) rename {docs/src => docs_src}/body_multiple_params/tutorial005.py (100%) rename {docs/src => docs_src}/body_nested_models/tutorial001.py (100%) rename {docs/src => docs_src}/body_nested_models/tutorial002.py (100%) rename {docs/src => docs_src}/body_nested_models/tutorial003.py (100%) rename {docs/src => docs_src}/body_nested_models/tutorial004.py (100%) rename {docs/src => docs_src}/body_nested_models/tutorial005.py (100%) rename {docs/src => docs_src}/body_nested_models/tutorial006.py (100%) rename {docs/src => docs_src}/body_nested_models/tutorial007.py (100%) rename {docs/src => docs_src}/body_nested_models/tutorial008.py (100%) rename {docs/src => docs_src}/body_nested_models/tutorial009.py (100%) rename {docs/src => docs_src}/body_updates/tutorial001.py (100%) rename {docs/src => docs_src}/body_updates/tutorial002.py (100%) rename {docs/src => docs_src}/cookie_params/tutorial001.py (100%) rename {docs/src => docs_src}/cors/tutorial001.py (100%) rename {docs/src => docs_src}/custom_request_and_route/tutorial001.py (100%) rename {docs/src => docs_src}/custom_request_and_route/tutorial002.py (100%) rename {docs/src => docs_src}/custom_request_and_route/tutorial003.py (100%) rename {docs/src => docs_src}/custom_response/tutorial001.py (100%) rename {docs/src => docs_src}/custom_response/tutorial001b.py (100%) rename {docs/src => docs_src}/custom_response/tutorial002.py (100%) rename {docs/src => docs_src}/custom_response/tutorial003.py (100%) rename {docs/src => docs_src}/custom_response/tutorial004.py (100%) rename {docs/src => docs_src}/custom_response/tutorial005.py (100%) rename {docs/src => docs_src}/custom_response/tutorial006.py (100%) rename {docs/src => docs_src}/custom_response/tutorial007.py (100%) rename {docs/src => docs_src}/custom_response/tutorial008.py (100%) rename {docs/src => docs_src}/custom_response/tutorial009.py (100%) rename {docs/src => docs_src}/debugging/tutorial001.py (100%) rename {docs/src => docs_src}/dependencies/tutorial001.py (100%) rename {docs/src => docs_src}/dependencies/tutorial002.py (100%) rename {docs/src => docs_src}/dependencies/tutorial003.py (100%) rename {docs/src => docs_src}/dependencies/tutorial004.py (100%) rename {docs/src => docs_src}/dependencies/tutorial005.py (100%) rename {docs/src => docs_src}/dependencies/tutorial006.py (100%) rename {docs/src => docs_src}/dependencies/tutorial007.py (100%) rename {docs/src => docs_src}/dependencies/tutorial008.py (100%) rename {docs/src => docs_src}/dependencies/tutorial009.py (100%) rename {docs/src => docs_src}/dependencies/tutorial010.py (100%) rename {docs/src => docs_src}/dependencies/tutorial011.py (100%) rename {docs/src => docs_src}/dependency_testing/tutorial001.py (100%) rename {docs/src => docs_src}/encoder/tutorial001.py (100%) rename {docs/src => docs_src}/events/tutorial001.py (100%) rename {docs/src => docs_src}/events/tutorial002.py (100%) rename {docs/src => docs_src}/extending_openapi/tutorial001.py (100%) rename {docs/src => docs_src}/extending_openapi/tutorial002.py (100%) rename {docs/src => docs_src}/extra_data_types/tutorial001.py (100%) rename {docs/src => docs_src}/extra_models/tutorial001.py (100%) rename {docs/src => docs_src}/extra_models/tutorial002.py (100%) rename {docs/src => docs_src}/extra_models/tutorial003.py (100%) rename {docs/src => docs_src}/extra_models/tutorial004.py (100%) rename {docs/src => docs_src}/extra_models/tutorial005.py (100%) rename {docs/src => docs_src}/first_steps/tutorial001.py (100%) rename {docs/src => docs_src}/first_steps/tutorial002.py (100%) rename {docs/src => docs_src}/first_steps/tutorial003.py (100%) rename {docs/src => docs_src}/graphql/tutorial001.py (100%) rename {docs/src => docs_src}/handling_errors/tutorial001.py (100%) rename {docs/src => docs_src}/handling_errors/tutorial002.py (100%) rename {docs/src => docs_src}/handling_errors/tutorial003.py (100%) rename {docs/src => docs_src}/handling_errors/tutorial004.py (100%) rename {docs/src => docs_src}/handling_errors/tutorial005.py (100%) rename {docs/src => docs_src}/handling_errors/tutorial006.py (100%) rename {docs/src => docs_src}/header_params/tutorial001.py (100%) rename {docs/src => docs_src}/header_params/tutorial002.py (100%) rename {docs/src => docs_src}/header_params/tutorial003.py (100%) rename {docs/src => docs_src}/middleware/tutorial001.py (100%) rename {docs/src => docs_src}/nosql_databases/tutorial001.py (100%) rename {docs/src => docs_src}/openapi_callbacks/tutorial001.py (100%) rename {docs/src => docs_src}/path_operation_advanced_configuration/tutorial001.py (100%) rename {docs/src => docs_src}/path_operation_advanced_configuration/tutorial002.py (100%) rename {docs/src => docs_src}/path_operation_advanced_configuration/tutorial003.py (100%) rename {docs/src => docs_src}/path_operation_advanced_configuration/tutorial004.py (100%) rename {docs/src => docs_src}/path_operation_configuration/tutorial001.py (100%) rename {docs/src => docs_src}/path_operation_configuration/tutorial002.py (100%) rename {docs/src => docs_src}/path_operation_configuration/tutorial003.py (100%) rename {docs/src => docs_src}/path_operation_configuration/tutorial004.py (100%) rename {docs/src => docs_src}/path_operation_configuration/tutorial005.py (100%) rename {docs/src => docs_src}/path_operation_configuration/tutorial006.py (100%) rename {docs/src => docs_src}/path_params/tutorial001.py (100%) rename {docs/src => docs_src}/path_params/tutorial002.py (100%) rename {docs/src => docs_src}/path_params/tutorial003.py (100%) rename {docs/src => docs_src}/path_params/tutorial004.py (100%) rename {docs/src => docs_src}/path_params/tutorial005.py (100%) rename {docs/src => docs_src}/path_params_numeric_validations/tutorial001.py (100%) rename {docs/src => docs_src}/path_params_numeric_validations/tutorial002.py (100%) rename {docs/src => docs_src}/path_params_numeric_validations/tutorial003.py (100%) rename {docs/src => docs_src}/path_params_numeric_validations/tutorial004.py (100%) rename {docs/src => docs_src}/path_params_numeric_validations/tutorial005.py (100%) rename {docs/src => docs_src}/path_params_numeric_validations/tutorial006.py (100%) rename {docs/src => docs_src}/python_types/tutorial001.py (100%) rename {docs/src => docs_src}/python_types/tutorial002.py (100%) rename {docs/src => docs_src}/python_types/tutorial003.py (100%) rename {docs/src => docs_src}/python_types/tutorial004.py (100%) rename {docs/src => docs_src}/python_types/tutorial005.py (100%) rename {docs/src => docs_src}/python_types/tutorial006.py (100%) rename {docs/src => docs_src}/python_types/tutorial007.py (100%) rename {docs/src => docs_src}/python_types/tutorial008.py (100%) rename {docs/src => docs_src}/python_types/tutorial009.py (100%) rename {docs/src => docs_src}/python_types/tutorial010.py (100%) rename {docs/src => docs_src}/query_params/tutorial001.py (100%) rename {docs/src => docs_src}/query_params/tutorial002.py (100%) rename {docs/src => docs_src}/query_params/tutorial003.py (100%) rename {docs/src => docs_src}/query_params/tutorial004.py (100%) rename {docs/src => docs_src}/query_params/tutorial005.py (100%) rename {docs/src => docs_src}/query_params/tutorial006.py (100%) rename {docs/src => docs_src}/query_params/tutorial007.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial001.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial002.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial003.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial004.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial005.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial006.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial007.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial008.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial009.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial010.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial011.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial012.py (100%) rename {docs/src => docs_src}/query_params_str_validations/tutorial013.py (100%) rename {docs/src => docs_src}/request_files/tutorial001.py (100%) rename {docs/src => docs_src}/request_files/tutorial002.py (100%) rename {docs/src => docs_src}/request_forms/tutorial001.py (100%) rename {docs/src => docs_src}/request_forms_and_files/tutorial001.py (100%) rename {docs/src => docs_src}/response_change_status_code/tutorial001.py (100%) rename {docs/src => docs_src}/response_cookies/tutorial001.py (100%) rename {docs/src => docs_src}/response_cookies/tutorial002.py (100%) rename {docs/src => docs_src}/response_directly/tutorial001.py (100%) rename {docs/src => docs_src}/response_directly/tutorial002.py (100%) rename {docs/src => docs_src}/response_headers/tutorial001.py (100%) rename {docs/src => docs_src}/response_headers/tutorial002.py (100%) rename {docs/src => docs_src}/response_model/tutorial001.py (100%) rename {docs/src => docs_src}/response_model/tutorial002.py (100%) rename {docs/src => docs_src}/response_model/tutorial003.py (100%) rename {docs/src => docs_src}/response_model/tutorial004.py (100%) rename {docs/src => docs_src}/response_model/tutorial005.py (100%) rename {docs/src => docs_src}/response_model/tutorial006.py (100%) rename {docs/src => docs_src}/response_status_code/tutorial001.py (100%) rename {docs/src => docs_src}/response_status_code/tutorial002.py (100%) rename {docs/src => docs_src}/security/tutorial001.py (100%) rename {docs/src => docs_src}/security/tutorial002.py (100%) rename {docs/src => docs_src}/security/tutorial003.py (100%) rename {docs/src => docs_src}/security/tutorial004.py (100%) rename {docs/src => docs_src}/security/tutorial005.py (100%) rename {docs/src => docs_src}/security/tutorial006.py (100%) rename {docs/src => docs_src}/security/tutorial007.py (100%) rename {docs/src => docs_src}/sql_databases/__init__.py (100%) rename {docs/src => docs_src}/sql_databases/sql_app/__init__.py (100%) rename {docs/src => docs_src}/sql_databases/sql_app/alt_main.py (100%) rename {docs/src => docs_src}/sql_databases/sql_app/crud.py (100%) rename {docs/src => docs_src}/sql_databases/sql_app/database.py (100%) rename {docs/src => docs_src}/sql_databases/sql_app/main.py (100%) rename {docs/src => docs_src}/sql_databases/sql_app/models.py (100%) rename {docs/src => docs_src}/sql_databases/sql_app/schemas.py (100%) rename {docs/src => docs_src}/sql_databases_peewee/__init__.py (100%) rename {docs/src => docs_src}/sql_databases_peewee/sql_app/__init__.py (100%) rename {docs/src => docs_src}/sql_databases_peewee/sql_app/crud.py (100%) rename {docs/src => docs_src}/sql_databases_peewee/sql_app/database.py (100%) rename {docs/src => docs_src}/sql_databases_peewee/sql_app/main.py (100%) rename {docs/src => docs_src}/sql_databases_peewee/sql_app/models.py (100%) rename {docs/src => docs_src}/sql_databases_peewee/sql_app/schemas.py (100%) rename {docs/src => docs_src}/static_files/tutorial001.py (100%) rename {docs/src => docs_src}/sub_applications/tutorial001.py (100%) rename {docs/src => docs_src}/templates/static/styles.css (100%) rename {docs/src => docs_src}/templates/templates/item.html (100%) rename {docs/src => docs_src}/templates/tutorial001.py (100%) rename {docs/src => docs_src}/using_request_directly/tutorial001.py (100%) rename {docs/src => docs_src}/websockets/__init__.py (100%) rename {docs/src => docs_src}/websockets/tutorial001.py (100%) rename {docs/src => docs_src}/websockets/tutorial002.py (100%) rename {docs/src => docs_src}/wsgi/tutorial001.py (100%) delete mode 100644 mkdocs.yml create mode 100644 scripts/docs.py diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 77f1c274c..60f8e4b4a 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -16,8 +16,8 @@ jobs: run: python3.7 -m pip install flit - name: Install docs extras run: python3.7 -m flit install --extras doc - - name: Build MkDocs - run: python3.7 -m mkdocs build + - name: Build Docs + run: python3.7 ./scripts/docs.py build-all - name: Deploy to Netlify uses: nwtgck/actions-netlify@v1.0.3 with: diff --git a/.gitignore b/.gitignore index f110dc597..3dbfdd44d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ test.db log.txt Pipfile.lock env3.* +docs_build diff --git a/docs/contributing.md b/docs/contributing.md deleted file mode 100644 index 4ca50db9e..000000000 --- a/docs/contributing.md +++ /dev/null @@ -1,176 +0,0 @@ -First, you might want to see the basic ways to [help FastAPI and get help](help-fastapi.md){.internal-link target=_blank}. - -## Developing - -If you already cloned the repository and you know that you need to deep dive in the code, here are some guidelines to set up your environment. - -### Virtual environment with `venv` - -You can create a virtual environment in a directory using Python's `venv` module: - -```console -$ python -m venv env -``` - -That will create a directory `./env/` with the Python binaries and then you will be able to install packages for that isolated environment. - -### Activate the environment - -Activate the new environment with: - -```console -$ source ./env/bin/activate -``` - -Or in Windows' PowerShell: - -```console -$ .\env\Scripts\Activate.ps1 -``` - -Or if you use Bash for Windows (e.g. Git Bash): - -```console -$ source ./env/Scripts/activate -``` - -To check it worked, use: - -```console -$ which pip - -some/directory/fastapi/env/bin/pip -``` - -If it shows the `pip` binary at `env/bin/pip` then it worked. 🎉 - -Or in Windows PowerShell: - -```console -$ Get-Command pip - -some/directory/fastapi/env/bin/pip -``` - -!!! tip - Every time you install a new package with `pip` under that environment, activate the environment again. - - This makes sure that if you use a terminal program installed by that package (like `flit`), you use the one from your local environment and not any other that could be installed globally. - -### Flit - -**FastAPI** uses Flit to build, package and publish the project. - -After activating the environment as described above, install `flit`: - -```console -$ pip install flit -``` - -Now re-activate the environment to make sure you are using the `flit` you just installed (and not a global one). - -And now use `flit` to install the development dependencies: - -```console -$ flit install --deps develop --symlink -``` - -It will install all the dependencies and your local FastAPI in your local environment. - -#### Using your local FastAPI - -If you create a Python file that imports and uses FastAPI, and run it with the Python from your local environment, it will use your local FastAPI source code. - -And if you update that local FastAPI source code, as it is installed with `--symlink`, when you run that Python file again, it will use the fresh version of FastAPI you just edited. - -That way, you don't have to "install" your local version to be able to test every change. - -### Format - -There is a script that you can run that will format and clean all your code: - -```console -$ bash scripts/format.sh -``` - -It will also auto-sort all your imports. - -For it to sort them correctly, you need to have FastAPI installed locally in your environment, with the command in the section above: - -```console -$ flit install --symlink -``` - -### Format imports - -There is another script that formats all the imports and makes sure you don't have unused imports: - -```console -$ bash scripts/format-imports.sh -``` - -As it runs one command after the other and modifies and reverts many files, it takes a bit longer to run, so it might be easier to use `scripts/format.sh` frequently and `scripts/format-imports.sh` only before committing. - -## Docs - -The documentation uses MkDocs. - -All the documentation is in Markdown format in the directory `./docs`. - -Many of the tutorials have blocks of code. - -In most of the cases, these blocks of code are actual complete applications that can be run as is. - -In fact, those blocks of code are not written inside the Markdown, they are Python files in the `./docs/src/` directory. - -And those Python files are included/injected in the documentation when generating the site. - -### Docs for tests - -Most of the tests actually run against the example source files in the documentation. - -This helps making sure that: - -* The documentation is up to date. -* The documentation examples can be run as is. -* Most of the features are covered by the documentation, ensured by test coverage. - -During local development, there is a script that builds the site and checks for any changes, live-reloading: - -```console -$ bash scripts/docs-live.sh -``` - -It will serve the documentation on `http://0.0.0.0:8008`. - -That way, you can edit the documentation/source files and see the changes live. - -### Apps and docs at the same time - -If you run the examples with, e.g.: - -```console -$ uvicorn tutorial001:app --reload -``` - -as Uvicorn by default will use the port `8000`, the documentation on port `8008` won't clash. - -## Tests - -There is a script that you can run locally to test all the code and generate coverage reports in HTML: - -```console -$ bash scripts/test-cov-html.sh -``` - -This command generates a directory `./htmlcov/`, if you open the file `./htmlcov/index.html` in your browser, you can explore interactively the regions of code that are covered by the tests, and notice if there is any region missing. - -### Tests in your editor - -If you want to use the integrated tests in your editor add `./docs/src` to your `PYTHONPATH` variable. - -For example, in VS Code you can create a file `.env` with: - -```env -PYTHONPATH=./docs/src -``` diff --git a/docs/advanced/additional-responses.md b/docs/en/docs/advanced/additional-responses.md similarity index 97% rename from docs/advanced/additional-responses.md rename to docs/en/docs/advanced/additional-responses.md index 71c4cf61d..4b2abaada 100644 --- a/docs/advanced/additional-responses.md +++ b/docs/en/docs/advanced/additional-responses.md @@ -1,3 +1,5 @@ +# Additional Responses in OpenAPI + !!! warning This is a rather advanced topic. @@ -22,7 +24,7 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write: ```Python hl_lines="18 23" -{!./src/additional_responses/tutorial001.py!} +{!../../../docs_src/additional_responses/tutorial001.py!} ``` !!! note @@ -167,7 +169,7 @@ You can use this same `responses` parameter to add different media types for the For example, you can add an additional media type of `image/png`, declaring that your *path operation* can return a JSON object (with media type `application/json`) or a PNG image: ```Python hl_lines="17 18 19 20 21 22 23 24 28" -{!./src/additional_responses/tutorial002.py!} +{!../../../docs_src/additional_responses/tutorial002.py!} ``` !!! note @@ -191,7 +193,7 @@ For example, you can declare a response with a status code `404` that uses a Pyd And a response with a status code `200` that uses your `response_model`, but includes a custom `example`: ```Python hl_lines="20 21 22 23 24 25 26 27 28 29 30 31" -{!./src/additional_responses/tutorial003.py!} +{!../../../docs_src/additional_responses/tutorial003.py!} ``` It will all be combined and included in your OpenAPI, and shown in the API docs: @@ -227,7 +229,7 @@ You can use that technique to re-use some predefined responses in your *path ope For example: ```Python hl_lines="11 12 13 14 15 24" -{!./src/additional_responses/tutorial004.py!} +{!../../../docs_src/additional_responses/tutorial004.py!} ``` ## More information about OpenAPI responses diff --git a/docs/advanced/additional-status-codes.md b/docs/en/docs/advanced/additional-status-codes.md similarity index 95% rename from docs/advanced/additional-status-codes.md rename to docs/en/docs/advanced/additional-status-codes.md index 14a867c98..b9a32cfa3 100644 --- a/docs/advanced/additional-status-codes.md +++ b/docs/en/docs/advanced/additional-status-codes.md @@ -1,3 +1,5 @@ +# Additional Status Codes + By default, **FastAPI** will return the responses using a `JSONResponse`, putting the content you return from your *path operation* inside of that `JSONResponse`. It will use the default status code or the one you set in your *path operation*. @@ -13,7 +15,7 @@ But you also want it to accept new items. And when the items didn't exist before To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want: ```Python hl_lines="2 19" -{!./src/additional_status_codes/tutorial001.py!} +{!../../../docs_src/additional_status_codes/tutorial001.py!} ``` !!! warning diff --git a/docs/advanced/advanced-dependencies.md b/docs/en/docs/advanced/advanced-dependencies.md similarity index 91% rename from docs/advanced/advanced-dependencies.md rename to docs/en/docs/advanced/advanced-dependencies.md index ec796362a..5e79776ca 100644 --- a/docs/advanced/advanced-dependencies.md +++ b/docs/en/docs/advanced/advanced-dependencies.md @@ -1,3 +1,5 @@ +# Advanced Dependencies + ## Parameterized dependencies All the dependencies we have seen are a fixed function or class. @@ -17,7 +19,7 @@ Not the class itself (which is already a callable), but an instance of that clas To do that, we declare a method `__call__`: ```Python hl_lines="10" -{!./src/dependencies/tutorial011.py!} +{!../../../docs_src/dependencies/tutorial011.py!} ``` In this case, this `__call__` is what **FastAPI** will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your *path operation function* later. @@ -27,7 +29,7 @@ In this case, this `__call__` is what **FastAPI** will use to check for addition And now, we can use `__init__` to declare the parameters of the instance that we can use to "parameterize" the dependency: ```Python hl_lines="7" -{!./src/dependencies/tutorial011.py!} +{!../../../docs_src/dependencies/tutorial011.py!} ``` In this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code. @@ -37,7 +39,7 @@ In this case, **FastAPI** won't ever touch or care about `__init__`, we will use We could create an instance of this class with: ```Python hl_lines="16" -{!./src/dependencies/tutorial011.py!} +{!../../../docs_src/dependencies/tutorial011.py!} ``` And that way we are able to "parameterize" our dependency, that now has `"bar"` inside of it, as the attribute `checker.fixed_content`. @@ -55,7 +57,7 @@ checker(q="somequery") ...and pass whatever that returns as the value of the dependency in our *path operation function* as the parameter `fixed_content_included`: ```Python hl_lines="20" -{!./src/dependencies/tutorial011.py!} +{!../../../docs_src/dependencies/tutorial011.py!} ``` !!! tip diff --git a/docs/advanced/async-sql-databases.md b/docs/en/docs/advanced/async-sql-databases.md similarity index 90% rename from docs/advanced/async-sql-databases.md rename to docs/en/docs/advanced/async-sql-databases.md index c7d0b86df..523bc91bf 100644 --- a/docs/advanced/async-sql-databases.md +++ b/docs/en/docs/advanced/async-sql-databases.md @@ -1,3 +1,5 @@ +# Async SQL (Relational) Databases + You can also use `encode/databases` with **FastAPI** to connect to databases using `async` and `await`. It is compatible with: @@ -22,7 +24,7 @@ Later, for your production application, you might want to use a database server * Create a table `notes` using the `metadata` object. ```Python hl_lines="4 14 16 17 18 19 20 21 22" -{!./src/async_sql_databases/tutorial001.py!} +{!../../../docs_src/async_sql_databases/tutorial001.py!} ``` !!! tip @@ -37,7 +39,7 @@ Later, for your production application, you might want to use a database server * Create a `database` object. ```Python hl_lines="3 9 12" -{!./src/async_sql_databases/tutorial001.py!} +{!../../../docs_src/async_sql_databases/tutorial001.py!} ``` !!! tip @@ -53,7 +55,7 @@ Here, this section would run directly, right before starting your **FastAPI** ap * Create all the tables from the `metadata` object. ```Python hl_lines="25 26 27 28" -{!./src/async_sql_databases/tutorial001.py!} +{!../../../docs_src/async_sql_databases/tutorial001.py!} ``` ## Create models @@ -64,7 +66,7 @@ Create Pydantic models for: * Notes to be returned (`Note`). ```Python hl_lines="31 32 33 36 37 38 39" -{!./src/async_sql_databases/tutorial001.py!} +{!../../../docs_src/async_sql_databases/tutorial001.py!} ``` By creating these Pydantic models, the input data will be validated, serialized (converted), and annotated (documented). @@ -77,7 +79,7 @@ So, you will be able to see it all in the interactive API docs. * Create event handlers to connect and disconnect from the database. ```Python hl_lines="42 45 46 47 50 51 52" -{!./src/async_sql_databases/tutorial001.py!} +{!../../../docs_src/async_sql_databases/tutorial001.py!} ``` ## Read notes @@ -85,7 +87,7 @@ So, you will be able to see it all in the interactive API docs. Create the *path operation function* to read notes: ```Python hl_lines="55 56 57 58" -{!./src/async_sql_databases/tutorial001.py!} +{!../../../docs_src/async_sql_databases/tutorial001.py!} ``` !!! Note @@ -102,7 +104,7 @@ That documents (and validates, serializes, filters) the output data, as a `list` Create the *path operation function* to create notes: ```Python hl_lines="61 62 63 64 65" -{!./src/async_sql_databases/tutorial001.py!} +{!../../../docs_src/async_sql_databases/tutorial001.py!} ``` !!! Note diff --git a/docs/advanced/custom-request-and-route.md b/docs/en/docs/advanced/custom-request-and-route.md similarity index 91% rename from docs/advanced/custom-request-and-route.md rename to docs/en/docs/advanced/custom-request-and-route.md index 2e823143a..6c5e97a18 100644 --- a/docs/advanced/custom-request-and-route.md +++ b/docs/en/docs/advanced/custom-request-and-route.md @@ -1,3 +1,5 @@ +# Custom Request and APIRoute class + In some cases, you may want to override the logic used by the `Request` and `APIRoute` classes. In particular, this may be a good alternative to logic in a middleware. @@ -35,7 +37,7 @@ If there's no `gzip` in the header, it will not try to decompress the body. That way, the same route class can handle gzip compressed or uncompressed requests. ```Python hl_lines="8 9 10 11 12 13 14 15" -{!./src/custom_request_and_route/tutorial001.py!} +{!../../../docs_src/custom_request_and_route/tutorial001.py!} ``` ### Create a custom `GzipRoute` class @@ -49,7 +51,7 @@ This method returns a function. And that function is what will receive a request Here we use it to create a `GzipRequest` from the original request. ```Python hl_lines="18 19 20 21 22 23 24 25 26" -{!./src/custom_request_and_route/tutorial001.py!} +{!../../../docs_src/custom_request_and_route/tutorial001.py!} ``` !!! note "Technical Details" @@ -83,13 +85,13 @@ We can also use this same approach to access the request body in an exception ha All we need to do is handle the request inside a `try`/`except` block: ```Python hl_lines="13 15" -{!./src/custom_request_and_route/tutorial002.py!} +{!../../../docs_src/custom_request_and_route/tutorial002.py!} ``` If an exception occurs, the`Request` instance will still be in scope, so we can read and make use of the request body when handling the error: ```Python hl_lines="16 17 18" -{!./src/custom_request_and_route/tutorial002.py!} +{!../../../docs_src/custom_request_and_route/tutorial002.py!} ``` ## Custom `APIRoute` class in a router @@ -97,11 +99,11 @@ If an exception occurs, the`Request` instance will still be in scope, so we can You can also set the `route_class` parameter of an `APIRouter`: ```Python hl_lines="26" -{!./src/custom_request_and_route/tutorial003.py!} +{!../../../docs_src/custom_request_and_route/tutorial003.py!} ``` In this example, the *path operations* under the `router` will use the custom `TimedRoute` class, and will have an extra `X-Response-Time` header in the response with the time it took to generate the response: ```Python hl_lines="13 14 15 16 17 18 19 20" -{!./src/custom_request_and_route/tutorial003.py!} +{!../../../docs_src/custom_request_and_route/tutorial003.py!} ``` diff --git a/docs/advanced/custom-response.md b/docs/en/docs/advanced/custom-response.md similarity index 92% rename from docs/advanced/custom-response.md rename to docs/en/docs/advanced/custom-response.md index 21e7abee4..545a84436 100644 --- a/docs/advanced/custom-response.md +++ b/docs/en/docs/advanced/custom-response.md @@ -1,3 +1,5 @@ +# Custom Response - HTML, Stream, File, others + By default, **FastAPI** will return the responses using `JSONResponse`. You can override it by returning a `Response` directly as seen in [Return a Response directly](response-directly.md){.internal-link target=_blank}. @@ -20,7 +22,7 @@ For example, if you are squeezing performance, you can install and use NoSQL. Here we'll see an example using **Couchbase**, a document based NoSQL database. @@ -18,7 +20,7 @@ You can adapt it to any other NoSQL database like: For now, don't pay attention to the rest, only the imports: ```Python hl_lines="6 7 8" -{!./src/nosql_databases/tutorial001.py!} +{!../../../docs_src/nosql_databases/tutorial001.py!} ``` ## Define a constant to use as a "document type" @@ -28,7 +30,7 @@ We will use it later as a fixed field `type` in our documents. This is not required by Couchbase, but is a good practice that will help you afterwards. ```Python hl_lines="10" -{!./src/nosql_databases/tutorial001.py!} +{!../../../docs_src/nosql_databases/tutorial001.py!} ``` ## Add a function to get a `Bucket` @@ -53,7 +55,7 @@ This utility function will: * Return it. ```Python hl_lines="13 14 15 16 17 18 19 20 21 22" -{!./src/nosql_databases/tutorial001.py!} +{!../../../docs_src/nosql_databases/tutorial001.py!} ``` ## Create Pydantic models @@ -65,7 +67,7 @@ As **Couchbase** "documents" are actually just "JSON objects", we can model them First, let's create a `User` model: ```Python hl_lines="25 26 27 28 29" -{!./src/nosql_databases/tutorial001.py!} +{!../../../docs_src/nosql_databases/tutorial001.py!} ``` We will use this model in our *path operation function*, so, we don't include in it the `hashed_password`. @@ -79,7 +81,7 @@ This will have the data that is actually stored in the database. We don't create it as a subclass of Pydantic's `BaseModel` but as a subclass of our own `User`, because it will have all the attributes in `User` plus a couple more: ```Python hl_lines="32 33 34" -{!./src/nosql_databases/tutorial001.py!} +{!../../../docs_src/nosql_databases/tutorial001.py!} ``` !!! note @@ -99,7 +101,7 @@ Now create a function that will: By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your *path operation function*, you can more easily re-use it in multiple parts and also add unit tests for it: ```Python hl_lines="37 38 39 40 41 42 43" -{!./src/nosql_databases/tutorial001.py!} +{!../../../docs_src/nosql_databases/tutorial001.py!} ``` ### f-strings @@ -134,7 +136,7 @@ UserInDB(username="johndoe", hashed_password="some_hash") ### Create the `FastAPI` app ```Python hl_lines="47" -{!./src/nosql_databases/tutorial001.py!} +{!../../../docs_src/nosql_databases/tutorial001.py!} ``` ### Create the *path operation function* @@ -144,7 +146,7 @@ As our code is calling Couchbase and we are not using the threads", so, we can get just get the bucket directly and pass it to our utility functions: ```Python hl_lines="50 51 52 53 54" -{!./src/nosql_databases/tutorial001.py!} +{!../../../docs_src/nosql_databases/tutorial001.py!} ``` ## Recap diff --git a/docs/advanced/openapi-callbacks.md b/docs/en/docs/advanced/openapi-callbacks.md similarity index 97% rename from docs/advanced/openapi-callbacks.md rename to docs/en/docs/advanced/openapi-callbacks.md index 8d3b0ac9e..15c0ba2a1 100644 --- a/docs/advanced/openapi-callbacks.md +++ b/docs/en/docs/advanced/openapi-callbacks.md @@ -1,3 +1,5 @@ +# OpenAPI Callbacks + You could create an API with a *path operation* that could trigger a request to an *external API* created by someone else (probably the same developer that would be *using* your API). The process that happens when your API app calls the *external API* is named a "callback". Because the software that the external developer wrote sends a request to your API and then your API *calls back*, sending a request to an *external API* (that was probably created by the same developer). @@ -30,7 +32,7 @@ It will have a *path operation* that will receive an `Invoice` body, and a query This part is pretty normal, most of the code is probably already familiar to you: ```Python hl_lines="8 9 10 11 12 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53" -{!./src/openapi_callbacks/tutorial001.py!} +{!../../../docs_src/openapi_callbacks/tutorial001.py!} ``` !!! tip @@ -91,7 +93,7 @@ Because of that, you need to declare what will be the `default_response_class`, But as we are never calling `app.include_router(some_router)`, we need to set the `default_response_class` during creation of the `APIRouter`. ```Python hl_lines="3 24" -{!./src/openapi_callbacks/tutorial001.py!} +{!../../../docs_src/openapi_callbacks/tutorial001.py!} ``` ### Create the callback *path operation* @@ -104,7 +106,7 @@ It should look just like a normal FastAPI *path operation*: * And it could also have a declaration of the response it should return, e.g. `response_model=InvoiceEventReceived`. ```Python hl_lines="15 16 17 20 21 27 28 29 30 31" -{!./src/openapi_callbacks/tutorial001.py!} +{!../../../docs_src/openapi_callbacks/tutorial001.py!} ``` There are 2 main differences from a normal *path operation*: @@ -171,7 +173,7 @@ At this point you have the *callback path operation(s)* needed (the one(s) that Now use the parameter `callbacks` in *your API's path operation decorator* to pass the attribute `.routes` (that's actually just a `list` of routes/*path operations*) from that callback router: ```Python hl_lines="34" -{!./src/openapi_callbacks/tutorial001.py!} +{!../../../docs_src/openapi_callbacks/tutorial001.py!} ``` !!! tip diff --git a/docs/advanced/path-operation-advanced-configuration.md b/docs/en/docs/advanced/path-operation-advanced-configuration.md similarity index 82% rename from docs/advanced/path-operation-advanced-configuration.md rename to docs/en/docs/advanced/path-operation-advanced-configuration.md index eb5cc6a12..7a3247a64 100644 --- a/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/en/docs/advanced/path-operation-advanced-configuration.md @@ -1,3 +1,5 @@ +# Path Operation Advanced Configuration + ## OpenAPI operationId !!! warning @@ -8,7 +10,7 @@ You can set the OpenAPI `operationId` to be used in your *path operation* with t You would have to make sure that it is unique for each operation. ```Python hl_lines="6" -{!./src/path_operation_advanced_configuration/tutorial001.py!} +{!../../../docs_src/path_operation_advanced_configuration/tutorial001.py!} ``` ### Using the *path operation function* name as the operationId @@ -18,7 +20,7 @@ If you want to use your APIs' function names as `operationId`s, you can iterate You should do it after adding all your *path operations*. ```Python hl_lines="2 12 13 14 15 16 17 18 19 20 21 24" -{!./src/path_operation_advanced_configuration/tutorial002.py!} +{!../../../docs_src/path_operation_advanced_configuration/tutorial002.py!} ``` !!! tip @@ -34,7 +36,7 @@ You should do it after adding all your *path operations*. To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`; ```Python hl_lines="6" -{!./src/path_operation_advanced_configuration/tutorial003.py!} +{!../../../docs_src/path_operation_advanced_configuration/tutorial003.py!} ``` ## Advanced description from docstring @@ -46,5 +48,5 @@ Adding an `\f` (an escaped "form feed" character) causes **FastAPI** to truncate It won't show up in the documentation, but other tools (such as Sphinx) will be able to use the rest. ```Python hl_lines="19 20 21 22 23 24 25 26 27 28 29" -{!./src/path_operation_advanced_configuration/tutorial004.py!} +{!../../../docs_src/path_operation_advanced_configuration/tutorial004.py!} ``` diff --git a/docs/advanced/response-change-status-code.md b/docs/en/docs/advanced/response-change-status-code.md similarity index 93% rename from docs/advanced/response-change-status-code.md rename to docs/en/docs/advanced/response-change-status-code.md index 1f10e12da..979cef3f0 100644 --- a/docs/advanced/response-change-status-code.md +++ b/docs/en/docs/advanced/response-change-status-code.md @@ -1,3 +1,5 @@ +# Response - Change Status Code + You probably read before that you can set a default [Response Status Code](../tutorial/response-status-code.md){.internal-link target=_blank}. But in some cases you need to return a different status code than the default. @@ -19,7 +21,7 @@ You can declare a parameter of type `Response` in your *path operation function* And then you can set the `status_code` in that *temporal* response object. ```Python hl_lines="1 9 12" -{!./src/response_change_status_code/tutorial001.py!} +{!../../../docs_src/response_change_status_code/tutorial001.py!} ``` And then you can return any object you need, as you normally would (a `dict`, a database model, etc). diff --git a/docs/advanced/response-cookies.md b/docs/en/docs/advanced/response-cookies.md similarity index 94% rename from docs/advanced/response-cookies.md rename to docs/en/docs/advanced/response-cookies.md index 8ce07bbf3..e46ae755f 100644 --- a/docs/advanced/response-cookies.md +++ b/docs/en/docs/advanced/response-cookies.md @@ -1,3 +1,5 @@ +# Response Cookies + ## Use a `Response` parameter You can declare a parameter of type `Response` in your *path operation function*. @@ -5,7 +7,7 @@ You can declare a parameter of type `Response` in your *path operation function* And then you can set cookies in that *temporal* response object. ```Python hl_lines="1 8 9" -{!./src/response_cookies/tutorial002.py!} +{!../../../docs_src/response_cookies/tutorial002.py!} ``` And then you can return any object you need, as you normally would (a `dict`, a database model, etc). @@ -25,7 +27,7 @@ To do that, you can create a response as described in [Return a Response Directl Then set Cookies in it, and then return it: ```Python hl_lines="10 11 12" -{!./src/response_cookies/tutorial001.py!} +{!../../../docs_src/response_cookies/tutorial001.py!} ``` !!! tip diff --git a/docs/advanced/response-directly.md b/docs/en/docs/advanced/response-directly.md similarity index 95% rename from docs/advanced/response-directly.md rename to docs/en/docs/advanced/response-directly.md index 1b1232808..f1dca1812 100644 --- a/docs/advanced/response-directly.md +++ b/docs/en/docs/advanced/response-directly.md @@ -1,3 +1,5 @@ +# Return a Response Directly + When you create a **FastAPI** *path operation* you can normally return any data from it: a `dict`, a `list`, a Pydantic model, a database model, etc. By default, **FastAPI** would automatically convert that return value to JSON using the `jsonable_encoder` explained in [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}. @@ -30,7 +32,7 @@ For example, you cannot put a Pydantic model in a `JSONResponse` without first c For those cases, you can use the `jsonable_encoder` to convert your data before passing it to a response: ```Python hl_lines="4 6 20 21" -{!./src/response_directly/tutorial001.py!} +{!../../../docs_src/response_directly/tutorial001.py!} ``` !!! note "Technical Details" @@ -49,7 +51,7 @@ Let's say that you want to return an `secrets` to check the username and password: ```Python hl_lines="1 11 12 13" -{!./src/security/tutorial007.py!} +{!../../../docs_src/security/tutorial007.py!} ``` This will ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`. This would be similar to: @@ -101,5 +103,5 @@ That way, using `secrets.compare_digest()` in your application code, it will be After detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again: ```Python hl_lines="15 16 17 18 19" -{!./src/security/tutorial007.py!} +{!../../../docs_src/security/tutorial007.py!} ``` diff --git a/docs/advanced/security/index.md b/docs/en/docs/advanced/security/index.md similarity index 95% rename from docs/advanced/security/index.md rename to docs/en/docs/advanced/security/index.md index 560af5a7c..0c94986b5 100644 --- a/docs/advanced/security/index.md +++ b/docs/en/docs/advanced/security/index.md @@ -1,3 +1,5 @@ +# Advanced Security - Intro + ## Additional Features There are some extra features to handle security apart from the ones covered in the [Tutorial - User Guide: Security](../../tutorial/security/){.internal-link target=_blank}. diff --git a/docs/advanced/security/oauth2-scopes.md b/docs/en/docs/advanced/security/oauth2-scopes.md similarity index 97% rename from docs/advanced/security/oauth2-scopes.md rename to docs/en/docs/advanced/security/oauth2-scopes.md index 84c806bf8..a78423221 100644 --- a/docs/advanced/security/oauth2-scopes.md +++ b/docs/en/docs/advanced/security/oauth2-scopes.md @@ -1,3 +1,5 @@ +# OAuth2 scopes + You can use OAuth2 scopes directly with **FastAPI**, they are integrated to work seamlessly. This would allow you to have a more fine-grained permission system, following the OAuth2 standard, integrated into your OpenAPI application (and the API docs). @@ -55,7 +57,7 @@ They are normally used to declare specific security permissions, for example: First, let's quickly see the parts that change from the examples in the main **Tutorial - User Guide** for [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Now using OAuth2 scopes: ```Python hl_lines="2 5 9 13 47 65 106 108 109 110 111 112 113 114 115 116 122 123 124 125 129 130 131 132 133 134 135 140 154" -{!./src/security/tutorial005.py!} +{!../../../docs_src/security/tutorial005.py!} ``` Now let's review those changes step by step. @@ -67,7 +69,7 @@ The first change is that now we are declaring the OAuth2 security scheme with tw The `scopes` parameter receives a `dict` with each scope as a key and the description as the value: ```Python hl_lines="63 64 65 66" -{!./src/security/tutorial005.py!} +{!../../../docs_src/security/tutorial005.py!} ``` Because we are now declaring those scopes, they will show up in the API docs when you log-in/authorize. @@ -92,7 +94,7 @@ And we return the scopes as part of the JWT token. But in your application, for security, you should make sure you only add the scopes that the user is actually able to have, or the ones you have predefined. ```Python hl_lines="155" -{!./src/security/tutorial005.py!} +{!../../../docs_src/security/tutorial005.py!} ``` ## Declare scopes in *path operations* and dependencies @@ -117,7 +119,7 @@ In this case, it requires the scope `me` (it could require more than one scope). We are doing it here to demonstrate how **FastAPI** handles scopes declared at different levels. ```Python hl_lines="5 140 167" -{!./src/security/tutorial005.py!} +{!../../../docs_src/security/tutorial005.py!} ``` !!! info "Technical Details" @@ -142,7 +144,7 @@ We also declare a special parameter of type `SecurityScopes`, imported from `fas This `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly). ```Python hl_lines="9 106" -{!./src/security/tutorial005.py!} +{!../../../docs_src/security/tutorial005.py!} ``` ## Use the `scopes` @@ -158,7 +160,7 @@ We create an `HTTPException` that we can re-use (`raise`) later at several point In this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in in the `WWW-Authenticate` header (this is part of the spec). ```Python hl_lines="106 108 109 110 111 112 113 114 115 116" -{!./src/security/tutorial005.py!} +{!../../../docs_src/security/tutorial005.py!} ``` ## Verify the `username` and data shape @@ -176,7 +178,7 @@ Instead of, for example, a `dict`, or something else, as it could break the appl We also verify that we have a user with that username, and if not, we raise that same exception we created before. ```Python hl_lines="47 117 118 119 120 121 122 123 124 125 126 127 128" -{!./src/security/tutorial005.py!} +{!../../../docs_src/security/tutorial005.py!} ``` ## Verify the `scopes` @@ -186,7 +188,7 @@ We now verify that all the scopes required, by this dependency and all the depen For this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`. ```Python hl_lines="129 130 131 132 133 134 135" -{!./src/security/tutorial005.py!} +{!../../../docs_src/security/tutorial005.py!} ``` ## Dependency tree and scopes diff --git a/docs/advanced/sql-databases-peewee.md b/docs/en/docs/advanced/sql-databases-peewee.md similarity index 95% rename from docs/advanced/sql-databases-peewee.md rename to docs/en/docs/advanced/sql-databases-peewee.md index ae957bec6..761029006 100644 --- a/docs/advanced/sql-databases-peewee.md +++ b/docs/en/docs/advanced/sql-databases-peewee.md @@ -1,3 +1,5 @@ +# SQL (Relational) Databases with Peewee + !!! warning If you are just starting, the tutorial [SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank} that uses SQLAlchemy should be enough. @@ -60,7 +62,7 @@ Let's refer to the file `sql_app/database.py`. Let's first check all the normal Peewee code, create a Peewee database: ```Python hl_lines="3 5 22" -{!./src/sql_databases_peewee/sql_app/database.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/database.py!} ``` !!! tip @@ -112,7 +114,7 @@ This might seem a bit complex (and it actually is), you don't really need to com We will create a `PeeweeConnectionState`: ```Python hl_lines="10 11 12 13 14 15 16 17 18 19" -{!./src/sql_databases_peewee/sql_app/database.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/database.py!} ``` This class inherits from a special internal class used by Peewee. @@ -133,7 +135,7 @@ So, we need to do some extra tricks to make it work as if it was just using `thr Now, overwrite the `._state` internal attribute in the Peewee database `db` object using the new `PeeweeConnectionState`: ```Python hl_lines="24" -{!./src/sql_databases_peewee/sql_app/database.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/database.py!} ``` !!! tip @@ -160,7 +162,7 @@ This is the same you would do if you followed the Peewee tutorial and updated th Import `db` from `database` (the file `database.py` from above) and use it here. ```Python hl_lines="3 6 7 8 9 10 11 12 15 16 17 18 19 20 21" -{!./src/sql_databases_peewee/sql_app/models.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/models.py!} ``` !!! tip @@ -188,7 +190,7 @@ Now let's check the file `sql_app/schemas.py`. Create all the same Pydantic models as in the SQLAlchemy tutorial: ```Python hl_lines="16 17 18 21 22 25 26 27 28 29 30 34 35 38 39 42 43 44 45 46 47 48" -{!./src/sql_databases_peewee/sql_app/schemas.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!} ``` !!! tip @@ -213,7 +215,7 @@ But recent versions of Pydantic allow providing a custom class that inherits fro We are going to create a custom `PeeweeGetterDict` class and use it in all the same Pydantic *models* / schemas that use `orm_mode`: ```Python hl_lines="3 8 9 10 11 12 13 31 49" -{!./src/sql_databases_peewee/sql_app/schemas.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!} ``` Here we are checking if the attribute that is being accessed (e.g. `.items` in `some_user.items`) is an instance of `peewee.ModelSelect`. @@ -234,7 +236,7 @@ Now let's see the file `sql_app/crud.py`. Create all the same CRUD utils as in the SQLAlchemy tutorial, all the code is very similar: ```Python hl_lines="1 4 5 8 9 12 13 16 17 18 19 20 23 24 27 28 29 30" -{!./src/sql_databases_peewee/sql_app/crud.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/crud.py!} ``` There are some differences with the code for the SQLAlchemy tutorial. @@ -258,7 +260,7 @@ And now in the file `sql_app/main.py` let's integrate and use all the other part In a very simplistic way create the database tables: ```Python hl_lines="9 10 11" -{!./src/sql_databases_peewee/sql_app/main.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/main.py!} ``` ### Create a dependency @@ -266,7 +268,7 @@ In a very simplistic way create the database tables: Create a dependency that will connect the database right at the beginning of a request and disconnect it at the end: ```Python hl_lines="23 24 25 26 27 28 29" -{!./src/sql_databases_peewee/sql_app/main.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/main.py!} ``` Here we have an empty `yield` because we are actually not using the database object directly. @@ -280,7 +282,7 @@ And then, in each *path operation function* that needs to access the database we But we are not using the value given by this dependency (it actually doesn't give any value, as it has an empty `yield`). So, we don't add it to the *path operation function* but to the *path operation decorator* in the `dependencies` parameter: ```Python hl_lines="32 40 47 59 65 72" -{!./src/sql_databases_peewee/sql_app/main.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/main.py!} ``` ### Context variable sub-dependency @@ -290,7 +292,7 @@ For all the `contextvars` parts to work, we need to make sure we have an indepen For that, we need to create another `async` dependency `reset_db_state()` that is used as a sub-dependency in `get_db()`. It will set the value for the context variable (with just a default `dict`) that will be used as the database state for the whole request. And then the dependency `get_db()` will store in it the database state (connection, transactions, etc). ```Python hl_lines="18 19 20" -{!./src/sql_databases_peewee/sql_app/main.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/main.py!} ``` For the **next request**, as we will reset that context variable again in the `async` dependency `reset_db_state()` and then create a new connection in the `get_db()` dependency, that new request will have its own database state (connection, transactions, etc). @@ -319,7 +321,7 @@ async def reset_db_state(): Now, finally, here's the standard **FastAPI** *path operations* code. ```Python hl_lines="32 33 34 35 36 37 40 41 42 43 46 47 48 49 50 51 52 53 56 57 58 59 60 61 62 65 66 67 68 71 72 73 74 75 76 77 78 79" -{!./src/sql_databases_peewee/sql_app/main.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/main.py!} ``` ### About `def` vs `async def` @@ -436,31 +438,31 @@ Repeat the same process with the 10 tabs. This time all of them will wait and yo * `sql_app/database.py`: ```Python -{!./src/sql_databases_peewee/sql_app/database.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/database.py!} ``` * `sql_app/models.py`: ```Python -{!./src/sql_databases_peewee/sql_app/models.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/models.py!} ``` * `sql_app/schemas.py`: ```Python -{!./src/sql_databases_peewee/sql_app/schemas.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!} ``` * `sql_app/crud.py`: ```Python -{!./src/sql_databases_peewee/sql_app/crud.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/crud.py!} ``` * `sql_app/main.py`: ```Python -{!./src/sql_databases_peewee/sql_app/main.py!} +{!../../../docs_src/sql_databases_peewee/sql_app/main.py!} ``` ## Technical Details diff --git a/docs/advanced/sub-applications-proxy.md b/docs/en/docs/advanced/sub-applications-proxy.md similarity index 94% rename from docs/advanced/sub-applications-proxy.md rename to docs/en/docs/advanced/sub-applications-proxy.md index 333ef9ae2..03a7f9446 100644 --- a/docs/advanced/sub-applications-proxy.md +++ b/docs/en/docs/advanced/sub-applications-proxy.md @@ -1,3 +1,5 @@ +# Sub Applications - Behind a Proxy, Mounts + There are at least two situations where you could need to create your **FastAPI** application using some specific paths. But then you need to set them up to be served with a path prefix. @@ -44,7 +46,7 @@ You could want to do this if you have several "independent" applications that yo First, create the main, top-level, **FastAPI** application, and its *path operations*: ```Python hl_lines="3 6 7 8" -{!./src/sub_applications/tutorial001.py!} +{!../../../docs_src/sub_applications/tutorial001.py!} ``` ### Sub-application @@ -56,7 +58,7 @@ This sub-application is just another standard FastAPI application, but this is t When creating the sub-application, use the parameter `openapi_prefix`. In this case, with a prefix of `/subapi`: ```Python hl_lines="11 14 15 16" -{!./src/sub_applications/tutorial001.py!} +{!../../../docs_src/sub_applications/tutorial001.py!} ``` ### Mount the sub-application @@ -66,7 +68,7 @@ In your top-level application, `app`, mount the sub-application, `subapi`. Here you need to make sure you use the same path that you used for the `openapi_prefix`, in this case, `/subapi`: ```Python hl_lines="11 19" -{!./src/sub_applications/tutorial001.py!} +{!../../../docs_src/sub_applications/tutorial001.py!} ``` ## Check the automatic API docs diff --git a/docs/advanced/templates.md b/docs/en/docs/advanced/templates.md similarity index 91% rename from docs/advanced/templates.md rename to docs/en/docs/advanced/templates.md index da4752e4a..871f3163f 100644 --- a/docs/advanced/templates.md +++ b/docs/en/docs/advanced/templates.md @@ -1,3 +1,5 @@ +# Templates + You can use any template engine you want with **FastAPI**. A common election is Jinja2, the same one used by Flask and other tools. @@ -38,7 +40,7 @@ $ pip install aiofiles * Use the `templates` you created to render and return a `TemplateResponse`, passing the `request` as one of the key-value pairs in the Jinja2 "context". ```Python hl_lines="3 10 14 15" -{!./src/templates/tutorial001.py!} +{!../../../docs_src/templates/tutorial001.py!} ``` !!! note @@ -54,7 +56,7 @@ $ pip install aiofiles Then you can write a template at `templates/item.html` with: ```jinja hl_lines="7" -{!./src/templates/templates/item.html!} +{!../../../docs_src/templates/templates/item.html!} ``` It will show the `id` taken from the "context" `dict` you passed: @@ -68,13 +70,13 @@ It will show the `id` taken from the "context" `dict` you passed: And you can also use `url_for()` inside of the template, and use it, for example, with the `StaticFiles` you mounted. ```jinja hl_lines="4" -{!./src/templates/templates/item.html!} +{!../../../docs_src/templates/templates/item.html!} ``` In this example, it would link to a CSS file at `static/styles.css` with: ```CSS hl_lines="4" -{!./src/templates/static/styles.css!} +{!../../../docs_src/templates/static/styles.css!} ``` And because you are using `StaticFiles`, that CSS file would be served automatically by your **FastAPI** application at the URL `/static/styles.css`. diff --git a/docs/advanced/testing-dependencies.md b/docs/en/docs/advanced/testing-dependencies.md similarity index 96% rename from docs/advanced/testing-dependencies.md rename to docs/en/docs/advanced/testing-dependencies.md index 50d50618c..5ba7e219b 100644 --- a/docs/advanced/testing-dependencies.md +++ b/docs/en/docs/advanced/testing-dependencies.md @@ -1,3 +1,5 @@ +# Testing Dependencies with Overrides + ## Overriding dependencies during testing There are some scenarios where you might want to override a dependency during testing. @@ -39,7 +41,7 @@ To override a dependency for testing, you put as a key the original dependency ( And then **FastAPI** will call that override instead of the original dependency. ```Python hl_lines="24 25 28" -{!./src/dependency_testing/tutorial001.py!} +{!../../../docs_src/dependency_testing/tutorial001.py!} ``` !!! tip diff --git a/docs/advanced/testing-events.md b/docs/en/docs/advanced/testing-events.md similarity index 67% rename from docs/advanced/testing-events.md rename to docs/en/docs/advanced/testing-events.md index a52aabe98..45d8d8686 100644 --- a/docs/advanced/testing-events.md +++ b/docs/en/docs/advanced/testing-events.md @@ -1,7 +1,7 @@ -## Testing Events, `startup` and `shutdown` +# Testing Events: startup - shutdown When you need your event handlers (`startup` and `shutdown`) to run in your tests, you can use the `TestClient` with a `with` statement: ```Python hl_lines="9 10 11 12 20 21 22 23 24" -{!./src/app_testing/tutorial003.py!} -``` \ No newline at end of file +{!../../../docs_src/app_testing/tutorial003.py!} +``` diff --git a/docs/advanced/testing-websockets.md b/docs/en/docs/advanced/testing-websockets.md similarity index 72% rename from docs/advanced/testing-websockets.md rename to docs/en/docs/advanced/testing-websockets.md index 8e9ecf34f..a9d6821be 100644 --- a/docs/advanced/testing-websockets.md +++ b/docs/en/docs/advanced/testing-websockets.md @@ -1,9 +1,9 @@ -## Testing WebSockets +# Testing WebSockets You can use the same `TestClient` to test WebSockets. For this, you use the `TestClient` in a `with` statement, connecting to the WebSocket: ```Python hl_lines="27 28 29 30 31" -{!./src/app_testing/tutorial002.py!} +{!../../../docs_src/app_testing/tutorial002.py!} ``` diff --git a/docs/advanced/using-request-directly.md b/docs/en/docs/advanced/using-request-directly.md similarity index 96% rename from docs/advanced/using-request-directly.md rename to docs/en/docs/advanced/using-request-directly.md index 4d9e84d2c..ac452c25e 100644 --- a/docs/advanced/using-request-directly.md +++ b/docs/en/docs/advanced/using-request-directly.md @@ -1,3 +1,5 @@ +# Using the Request Directly + Up to now, you have been declaring the parts of the request that you need with their types. Taking data from: @@ -28,7 +30,7 @@ Let's imagine you want to get the client's IP address/host inside of your *path For that you need to access the request directly. ```Python hl_lines="1 7 8" -{!./src/using_request_directly/tutorial001.py!} +{!../../../docs_src/using_request_directly/tutorial001.py!} ``` By declaring a *path operation function* parameter with the type being the `Request` **FastAPI** will know to pass the `Request` in that parameter. diff --git a/docs/advanced/websockets.md b/docs/en/docs/advanced/websockets.md similarity index 94% rename from docs/advanced/websockets.md rename to docs/en/docs/advanced/websockets.md index a76eab59c..d473cef07 100644 --- a/docs/advanced/websockets.md +++ b/docs/en/docs/advanced/websockets.md @@ -1,3 +1,4 @@ +# WebSockets You can use WebSockets with **FastAPI**. @@ -24,7 +25,7 @@ In production you would have one of the options above. But it's the simplest way to focus on the server-side of WebSockets and have a working example: ```Python hl_lines="2 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 41 42 43" -{!./src/websockets/tutorial001.py!} +{!../../../docs_src/websockets/tutorial001.py!} ``` ## Create a `websocket` @@ -32,7 +33,7 @@ But it's the simplest way to focus on the server-side of WebSockets and have a w In your **FastAPI** application, create a `websocket`: ```Python hl_lines="1 46 47" -{!./src/websockets/tutorial001.py!} +{!../../../docs_src/websockets/tutorial001.py!} ``` !!! note "Technical Details" @@ -45,7 +46,7 @@ In your **FastAPI** application, create a `websocket`: In your WebSocket route you can `await` for messages and send messages. ```Python hl_lines="48 49 50 51 52" -{!./src/websockets/tutorial001.py!} +{!../../../docs_src/websockets/tutorial001.py!} ``` You can receive and send binary, text, and JSON data. @@ -64,7 +65,7 @@ In WebSocket endpoints you can import from `fastapi` and use: They work the same way as for other FastAPI endpoints/*path operations*: ```Python hl_lines="53 54 55 56 57 58 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76" -{!./src/websockets/tutorial002.py!} +{!../../../docs_src/websockets/tutorial002.py!} ``` !!! info diff --git a/docs/advanced/wsgi.md b/docs/en/docs/advanced/wsgi.md similarity index 92% rename from docs/advanced/wsgi.md rename to docs/en/docs/advanced/wsgi.md index 7d2edfc55..4b81aff2e 100644 --- a/docs/advanced/wsgi.md +++ b/docs/en/docs/advanced/wsgi.md @@ -1,3 +1,5 @@ +# Including WSGI - Flask, Django, others + You can mount WSGI applications as you saw with [Sub Applications - Behind a Proxy, Mounts](./sub-applications-proxy.md){.internal-link target=_blank}. For that, you can use the `WSGIMiddleware` and use it to wrap your WSGI application, for example, Flask, Django, etc. @@ -11,7 +13,7 @@ Then wrap the WSGI (e.g. Flask) app with the middleware. And then mount that under a path. ```Python hl_lines="1 3 22" -{!./src/wsgi/tutorial001.py!} +{!../../../docs_src/wsgi/tutorial001.py!} ``` ## Check it diff --git a/docs/alternatives.md b/docs/en/docs/alternatives.md similarity index 99% rename from docs/alternatives.md rename to docs/en/docs/alternatives.md index 730c10794..3d9e3a55a 100644 --- a/docs/alternatives.md +++ b/docs/en/docs/alternatives.md @@ -1,3 +1,5 @@ +# Alternatives, Inspiration and Comparisons + What inspired **FastAPI**, how it compares to other alternatives and what it learned from them. ## Intro diff --git a/docs/async.md b/docs/en/docs/async.md similarity index 99% rename from docs/async.md rename to docs/en/docs/async.md index 24c2f61d2..dc17e5172 100644 --- a/docs/async.md +++ b/docs/en/docs/async.md @@ -1,3 +1,5 @@ +# Concurrency and async / await + Details about the `async def` syntax for *path operation functions* and some background about asynchronous code, concurrency, and parallelism. ## In a hurry? diff --git a/docs/benchmarks.md b/docs/en/docs/benchmarks.md similarity index 99% rename from docs/benchmarks.md rename to docs/en/docs/benchmarks.md index 95efcab53..5223df81d 100644 --- a/docs/benchmarks.md +++ b/docs/en/docs/benchmarks.md @@ -1,3 +1,5 @@ +# Benchmarks + Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) But when checking benchmarks and comparisons you should have the following in mind. diff --git a/docs/en/docs/contributing.md b/docs/en/docs/contributing.md new file mode 100644 index 000000000..a08991a15 --- /dev/null +++ b/docs/en/docs/contributing.md @@ -0,0 +1,441 @@ +# Development - Contributing + +First, you might want to see the basic ways to [help FastAPI and get help](help-fastapi.md){.internal-link target=_blank}. + +## Developing + +If you already cloned the repository and you know that you need to deep dive in the code, here are some guidelines to set up your environment. + +### Virtual environment with `venv` + +You can create a virtual environment in a directory using Python's `venv` module: + +
+ +```console +$ python -m venv env +``` + +
+ +That will create a directory `./env/` with the Python binaries and then you will be able to install packages for that isolated environment. + +### Activate the environment + +Activate the new environment with: + +
+ +```console +$ source ./env/bin/activate +``` + +
+ +Or in Windows' PowerShell: + +
+ +```console +$ .\env\Scripts\Activate.ps1 +``` + +
+ +Or if you use Bash for Windows (e.g. Git Bash): + +
+ +```console +$ source ./env/Scripts/activate +``` + +
+ +To check it worked, use: + +
+ +```console +$ which pip + +some/directory/fastapi/env/bin/pip +``` + +
+ +If it shows the `pip` binary at `env/bin/pip` then it worked. 🎉 + +Or in Windows PowerShell: + +
+ +```console +$ Get-Command pip + +some/directory/fastapi/env/bin/pip +``` + +
+ +!!! tip + Every time you install a new package with `pip` under that environment, activate the environment again. + + This makes sure that if you use a terminal program installed by that package (like `flit`), you use the one from your local environment and not any other that could be installed globally. + +### Flit + +**FastAPI** uses Flit to build, package and publish the project. + +After activating the environment as described above, install `flit`: + +
+ +```console +$ pip install flit + +---> 100% +``` + +
+ +Now re-activate the environment to make sure you are using the `flit` you just installed (and not a global one). + +And now use `flit` to install the development dependencies: + +
+ +```console +$ flit install --deps develop --symlink + +---> 100% +``` + +
+ +It will install all the dependencies and your local FastAPI in your local environment. + +#### Using your local FastAPI + +If you create a Python file that imports and uses FastAPI, and run it with the Python from your local environment, it will use your local FastAPI source code. + +And if you update that local FastAPI source code, as it is installed with `--symlink`, when you run that Python file again, it will use the fresh version of FastAPI you just edited. + +That way, you don't have to "install" your local version to be able to test every change. + +### Format + +There is a script that you can run that will format and clean all your code: + +
+ +```console +$ bash scripts/format.sh +``` + +
+ +It will also auto-sort all your imports. + +For it to sort them correctly, you need to have FastAPI installed locally in your environment, with the command in the section above: + +
+ +```console +$ flit install --symlink + +---> 100% +``` + +
+ +### Format imports + +There is another script that formats all the imports and makes sure you don't have unused imports: + +
+ +```console +$ bash scripts/format-imports.sh +``` + +
+ +As it runs one command after the other and modifies and reverts many files, it takes a bit longer to run, so it might be easier to use `scripts/format.sh` frequently and `scripts/format-imports.sh` only before committing. + +## Docs + +First, make sure you set up your environment as described above, that will install all the requirements. + +The documentation uses MkDocs. + +And there are extra tools/scripts in place to handle translations in `./scripts/docs.py`. + +!!! tip + You don't need to see the code in `./scripts/docs.py`, you just use it in the command line. + +All the documentation is in Markdown format in the directory `./docs/en/`. + +Many of the tutorials have blocks of code. + +In most of the cases, these blocks of code are actual complete applications that can be run as is. + +In fact, those blocks of code are not written inside the Markdown, they are Python files in the `./docs_src/` directory. + +And those Python files are included/injected in the documentation when generating the site. + +### Docs for tests + +Most of the tests actually run against the example source files in the documentation. + +This helps making sure that: + +* The documentation is up to date. +* The documentation examples can be run as is. +* Most of the features are covered by the documentation, ensured by test coverage. + +During local development, there is a script that builds the site and checks for any changes, live-reloading: + +
+ +```console +$ python ./scripts/docs.py live + +[INFO] Serving on http://0.0.0.0:8008 +[INFO] Start watching changes +[INFO] Start detecting changes +``` + +
+ +It will serve the documentation on `http://0.0.0.0:8008`. + +That way, you can edit the documentation/source files and see the changes live. + +#### Typer CLI (optional) + +The instructions here show you how to use the script at `./scripts/docs.py` with the `python` program directly. + +But you can also use Typer CLI, and you will get autocompletion in your terminal for the commands after installing completion. + +If you install Typer CLI, you can install completion with: + +
+ +```console +$ typer --install-completion + +zsh completion installed in /home/user/.bashrc. +Completion will take effect once you restart the terminal. +``` + +
+ +### Apps and docs at the same time + +If you run the examples with, e.g.: + +
+ +```console +$ uvicorn tutorial001:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +as Uvicorn by default will use the port `8000`, the documentation on port `8008` won't clash. + +### Translations + +Help with translations is VERY MUCH appreciated! And it can't be done without the help from the community. 🌎 🚀 + +Here are the steps to help with translations. + +#### Tips + +✨ Add a single Pull Request per page translated. That will make it much easier for others to review it. + +For the languages I don't speak, I'll wait for several others to review the translation before merging. + +✨ You can also check if there are translations for your language and add a review to them, that will help me know that the translation is correct and I can merge it. + +✨ To check the 2-letter code for the language you want to translate you can use the table List of ISO 639-1 codes. + +#### Existing language + +Let's say you want to translate a page for a language that already has translations for some pages, like Spanish. + +In the case of Spanish, the 2-letter code is `es`. So, the directory for Spanish translations is located at `docs/es/`. + +!!! tip + The main ("official") language is English, located at `docs/en/`. + +Now run the live server for the docs in Spanish: + +
+ +```console +// Use the command "live" and pass the language code as a CLI argument +$ python ./scripts/docs.py live es + +[INFO] Serving on http://0.0.0.0:8008 +[INFO] Start watching changes +[INFO] Start detecting changes +``` + +
+ +Now you can go to http://0.0.0.0:8008 and see your changes live. + +If you look at the FastAPI docs website, you will see that every language has all the pages. But some are not translated and have a notification about the the translation is missing. + +But when you run it locally like this, you will only see the pages that are already translated. + +Now let's say that you want to add a translation for the section [Advanced User Guide: Extending OpenAPI](advanced/extending-openapi.md){.internal-link target=_blank}. + +* Copy the file at: + +``` +docs/en/docs/advanced/extending-openapi.md +``` + +* Paste it in exactly the same location but for the language you want to translate, e.g.: + +``` +docs/es/docs/advanced/extending-openapi.md +``` + +!!! tip + Notice that the only change in the path and file name is the language code, from `en` to `es`. + +* Now open the MkDocs config file at: + +``` +docs/en/docs/mkdocs.yml +``` + +* Find the place where that `advanced/extending-openapi.md` is located in the config file. Somewhere like: + +```YAML hl_lines="9" +site_name: FastAPI +# More stuff +nav: +- FastAPI: index.md +# More stuff +- Advanced User Guide: + # More stuff + - advanced/testing-dependencies.md + - advanced/extending-openapi.md + - advanced/openapi-callbacks.md +``` + +* Open the MkDocs config file for the language you are editing, e.g.: + +``` +docs/es/docs/mkdocs.yml +``` + +* Add the equivalent structure code and add it at the exact same location it would be, e.g.: + +```YAML hl_lines="6 9" +site_name: FastAPI +# More stuff +nav: +- FastAPI: index.md +# More stuff +- Guía de Usuario Avanzada: + # More stuff + - advanced/testing-dependencies.md + - advanced/extending-openapi.md + - advanced/openapi-callbacks.md +``` + +Notice that the `Advanced User Guide` is translated to `Guía de Usuario Avanzada`. + +Also, make sure that if there are other entries, the new entry with your translation is in exactly in the same order as in the English version. + +If you go to your browser you will see that now the docs show your new section. 🎉 + +Now you can translate it all and see how it looks as you save the file. + +#### New Language + +Let's say that you want to add translations for a language that is not yet translated, not even some pages. + +Let's say you want to add translations for Creole, and it's not yet there in the docs. + +Checking the link from above, the code for "Creole" is `ht`. + +The next step is to run the script to generate a new translation directory: + +
+ +```console +// Use the command new-lang, pass the language code as a CLI argument +$ python ./scripts/docs.py new-lang ht + +Successfully initialized: docs/ht +Updating ht +Updating en +``` + +
+ +Now you can check in your code editor the newly created directory `docs/ht/`. + +Start by translating the main page, `docs/ht/index.md`. + +Then you can continue with the previous instructions, for an "Existing Language". + +##### New Language not supported + +If when running the live server script you get an error about the language not being supported, something like: + +``` + raise TemplateNotFound(template) +jinja2.exceptions.TemplateNotFound: partials/language/xx.html +``` + +That means that the theme doesn't support that language (in this case, with a fake 2-letter code of `xx`). + +But don't worry, you can set the theme language to English and then translate the content of the docs. + +If you need to do that, edit the `mkdocs.yml` for your new language, it will have something like: + +```YAML hl_lines="5" +site_name: FastAPI +# More stuff +theme: + # More stuff + language: xx +``` + +Change that language from `xx` (from your language code) to `en`. + +Then you can start the live server again. + +## Tests + +There is a script that you can run locally to test all the code and generate coverage reports in HTML: + +
+ +```console +$ bash scripts/test-cov-html.sh +``` + +
+ +This command generates a directory `./htmlcov/`, if you open the file `./htmlcov/index.html` in your browser, you can explore interactively the regions of code that are covered by the tests, and notice if there is any region missing. + +### Tests in your editor + +If you want to use the integrated tests in your editor add `./docs/src` to your `PYTHONPATH` variable. + +For example, in VS Code you can create a file `.env` with: + +```env +PYTHONPATH=./docs/src +``` diff --git a/docs/css/custom.css b/docs/en/docs/css/custom.css similarity index 100% rename from docs/css/custom.css rename to docs/en/docs/css/custom.css diff --git a/docs/css/termynal.css b/docs/en/docs/css/termynal.css similarity index 100% rename from docs/css/termynal.css rename to docs/en/docs/css/termynal.css diff --git a/docs/deployment.md b/docs/en/docs/deployment.md similarity index 99% rename from docs/deployment.md rename to docs/en/docs/deployment.md index 8d4c6fcdb..8ca7c433f 100644 --- a/docs/deployment.md +++ b/docs/en/docs/deployment.md @@ -1,3 +1,5 @@ +# Deployment + Deploying a **FastAPI** application is relatively easy. There are several ways to do it depending on your specific use case and the tools that you use. diff --git a/docs/external-links.md b/docs/en/docs/external-links.md similarity index 99% rename from docs/external-links.md rename to docs/en/docs/external-links.md index c222e1247..4546befd0 100644 --- a/docs/external-links.md +++ b/docs/en/docs/external-links.md @@ -1,3 +1,5 @@ +# External Links and Articles + **FastAPI** has a great community constantly growing. There are many posts, articles, tools, and projects, related to **FastAPI**. diff --git a/docs/features.md b/docs/en/docs/features.md similarity index 96% rename from docs/features.md rename to docs/en/docs/features.md index 69c62cbce..8b5bb51f1 100644 --- a/docs/features.md +++ b/docs/en/docs/features.md @@ -1,3 +1,4 @@ +# Features ## FastAPI features @@ -16,11 +17,11 @@ Interactive API documentation and exploration web user interfaces. As the framew * Swagger UI, with interactive exploration, call and test your API directly from the browser. -![Swagger UI interaction](img/index/index-03-swagger-02.png) +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) * Alternative API documentation with ReDoc. -![ReDoc](img/index/index-06-redoc-02.png) +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) ### Just Modern Python @@ -82,11 +83,11 @@ Here's how your editor might help you: * in Visual Studio Code: -![editor support](img/vscode-completion.png) +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) * in PyCharm: -![editor support](img/pycharm-completion.png) +![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png) You will get completion in code you might even consider impossible before. As for example, the `price` key inside a JSON body (that could have been nested) that comes from a request. diff --git a/docs/help-fastapi.md b/docs/en/docs/help-fastapi.md similarity index 99% rename from docs/help-fastapi.md rename to docs/en/docs/help-fastapi.md index 1370a5770..f69656583 100644 --- a/docs/help-fastapi.md +++ b/docs/en/docs/help-fastapi.md @@ -1,3 +1,5 @@ +# Help FastAPI - Get Help + Do you like **FastAPI**? Would you like to help FastAPI, other users, and the author? diff --git a/docs/history-design-future.md b/docs/en/docs/history-design-future.md similarity index 99% rename from docs/history-design-future.md rename to docs/en/docs/history-design-future.md index 08067e3c2..9db1027c2 100644 --- a/docs/history-design-future.md +++ b/docs/en/docs/history-design-future.md @@ -1,3 +1,5 @@ +# History, Design and Future + Some time ago, a **FastAPI** user asked: > What’s the history of this project? It seems to have come from nowhere to awesome in a few weeks [...] diff --git a/docs/img/favicon.png b/docs/en/docs/img/favicon.png similarity index 100% rename from docs/img/favicon.png rename to docs/en/docs/img/favicon.png diff --git a/docs/img/github-social-preview.png b/docs/en/docs/img/github-social-preview.png similarity index 100% rename from docs/img/github-social-preview.png rename to docs/en/docs/img/github-social-preview.png diff --git a/docs/img/github-social-preview.svg b/docs/en/docs/img/github-social-preview.svg similarity index 100% rename from docs/img/github-social-preview.svg rename to docs/en/docs/img/github-social-preview.svg diff --git a/docs/img/icon-transparent-bg.png b/docs/en/docs/img/icon-transparent-bg.png similarity index 100% rename from docs/img/icon-transparent-bg.png rename to docs/en/docs/img/icon-transparent-bg.png diff --git a/docs/img/icon-white-bg.png b/docs/en/docs/img/icon-white-bg.png similarity index 100% rename from docs/img/icon-white-bg.png rename to docs/en/docs/img/icon-white-bg.png diff --git a/docs/img/icon-white.svg b/docs/en/docs/img/icon-white.svg similarity index 100% rename from docs/img/icon-white.svg rename to docs/en/docs/img/icon-white.svg diff --git a/docs/img/index/index-01-swagger-ui-simple.png b/docs/en/docs/img/index/index-01-swagger-ui-simple.png similarity index 100% rename from docs/img/index/index-01-swagger-ui-simple.png rename to docs/en/docs/img/index/index-01-swagger-ui-simple.png diff --git a/docs/img/index/index-02-redoc-simple.png b/docs/en/docs/img/index/index-02-redoc-simple.png similarity index 100% rename from docs/img/index/index-02-redoc-simple.png rename to docs/en/docs/img/index/index-02-redoc-simple.png diff --git a/docs/img/index/index-03-swagger-02.png b/docs/en/docs/img/index/index-03-swagger-02.png similarity index 100% rename from docs/img/index/index-03-swagger-02.png rename to docs/en/docs/img/index/index-03-swagger-02.png diff --git a/docs/img/index/index-04-swagger-03.png b/docs/en/docs/img/index/index-04-swagger-03.png similarity index 100% rename from docs/img/index/index-04-swagger-03.png rename to docs/en/docs/img/index/index-04-swagger-03.png diff --git a/docs/img/index/index-05-swagger-04.png b/docs/en/docs/img/index/index-05-swagger-04.png similarity index 100% rename from docs/img/index/index-05-swagger-04.png rename to docs/en/docs/img/index/index-05-swagger-04.png diff --git a/docs/img/index/index-06-redoc-02.png b/docs/en/docs/img/index/index-06-redoc-02.png similarity index 100% rename from docs/img/index/index-06-redoc-02.png rename to docs/en/docs/img/index/index-06-redoc-02.png diff --git a/docs/img/logo-margin/logo-teal-vector.svg b/docs/en/docs/img/logo-margin/logo-teal-vector.svg similarity index 100% rename from docs/img/logo-margin/logo-teal-vector.svg rename to docs/en/docs/img/logo-margin/logo-teal-vector.svg diff --git a/docs/img/logo-margin/logo-teal.png b/docs/en/docs/img/logo-margin/logo-teal.png similarity index 100% rename from docs/img/logo-margin/logo-teal.png rename to docs/en/docs/img/logo-margin/logo-teal.png diff --git a/docs/img/logo-margin/logo-teal.svg b/docs/en/docs/img/logo-margin/logo-teal.svg similarity index 100% rename from docs/img/logo-margin/logo-teal.svg rename to docs/en/docs/img/logo-margin/logo-teal.svg diff --git a/docs/img/logo-margin/logo-white-bg.png b/docs/en/docs/img/logo-margin/logo-white-bg.png similarity index 100% rename from docs/img/logo-margin/logo-white-bg.png rename to docs/en/docs/img/logo-margin/logo-white-bg.png diff --git a/docs/img/logo-teal-vector.svg b/docs/en/docs/img/logo-teal-vector.svg similarity index 100% rename from docs/img/logo-teal-vector.svg rename to docs/en/docs/img/logo-teal-vector.svg diff --git a/docs/img/logo-teal.svg b/docs/en/docs/img/logo-teal.svg similarity index 100% rename from docs/img/logo-teal.svg rename to docs/en/docs/img/logo-teal.svg diff --git a/docs/img/pycharm-completion.png b/docs/en/docs/img/pycharm-completion.png similarity index 100% rename from docs/img/pycharm-completion.png rename to docs/en/docs/img/pycharm-completion.png diff --git a/docs/img/python-types/image01.png b/docs/en/docs/img/python-types/image01.png similarity index 100% rename from docs/img/python-types/image01.png rename to docs/en/docs/img/python-types/image01.png diff --git a/docs/img/python-types/image02.png b/docs/en/docs/img/python-types/image02.png similarity index 100% rename from docs/img/python-types/image02.png rename to docs/en/docs/img/python-types/image02.png diff --git a/docs/img/python-types/image03.png b/docs/en/docs/img/python-types/image03.png similarity index 100% rename from docs/img/python-types/image03.png rename to docs/en/docs/img/python-types/image03.png diff --git a/docs/img/python-types/image04.png b/docs/en/docs/img/python-types/image04.png similarity index 100% rename from docs/img/python-types/image04.png rename to docs/en/docs/img/python-types/image04.png diff --git a/docs/img/python-types/image05.png b/docs/en/docs/img/python-types/image05.png similarity index 100% rename from docs/img/python-types/image05.png rename to docs/en/docs/img/python-types/image05.png diff --git a/docs/img/python-types/image06.png b/docs/en/docs/img/python-types/image06.png similarity index 100% rename from docs/img/python-types/image06.png rename to docs/en/docs/img/python-types/image06.png diff --git a/docs/img/tutorial/additional-responses/image01.png b/docs/en/docs/img/tutorial/additional-responses/image01.png similarity index 100% rename from docs/img/tutorial/additional-responses/image01.png rename to docs/en/docs/img/tutorial/additional-responses/image01.png diff --git a/docs/img/tutorial/application-configuration/image01.png b/docs/en/docs/img/tutorial/application-configuration/image01.png similarity index 100% rename from docs/img/tutorial/application-configuration/image01.png rename to docs/en/docs/img/tutorial/application-configuration/image01.png diff --git a/docs/img/tutorial/async-sql-databases/image01.png b/docs/en/docs/img/tutorial/async-sql-databases/image01.png similarity index 100% rename from docs/img/tutorial/async-sql-databases/image01.png rename to docs/en/docs/img/tutorial/async-sql-databases/image01.png diff --git a/docs/img/tutorial/bigger-applications/image01.png b/docs/en/docs/img/tutorial/bigger-applications/image01.png similarity index 100% rename from docs/img/tutorial/bigger-applications/image01.png rename to docs/en/docs/img/tutorial/bigger-applications/image01.png diff --git a/docs/img/tutorial/body-fields/image01.png b/docs/en/docs/img/tutorial/body-fields/image01.png similarity index 100% rename from docs/img/tutorial/body-fields/image01.png rename to docs/en/docs/img/tutorial/body-fields/image01.png diff --git a/docs/img/tutorial/body-nested-models/image01.png b/docs/en/docs/img/tutorial/body-nested-models/image01.png similarity index 100% rename from docs/img/tutorial/body-nested-models/image01.png rename to docs/en/docs/img/tutorial/body-nested-models/image01.png diff --git a/docs/img/tutorial/body/image01.png b/docs/en/docs/img/tutorial/body/image01.png similarity index 100% rename from docs/img/tutorial/body/image01.png rename to docs/en/docs/img/tutorial/body/image01.png diff --git a/docs/img/tutorial/body/image02.png b/docs/en/docs/img/tutorial/body/image02.png similarity index 100% rename from docs/img/tutorial/body/image02.png rename to docs/en/docs/img/tutorial/body/image02.png diff --git a/docs/img/tutorial/body/image03.png b/docs/en/docs/img/tutorial/body/image03.png similarity index 100% rename from docs/img/tutorial/body/image03.png rename to docs/en/docs/img/tutorial/body/image03.png diff --git a/docs/img/tutorial/body/image04.png b/docs/en/docs/img/tutorial/body/image04.png similarity index 100% rename from docs/img/tutorial/body/image04.png rename to docs/en/docs/img/tutorial/body/image04.png diff --git a/docs/img/tutorial/body/image05.png b/docs/en/docs/img/tutorial/body/image05.png similarity index 100% rename from docs/img/tutorial/body/image05.png rename to docs/en/docs/img/tutorial/body/image05.png diff --git a/docs/img/tutorial/custom-response/image01.png b/docs/en/docs/img/tutorial/custom-response/image01.png similarity index 100% rename from docs/img/tutorial/custom-response/image01.png rename to docs/en/docs/img/tutorial/custom-response/image01.png diff --git a/docs/img/tutorial/debugging/image01.png b/docs/en/docs/img/tutorial/debugging/image01.png similarity index 100% rename from docs/img/tutorial/debugging/image01.png rename to docs/en/docs/img/tutorial/debugging/image01.png diff --git a/docs/img/tutorial/dependencies/image01.png b/docs/en/docs/img/tutorial/dependencies/image01.png similarity index 100% rename from docs/img/tutorial/dependencies/image01.png rename to docs/en/docs/img/tutorial/dependencies/image01.png diff --git a/docs/img/tutorial/dependencies/image02.png b/docs/en/docs/img/tutorial/dependencies/image02.png similarity index 100% rename from docs/img/tutorial/dependencies/image02.png rename to docs/en/docs/img/tutorial/dependencies/image02.png diff --git a/docs/img/tutorial/extending-openapi/image01.png b/docs/en/docs/img/tutorial/extending-openapi/image01.png similarity index 100% rename from docs/img/tutorial/extending-openapi/image01.png rename to docs/en/docs/img/tutorial/extending-openapi/image01.png diff --git a/docs/img/tutorial/graphql/image01.png b/docs/en/docs/img/tutorial/graphql/image01.png similarity index 100% rename from docs/img/tutorial/graphql/image01.png rename to docs/en/docs/img/tutorial/graphql/image01.png diff --git a/docs/img/tutorial/openapi-callbacks/image01.png b/docs/en/docs/img/tutorial/openapi-callbacks/image01.png similarity index 100% rename from docs/img/tutorial/openapi-callbacks/image01.png rename to docs/en/docs/img/tutorial/openapi-callbacks/image01.png diff --git a/docs/img/tutorial/path-operation-configuration/image01.png b/docs/en/docs/img/tutorial/path-operation-configuration/image01.png similarity index 100% rename from docs/img/tutorial/path-operation-configuration/image01.png rename to docs/en/docs/img/tutorial/path-operation-configuration/image01.png diff --git a/docs/img/tutorial/path-operation-configuration/image02.png b/docs/en/docs/img/tutorial/path-operation-configuration/image02.png similarity index 100% rename from docs/img/tutorial/path-operation-configuration/image02.png rename to docs/en/docs/img/tutorial/path-operation-configuration/image02.png diff --git a/docs/img/tutorial/path-operation-configuration/image03.png b/docs/en/docs/img/tutorial/path-operation-configuration/image03.png similarity index 100% rename from docs/img/tutorial/path-operation-configuration/image03.png rename to docs/en/docs/img/tutorial/path-operation-configuration/image03.png diff --git a/docs/img/tutorial/path-operation-configuration/image04.png b/docs/en/docs/img/tutorial/path-operation-configuration/image04.png similarity index 100% rename from docs/img/tutorial/path-operation-configuration/image04.png rename to docs/en/docs/img/tutorial/path-operation-configuration/image04.png diff --git a/docs/img/tutorial/path-operation-configuration/image05.png b/docs/en/docs/img/tutorial/path-operation-configuration/image05.png similarity index 100% rename from docs/img/tutorial/path-operation-configuration/image05.png rename to docs/en/docs/img/tutorial/path-operation-configuration/image05.png diff --git a/docs/img/tutorial/path-params/image01.png b/docs/en/docs/img/tutorial/path-params/image01.png similarity index 100% rename from docs/img/tutorial/path-params/image01.png rename to docs/en/docs/img/tutorial/path-params/image01.png diff --git a/docs/img/tutorial/path-params/image02.png b/docs/en/docs/img/tutorial/path-params/image02.png similarity index 100% rename from docs/img/tutorial/path-params/image02.png rename to docs/en/docs/img/tutorial/path-params/image02.png diff --git a/docs/img/tutorial/path-params/image03.png b/docs/en/docs/img/tutorial/path-params/image03.png similarity index 100% rename from docs/img/tutorial/path-params/image03.png rename to docs/en/docs/img/tutorial/path-params/image03.png diff --git a/docs/img/tutorial/query-params-str-validations/image01.png b/docs/en/docs/img/tutorial/query-params-str-validations/image01.png similarity index 100% rename from docs/img/tutorial/query-params-str-validations/image01.png rename to docs/en/docs/img/tutorial/query-params-str-validations/image01.png diff --git a/docs/img/tutorial/query-params-str-validations/image02.png b/docs/en/docs/img/tutorial/query-params-str-validations/image02.png similarity index 100% rename from docs/img/tutorial/query-params-str-validations/image02.png rename to docs/en/docs/img/tutorial/query-params-str-validations/image02.png diff --git a/docs/img/tutorial/response-model/image01.png b/docs/en/docs/img/tutorial/response-model/image01.png similarity index 100% rename from docs/img/tutorial/response-model/image01.png rename to docs/en/docs/img/tutorial/response-model/image01.png diff --git a/docs/img/tutorial/response-model/image02.png b/docs/en/docs/img/tutorial/response-model/image02.png similarity index 100% rename from docs/img/tutorial/response-model/image02.png rename to docs/en/docs/img/tutorial/response-model/image02.png diff --git a/docs/img/tutorial/response-status-code/image01.png b/docs/en/docs/img/tutorial/response-status-code/image01.png similarity index 100% rename from docs/img/tutorial/response-status-code/image01.png rename to docs/en/docs/img/tutorial/response-status-code/image01.png diff --git a/docs/img/tutorial/response-status-code/image02.png b/docs/en/docs/img/tutorial/response-status-code/image02.png similarity index 100% rename from docs/img/tutorial/response-status-code/image02.png rename to docs/en/docs/img/tutorial/response-status-code/image02.png diff --git a/docs/img/tutorial/security/image01.png b/docs/en/docs/img/tutorial/security/image01.png similarity index 100% rename from docs/img/tutorial/security/image01.png rename to docs/en/docs/img/tutorial/security/image01.png diff --git a/docs/img/tutorial/security/image02.png b/docs/en/docs/img/tutorial/security/image02.png similarity index 100% rename from docs/img/tutorial/security/image02.png rename to docs/en/docs/img/tutorial/security/image02.png diff --git a/docs/img/tutorial/security/image03.png b/docs/en/docs/img/tutorial/security/image03.png similarity index 100% rename from docs/img/tutorial/security/image03.png rename to docs/en/docs/img/tutorial/security/image03.png diff --git a/docs/img/tutorial/security/image04.png b/docs/en/docs/img/tutorial/security/image04.png similarity index 100% rename from docs/img/tutorial/security/image04.png rename to docs/en/docs/img/tutorial/security/image04.png diff --git a/docs/img/tutorial/security/image05.png b/docs/en/docs/img/tutorial/security/image05.png similarity index 100% rename from docs/img/tutorial/security/image05.png rename to docs/en/docs/img/tutorial/security/image05.png diff --git a/docs/img/tutorial/security/image06.png b/docs/en/docs/img/tutorial/security/image06.png similarity index 100% rename from docs/img/tutorial/security/image06.png rename to docs/en/docs/img/tutorial/security/image06.png diff --git a/docs/img/tutorial/security/image07.png b/docs/en/docs/img/tutorial/security/image07.png similarity index 100% rename from docs/img/tutorial/security/image07.png rename to docs/en/docs/img/tutorial/security/image07.png diff --git a/docs/img/tutorial/security/image08.png b/docs/en/docs/img/tutorial/security/image08.png similarity index 100% rename from docs/img/tutorial/security/image08.png rename to docs/en/docs/img/tutorial/security/image08.png diff --git a/docs/img/tutorial/security/image09.png b/docs/en/docs/img/tutorial/security/image09.png similarity index 100% rename from docs/img/tutorial/security/image09.png rename to docs/en/docs/img/tutorial/security/image09.png diff --git a/docs/img/tutorial/security/image10.png b/docs/en/docs/img/tutorial/security/image10.png similarity index 100% rename from docs/img/tutorial/security/image10.png rename to docs/en/docs/img/tutorial/security/image10.png diff --git a/docs/img/tutorial/security/image11.png b/docs/en/docs/img/tutorial/security/image11.png similarity index 100% rename from docs/img/tutorial/security/image11.png rename to docs/en/docs/img/tutorial/security/image11.png diff --git a/docs/img/tutorial/security/image12.png b/docs/en/docs/img/tutorial/security/image12.png similarity index 100% rename from docs/img/tutorial/security/image12.png rename to docs/en/docs/img/tutorial/security/image12.png diff --git a/docs/img/tutorial/sql-databases/image01.png b/docs/en/docs/img/tutorial/sql-databases/image01.png similarity index 100% rename from docs/img/tutorial/sql-databases/image01.png rename to docs/en/docs/img/tutorial/sql-databases/image01.png diff --git a/docs/img/tutorial/sql-databases/image02.png b/docs/en/docs/img/tutorial/sql-databases/image02.png similarity index 100% rename from docs/img/tutorial/sql-databases/image02.png rename to docs/en/docs/img/tutorial/sql-databases/image02.png diff --git a/docs/img/tutorial/sub-applications/image01.png b/docs/en/docs/img/tutorial/sub-applications/image01.png similarity index 100% rename from docs/img/tutorial/sub-applications/image01.png rename to docs/en/docs/img/tutorial/sub-applications/image01.png diff --git a/docs/img/tutorial/sub-applications/image02.png b/docs/en/docs/img/tutorial/sub-applications/image02.png similarity index 100% rename from docs/img/tutorial/sub-applications/image02.png rename to docs/en/docs/img/tutorial/sub-applications/image02.png diff --git a/docs/img/tutorial/websockets/image01.png b/docs/en/docs/img/tutorial/websockets/image01.png similarity index 100% rename from docs/img/tutorial/websockets/image01.png rename to docs/en/docs/img/tutorial/websockets/image01.png diff --git a/docs/img/tutorial/websockets/image02.png b/docs/en/docs/img/tutorial/websockets/image02.png similarity index 100% rename from docs/img/tutorial/websockets/image02.png rename to docs/en/docs/img/tutorial/websockets/image02.png diff --git a/docs/img/tutorial/websockets/image03.png b/docs/en/docs/img/tutorial/websockets/image03.png similarity index 100% rename from docs/img/tutorial/websockets/image03.png rename to docs/en/docs/img/tutorial/websockets/image03.png diff --git a/docs/img/tutorial/websockets/image04.png b/docs/en/docs/img/tutorial/websockets/image04.png similarity index 100% rename from docs/img/tutorial/websockets/image04.png rename to docs/en/docs/img/tutorial/websockets/image04.png diff --git a/docs/img/vscode-completion.png b/docs/en/docs/img/vscode-completion.png similarity index 100% rename from docs/img/vscode-completion.png rename to docs/en/docs/img/vscode-completion.png diff --git a/docs/index.md b/docs/en/docs/index.md similarity index 100% rename from docs/index.md rename to docs/en/docs/index.md diff --git a/docs/js/custom.js b/docs/en/docs/js/custom.js similarity index 100% rename from docs/js/custom.js rename to docs/en/docs/js/custom.js diff --git a/docs/js/termynal.js b/docs/en/docs/js/termynal.js similarity index 100% rename from docs/js/termynal.js rename to docs/en/docs/js/termynal.js diff --git a/docs/project-generation.md b/docs/en/docs/project-generation.md similarity index 99% rename from docs/project-generation.md rename to docs/en/docs/project-generation.md index 4562d6204..fd7a10fb7 100644 --- a/docs/project-generation.md +++ b/docs/en/docs/project-generation.md @@ -1,3 +1,5 @@ +# Project Generation - Template + There is a project generator that you can use to get started, with a lot of the initial set up, security, database and first API endpoints already done for you. ## Full-Stack-FastAPI-PostgreSQL diff --git a/docs/python-types.md b/docs/en/docs/python-types.md similarity index 92% rename from docs/python-types.md rename to docs/en/docs/python-types.md index 5d25e1816..ce24281ba 100644 --- a/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -1,3 +1,5 @@ +# Python Types Intro + **Python 3.6+** has support for optional "type hints". These **"type hints"** are a new syntax (since Python 3.6+) that allow declaring the type of a variable. @@ -18,7 +20,7 @@ But even if you never use **FastAPI**, you would benefit from learning a bit abo Let's start with a simple example: ```Python -{!./src/python_types/tutorial001.py!} +{!../../../docs_src/python_types/tutorial001.py!} ``` Calling this program outputs: @@ -34,7 +36,7 @@ The function does the following: * Concatenates them with a space in the middle. ```Python hl_lines="2" -{!./src/python_types/tutorial001.py!} +{!../../../docs_src/python_types/tutorial001.py!} ``` ### Edit it @@ -78,7 +80,7 @@ That's it. Those are the "type hints": ```Python hl_lines="1" -{!./src/python_types/tutorial002.py!} +{!../../../docs_src/python_types/tutorial002.py!} ``` That is not the same as declaring default values like would be with: @@ -108,7 +110,7 @@ With that, you can scroll, seeing the options, until you find the one that "ring Check this function, it already has type hints: ```Python hl_lines="1" -{!./src/python_types/tutorial003.py!} +{!../../../docs_src/python_types/tutorial003.py!} ``` Because the editor knows the types of the variables, you don't only get completion, you also get error checks: @@ -118,7 +120,7 @@ Because the editor knows the types of the variables, you don't only get completi Now you know that you have to fix it, convert `age` to a string with `str(age)`: ```Python hl_lines="2" -{!./src/python_types/tutorial004.py!} +{!../../../docs_src/python_types/tutorial004.py!} ``` ## Declaring types @@ -139,7 +141,7 @@ You can use, for example: * `bytes` ```Python hl_lines="1" -{!./src/python_types/tutorial005.py!} +{!../../../docs_src/python_types/tutorial005.py!} ``` ### Types with subtypes @@ -157,7 +159,7 @@ For example, let's define a variable to be a `list` of `str`. From `typing`, import `List` (with a capital `L`): ```Python hl_lines="1" -{!./src/python_types/tutorial006.py!} +{!../../../docs_src/python_types/tutorial006.py!} ``` Declare the variable, with the same colon (`:`) syntax. @@ -167,7 +169,7 @@ As the type, put the `List`. As the list is a type that takes a "subtype", you put the subtype in square brackets: ```Python hl_lines="4" -{!./src/python_types/tutorial006.py!} +{!../../../docs_src/python_types/tutorial006.py!} ``` That means: "the variable `items` is a `list`, and each of the items in this list is a `str`". @@ -187,7 +189,7 @@ And still, the editor knows it is a `str`, and provides support for that. You would do the same to declare `tuple`s and `set`s: ```Python hl_lines="1 4" -{!./src/python_types/tutorial007.py!} +{!../../../docs_src/python_types/tutorial007.py!} ``` This means: @@ -204,7 +206,7 @@ The first subtype is for the keys of the `dict`. The second subtype is for the values of the `dict`: ```Python hl_lines="1 4" -{!./src/python_types/tutorial008.py!} +{!../../../docs_src/python_types/tutorial008.py!} ``` This means: @@ -220,13 +222,13 @@ You can also declare a class as the type of a variable. Let's say you have a class `Person`, with a name: ```Python hl_lines="1 2 3" -{!./src/python_types/tutorial009.py!} +{!../../../docs_src/python_types/tutorial009.py!} ``` Then you can declare a variable to be of type `Person`: ```Python hl_lines="6" -{!./src/python_types/tutorial009.py!} +{!../../../docs_src/python_types/tutorial009.py!} ``` And then, again, you get all the editor support: @@ -248,7 +250,7 @@ And you get all the editor support with that resulting object. Taken from the official Pydantic docs: ```Python -{!./src/python_types/tutorial010.py!} +{!../../../docs_src/python_types/tutorial010.py!} ``` !!! info diff --git a/docs/release-notes.md b/docs/en/docs/release-notes.md similarity index 99% rename from docs/release-notes.md rename to docs/en/docs/release-notes.md index 08d880650..d5218e063 100644 --- a/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -1,3 +1,5 @@ +# Release Notes + ## Latest changes * Update terminal styles in docs and add note about [**Typer**, the FastAPI of CLIs](https://typer.tiangolo.com/). PR [#1139](https://github.com/tiangolo/fastapi/pull/1139). diff --git a/docs/tutorial/application-configuration.md b/docs/en/docs/tutorial/application-configuration.md similarity index 87% rename from docs/tutorial/application-configuration.md rename to docs/en/docs/tutorial/application-configuration.md index 706ecd348..978273cc1 100644 --- a/docs/tutorial/application-configuration.md +++ b/docs/en/docs/tutorial/application-configuration.md @@ -1,3 +1,5 @@ +# Application Configuration + There are several things that you can configure in your FastAPI application. ## Title, description, and version @@ -12,7 +14,7 @@ You can set the: To set them, use the parameters `title`, `description`, and `version`: ```Python hl_lines="4 5 6" -{!./src/application_configuration/tutorial001.py!} +{!../../../docs_src/application_configuration/tutorial001.py!} ``` With this configuration, the automatic API docs would look like: @@ -28,7 +30,7 @@ But you can configure it with the parameter `openapi_url`. For example, to set it to be served at `/api/v1/openapi.json`: ```Python hl_lines="3" -{!./src/application_configuration/tutorial002.py!} +{!../../../docs_src/application_configuration/tutorial002.py!} ``` If you want to disable the OpenAPI schema completely you can set `openapi_url=None`. @@ -47,5 +49,5 @@ You can configure the two documentation user interfaces included: For example, to set Swagger UI to be served at `/documentation` and disable ReDoc: ```Python hl_lines="3" -{!./src/application_configuration/tutorial003.py!} +{!../../../docs_src/application_configuration/tutorial003.py!} ``` diff --git a/docs/tutorial/background-tasks.md b/docs/en/docs/tutorial/background-tasks.md similarity index 95% rename from docs/tutorial/background-tasks.md rename to docs/en/docs/tutorial/background-tasks.md index 15b92e8f5..3771eff71 100644 --- a/docs/tutorial/background-tasks.md +++ b/docs/en/docs/tutorial/background-tasks.md @@ -1,3 +1,5 @@ +# Background Tasks + You can define background tasks to be run *after* returning a response. This is useful for operations that need to happen after a request, but that the client doesn't really have to be waiting for the operation to complete before receiving his response. @@ -14,7 +16,7 @@ This includes, for example: First, import `BackgroundTasks` and define a parameter in your *path operation function* with a type declaration of `BackgroundTasks`: ```Python hl_lines="1 13" -{!./src/background_tasks/tutorial001.py!} +{!../../../docs_src/background_tasks/tutorial001.py!} ``` **FastAPI** will create the object of type `BackgroundTasks` for you and pass it as that parameter. @@ -32,7 +34,7 @@ In this case, the task function will write to a file (simulating sending an emai And as the write operation doesn't use `async` and `await`, we define the function with normal `def`: ```Python hl_lines="6 7 8 9" -{!./src/background_tasks/tutorial001.py!} +{!../../../docs_src/background_tasks/tutorial001.py!} ``` ## Add the background task @@ -40,7 +42,7 @@ And as the write operation doesn't use `async` and `await`, we define the functi Inside of your *path operation function*, pass your task function to the *background tasks* object with the method `.add_task()`: ```Python hl_lines="14" -{!./src/background_tasks/tutorial001.py!} +{!../../../docs_src/background_tasks/tutorial001.py!} ``` `.add_task()` receives as arguments: @@ -56,7 +58,7 @@ Using `BackgroundTasks` also works with the dependency injection system, you can **FastAPI** knows what to do in each case and how to re-use the same object, so that all the background tasks are merged together and are run in the background afterwards: ```Python hl_lines="11 14 20 23" -{!./src/background_tasks/tutorial002.py!} +{!../../../docs_src/background_tasks/tutorial002.py!} ``` In this example, the messages will be written to the `log.txt` file *after* the response is sent. diff --git a/docs/tutorial/bigger-applications.md b/docs/en/docs/tutorial/bigger-applications.md similarity index 95% rename from docs/tutorial/bigger-applications.md rename to docs/en/docs/tutorial/bigger-applications.md index f6c623b84..0d3be0f16 100644 --- a/docs/tutorial/bigger-applications.md +++ b/docs/en/docs/tutorial/bigger-applications.md @@ -1,3 +1,5 @@ +# Bigger Applications - Multiple Files + If you are building an application or a web API, it's rarely the case that you can put everything on a single file. **FastAPI** provides a convenience tool to structure your application while keeping all the flexibility. @@ -59,7 +61,7 @@ You can create the *path operations* for that module using `APIRouter`. You import it and create an "instance" the same way you would with the class `FastAPI`: ```Python hl_lines="1 3" -{!./src/bigger_applications/app/routers/users.py!} +{!../../../docs_src/bigger_applications/app/routers/users.py!} ``` ### *Path operations* with `APIRouter` @@ -69,7 +71,7 @@ And then you use it to declare your *path operations*. Use it the same way you would use the `FastAPI` class: ```Python hl_lines="6 11 16" -{!./src/bigger_applications/app/routers/users.py!} +{!../../../docs_src/bigger_applications/app/routers/users.py!} ``` You can think of `APIRouter` as a "mini `FastAPI`" class. @@ -99,7 +101,7 @@ But let's say that this time we are more lazy. And we don't want to have to explicitly type `/items/` and `tags=["items"]` in every *path operation* (we will be able to do it later): ```Python hl_lines="6 11" -{!./src/bigger_applications/app/routers/items.py!} +{!../../../docs_src/bigger_applications/app/routers/items.py!} ``` ### Add some custom `tags`, `responses`, and `dependencies` @@ -109,7 +111,7 @@ We are not adding the prefix `/items/` nor the `tags=["items"]` to add them late But we can add custom `tags` and `responses` that will be applied to a specific *path operation*: ```Python hl_lines="18 19" -{!./src/bigger_applications/app/routers/items.py!} +{!../../../docs_src/bigger_applications/app/routers/items.py!} ``` ## The main `FastAPI` @@ -125,7 +127,7 @@ This will be the main file in your application that ties everything together. You import and create a `FastAPI` class as normally: ```Python hl_lines="1 5" -{!./src/bigger_applications/app/main.py!} +{!../../../docs_src/bigger_applications/app/main.py!} ``` ### Import the `APIRouter` @@ -135,7 +137,7 @@ But this time we are not adding *path operations* directly with the `FastAPI` `a We import the other submodules that have `APIRouter`s: ```Python hl_lines="3" -{!./src/bigger_applications/app/main.py!} +{!../../../docs_src/bigger_applications/app/main.py!} ``` As the file `app/routers/items.py` is part of the same Python package, we can import it using "dot notation". @@ -187,7 +189,7 @@ The `router` from `users` would overwrite the one from `items` and we wouldn't b So, to be able to use both of them in the same file, we import the submodules directly: ```Python hl_lines="3" -{!./src/bigger_applications/app/main.py!} +{!../../../docs_src/bigger_applications/app/main.py!} ``` ### Include an `APIRouter` @@ -195,7 +197,7 @@ So, to be able to use both of them in the same file, we import the submodules di Now, let's include the `router` from the submodule `users`: ```Python hl_lines="13" -{!./src/bigger_applications/app/main.py!} +{!../../../docs_src/bigger_applications/app/main.py!} ``` !!! info @@ -244,7 +246,7 @@ And we can add predefined `responses` that will be included in all the *path ope And we can add a list of `dependencies` that will be added to all the *path operations* in the router and will be executed/solved for each request made to them. Note that, much like dependencies in *path operation decorators*, no value will be passed to your *path operation function*. ```Python hl_lines="8 9 10 14 15 16 17 18 19 20" -{!./src/bigger_applications/app/main.py!} +{!../../../docs_src/bigger_applications/app/main.py!} ``` The end result is that the item paths are now: diff --git a/docs/tutorial/body-fields.md b/docs/en/docs/tutorial/body-fields.md similarity index 93% rename from docs/tutorial/body-fields.md rename to docs/en/docs/tutorial/body-fields.md index f54ed4eb8..daba2eaff 100644 --- a/docs/tutorial/body-fields.md +++ b/docs/en/docs/tutorial/body-fields.md @@ -1,3 +1,5 @@ +# Body - Fields + The same way you can declare additional validation and metadata in *path operation function* parameters with `Query`, `Path` and `Body`, you can declare validation and metadata inside of Pydantic models using Pydantic's `Field`. ## Import `Field` @@ -5,7 +7,7 @@ The same way you can declare additional validation and metadata in *path operati First, you have to import it: ```Python hl_lines="2" -{!./src/body_fields/tutorial001.py!} +{!../../../docs_src/body_fields/tutorial001.py!} ``` !!! warning @@ -16,7 +18,7 @@ First, you have to import it: You can then use `Field` with model attributes: ```Python hl_lines="9 10" -{!./src/body_fields/tutorial001.py!} +{!../../../docs_src/body_fields/tutorial001.py!} ``` `Field` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc. @@ -47,7 +49,7 @@ If you know JSON Schema and want to add extra information apart from what we hav For example, you can use that functionality to pass a JSON Schema example field to a body request JSON Schema: ```Python hl_lines="20 21 22 23 24 25" -{!./src/body_fields/tutorial002.py!} +{!../../../docs_src/body_fields/tutorial002.py!} ``` And it would look in the `/docs` like this: diff --git a/docs/tutorial/body-multiple-params.md b/docs/en/docs/tutorial/body-multiple-params.md similarity index 93% rename from docs/tutorial/body-multiple-params.md rename to docs/en/docs/tutorial/body-multiple-params.md index 5009c21bf..6d5e6e39d 100644 --- a/docs/tutorial/body-multiple-params.md +++ b/docs/en/docs/tutorial/body-multiple-params.md @@ -1,3 +1,5 @@ +# Body - Multiple Parameters + Now that we have seen how to use `Path` and `Query`, let's see more advanced uses of request body declarations. ## Mix `Path`, `Query` and body parameters @@ -7,7 +9,7 @@ First, of course, you can mix `Path`, `Query` and request body parameter declara And you can also declare body parameters as optional, by setting the default to `None`: ```Python hl_lines="17 18 19" -{!./src/body_multiple_params/tutorial001.py!} +{!../../../docs_src/body_multiple_params/tutorial001.py!} ``` !!! note @@ -29,7 +31,7 @@ In the previous example, the *path operations* would expect a JSON body with the But you can also declare multiple body parameters, e.g. `item` and `user`: ```Python hl_lines="20" -{!./src/body_multiple_params/tutorial002.py!} +{!../../../docs_src/body_multiple_params/tutorial002.py!} ``` In this case, **FastAPI** will notice that there are more than one body parameters in the function (two parameters that are Pydantic models). @@ -71,7 +73,7 @@ But you can instruct **FastAPI** to treat it as another body key using `Body`: ```Python hl_lines="21" -{!./src/body_multiple_params/tutorial003.py!} +{!../../../docs_src/body_multiple_params/tutorial003.py!} ``` In this case, **FastAPI** will expect a body like: @@ -108,7 +110,7 @@ q: str = None as in: ```Python hl_lines="25" -{!./src/body_multiple_params/tutorial004.py!} +{!../../../docs_src/body_multiple_params/tutorial004.py!} ``` !!! info @@ -130,7 +132,7 @@ item: Item = Body(..., embed=True) as in: ```Python hl_lines="15" -{!./src/body_multiple_params/tutorial005.py!} +{!../../../docs_src/body_multiple_params/tutorial005.py!} ``` In this case **FastAPI** will expect a body like: diff --git a/docs/tutorial/body-nested-models.md b/docs/en/docs/tutorial/body-nested-models.md similarity index 90% rename from docs/tutorial/body-nested-models.md rename to docs/en/docs/tutorial/body-nested-models.md index d5c5c9575..993389c90 100644 --- a/docs/tutorial/body-nested-models.md +++ b/docs/en/docs/tutorial/body-nested-models.md @@ -1,3 +1,5 @@ +# Body - Nested Models + With **FastAPI**, you can define, validate, document, and use arbitrarily deeply nested models (thanks to Pydantic). ## List fields @@ -5,7 +7,7 @@ With **FastAPI**, you can define, validate, document, and use arbitrarily deeply You can define an attribute to be a subtype. For example, a Python `list`: ```Python hl_lines="12" -{!./src/body_nested_models/tutorial001.py!} +{!../../../docs_src/body_nested_models/tutorial001.py!} ``` This will make `tags` be a list of items. Although it doesn't declare the type of each of the items. @@ -19,7 +21,7 @@ But Python has a specific way to declare lists with subtypes: First, import `List` from standard Python's `typing` module: ```Python hl_lines="1" -{!./src/body_nested_models/tutorial002.py!} +{!../../../docs_src/body_nested_models/tutorial002.py!} ``` ### Declare a `List` with a subtype @@ -42,7 +44,7 @@ Use that same standard syntax for model attributes with subtypes. So, in our example, we can make `tags` be specifically a "list of strings": ```Python hl_lines="14" -{!./src/body_nested_models/tutorial002.py!} +{!../../../docs_src/body_nested_models/tutorial002.py!} ``` ## Set types @@ -54,7 +56,7 @@ And Python has a special data type for sets of unique items, the `set`. Then we can import `Set` and declare `tags` as a `set` of `str`: ```Python hl_lines="1 14" -{!./src/body_nested_models/tutorial003.py!} +{!../../../docs_src/body_nested_models/tutorial003.py!} ``` With this, even if you receive a request with duplicate data, it will be converted to a set of unique items. @@ -78,7 +80,7 @@ All that, arbitrarily nested. For example, we can define an `Image` model: ```Python hl_lines="9 10 11" -{!./src/body_nested_models/tutorial004.py!} +{!../../../docs_src/body_nested_models/tutorial004.py!} ``` ### Use the submodel as a type @@ -86,7 +88,7 @@ For example, we can define an `Image` model: And then we can use it as the type of an attribute: ```Python hl_lines="20" -{!./src/body_nested_models/tutorial004.py!} +{!../../../docs_src/body_nested_models/tutorial004.py!} ``` This would mean that **FastAPI** would expect a body similar to: @@ -121,7 +123,7 @@ To see all the options you have, checkout the docs for HTTP `PUT` operation. @@ -5,7 +7,7 @@ To update an item you can use the CORS or "Cross-Origin Resource Sharing" refers to the situations when a frontend running in a browser has JavaScript code that communicates with a backend, and the backend is in a different "origin" than the frontend. ## Origin @@ -45,7 +47,7 @@ You can also specify if your backend allows: * Specific HTTP headers or all of them with the wildcard `"*"`. ```Python hl_lines="2 6 7 8 9 10 11 13 14 15 16 17 18 19" -{!./src/cors/tutorial001.py!} +{!../../../docs_src/cors/tutorial001.py!} ``` The default parameters used by the `CORSMiddleware` implementation are restrictive by default, so you'll need to explicitly enable particular origins, methods, or headers, in order for browsers to be permitted to use them in a Cross-Domain context. diff --git a/docs/tutorial/debugging.md b/docs/en/docs/tutorial/debugging.md similarity index 97% rename from docs/tutorial/debugging.md rename to docs/en/docs/tutorial/debugging.md index e527bf971..733ae32a1 100644 --- a/docs/tutorial/debugging.md +++ b/docs/en/docs/tutorial/debugging.md @@ -1,3 +1,5 @@ +# Debugging + You can connect the debugger in your editor, for example with Visual Studio Code or PyCharm. ## Call `uvicorn` @@ -5,7 +7,7 @@ You can connect the debugger in your editor, for example with Visual Studio Code In your FastAPI application, import and run `uvicorn` directly: ```Python hl_lines="1 15" -{!./src/debugging/tutorial001.py!} +{!../../../docs_src/debugging/tutorial001.py!} ``` ### About `__name__ == "__main__"` diff --git a/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md similarity index 93% rename from docs/tutorial/dependencies/classes-as-dependencies.md rename to docs/en/docs/tutorial/dependencies/classes-as-dependencies.md index 674615410..b4d78af84 100644 --- a/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md @@ -1,3 +1,5 @@ +# Classes as Dependencies + Before diving deeper into the **Dependency Injection** system, let's upgrade the previous example. ## A `dict` from the previous example @@ -5,7 +7,7 @@ Before diving deeper into the **Dependency Injection** system, let's upgrade the In the previous example, we were returning a `dict` from our dependency ("dependable"): ```Python hl_lines="7" -{!./src/dependencies/tutorial001.py!} +{!../../../docs_src/dependencies/tutorial001.py!} ``` But then we get a `dict` in the parameter `commons` of the *path operation function*. @@ -70,19 +72,19 @@ That also applies to callables with no parameters at all. The same as it would b Then, we can change the dependency "dependable" `common_parameters` from above to the class `CommonQueryParameters`: ```Python hl_lines="9 10 11 12 13" -{!./src/dependencies/tutorial002.py!} +{!../../../docs_src/dependencies/tutorial002.py!} ``` Pay attention to the `__init__` method used to create the instance of the class: ```Python hl_lines="10" -{!./src/dependencies/tutorial002.py!} +{!../../../docs_src/dependencies/tutorial002.py!} ``` ...it has the same parameters as our previous `common_parameters`: ```Python hl_lines="6" -{!./src/dependencies/tutorial001.py!} +{!../../../docs_src/dependencies/tutorial001.py!} ``` Those parameters are what **FastAPI** will use to "solve" the dependency. @@ -102,7 +104,7 @@ Now you can declare your dependency using this class. And as when **FastAPI** calls that class the value that will be passed as `commons` to your function will be an "instance" of the class, you can declare that parameter `commons` to be of type of the class, `CommonQueryParams`. ```Python hl_lines="17" -{!./src/dependencies/tutorial002.py!} +{!../../../docs_src/dependencies/tutorial002.py!} ``` ## Type annotation vs `Depends` @@ -142,7 +144,7 @@ commons = Depends(CommonQueryParams) ..as in: ```Python hl_lines="17" -{!./src/dependencies/tutorial003.py!} +{!../../../docs_src/dependencies/tutorial003.py!} ``` But declaring the type is encouraged as that way your editor will know what will be passed as the parameter `commons`, and then it can help you with code completion, type checks, etc: @@ -178,7 +180,7 @@ So, you can declare the dependency as the type of the variable, and use `Depends So, the same example would look like: ```Python hl_lines="17" -{!./src/dependencies/tutorial004.py!} +{!../../../docs_src/dependencies/tutorial004.py!} ``` ...and **FastAPI** will know what to do. diff --git a/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md similarity index 89% rename from docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md rename to docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md index 7e774d520..64e03139c 100644 --- a/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md @@ -1,3 +1,5 @@ +# Dependencies in path operation decorators + In some cases you don't really need the return value of a dependency inside your *path operation function*. Or the dependency doesn't return a value. @@ -13,7 +15,7 @@ The *path operation decorator* receives an optional argument `dependencies`. It should be a `list` of `Depends()`: ```Python hl_lines="17" -{!./src/dependencies/tutorial006.py!} +{!../../../docs_src/dependencies/tutorial006.py!} ``` These dependencies will be executed/solved the same way normal dependencies. But their value (if they return any) won't be passed to your *path operation function*. @@ -34,7 +36,7 @@ You can use the same dependency *functions* you use normally. They can declare request requirements (like headers) or other sub-dependencies: ```Python hl_lines="6 11" -{!./src/dependencies/tutorial006.py!} +{!../../../docs_src/dependencies/tutorial006.py!} ``` ### Raise exceptions @@ -42,7 +44,7 @@ They can declare request requirements (like headers) or other sub-dependencies: These dependencies can `raise` exceptions, the same as normal dependencies: ```Python hl_lines="8 13" -{!./src/dependencies/tutorial006.py!} +{!../../../docs_src/dependencies/tutorial006.py!} ``` ### Return values @@ -52,7 +54,7 @@ And they can return values or not, the values won't be used. So, you can re-use a normal dependency (that returns a value) you already use somewhere else, and even though the value won't be used, the dependency will be executed: ```Python hl_lines="9 14" -{!./src/dependencies/tutorial006.py!} +{!../../../docs_src/dependencies/tutorial006.py!} ``` ## Dependencies for a group of *path operations* diff --git a/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md similarity index 96% rename from docs/tutorial/dependencies/dependencies-with-yield.md rename to docs/en/docs/tutorial/dependencies/dependencies-with-yield.md index 08d600a5a..1c8cdba65 100644 --- a/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md @@ -1,4 +1,4 @@ -# Dependencies with `yield` +# Dependencies with yield FastAPI supports dependencies that do some extra steps after finishing. @@ -33,19 +33,19 @@ For example, you could use this to create a database session and close it after Only the code prior to and including the `yield` statement is executed before sending a response: ```Python hl_lines="2 3 4" -{!./src/dependencies/tutorial007.py!} +{!../../../docs_src/dependencies/tutorial007.py!} ``` The yielded value is what is injected into *path operations* and other dependencies: ```Python hl_lines="4" -{!./src/dependencies/tutorial007.py!} +{!../../../docs_src/dependencies/tutorial007.py!} ``` The code following the `yield` statement is executed after the response has been delivered: ```Python hl_lines="5 6" -{!./src/dependencies/tutorial007.py!} +{!../../../docs_src/dependencies/tutorial007.py!} ``` !!! tip @@ -64,7 +64,7 @@ So, you can look for that specific exception inside the dependency with `except In the same way, you can use `finally` to make sure the exit steps are executed, no matter if there was an exception or not. ```Python hl_lines="3 5" -{!./src/dependencies/tutorial007.py!} +{!../../../docs_src/dependencies/tutorial007.py!} ``` ## Sub-dependencies with `yield` @@ -76,7 +76,7 @@ You can have sub-dependencies and "trees" of sub-dependencies of any size and sh For example, `dependency_c` can have a dependency on `dependency_b`, and `dependency_b` on `dependency_a`: ```Python hl_lines="4 12 20" -{!./src/dependencies/tutorial008.py!} +{!../../../docs_src/dependencies/tutorial008.py!} ``` And all of them can use `yield`. @@ -86,7 +86,7 @@ In this case `dependency_c`, to execute its exit code, needs the value from `dep And, in turn, `dependency_b` needs the value from `dependency_a` (here named `dep_a`) to be available for its exit code. ```Python hl_lines="16 17 24 25" -{!./src/dependencies/tutorial008.py!} +{!../../../docs_src/dependencies/tutorial008.py!} ``` The same way, you could have dependencies with `yield` and `return` mixed. @@ -208,7 +208,7 @@ You can also use them inside of **FastAPI** dependencies with `yield` by using `with` or `async with` statements inside of the dependency function: ```Python hl_lines="1 2 3 4 5 6 7 8 9 13" -{!./src/dependencies/tutorial010.py!} +{!../../../docs_src/dependencies/tutorial010.py!} ``` !!! tip diff --git a/docs/tutorial/dependencies/index.md b/docs/en/docs/tutorial/dependencies/index.md similarity index 97% rename from docs/tutorial/dependencies/index.md rename to docs/en/docs/tutorial/dependencies/index.md index c92dcebf6..5b8d11ea7 100644 --- a/docs/tutorial/dependencies/index.md +++ b/docs/en/docs/tutorial/dependencies/index.md @@ -1,3 +1,5 @@ +# Dependencies - First Steps + **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**. @@ -30,7 +32,7 @@ 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!} +{!../../../docs_src/dependencies/tutorial001.py!} ``` That's it. @@ -54,7 +56,7 @@ And then it just returns a `dict` containing those values. ### Import `Depends` ```Python hl_lines="1" -{!./src/dependencies/tutorial001.py!} +{!../../../docs_src/dependencies/tutorial001.py!} ``` ### Declare the dependency, in the "dependant" @@ -62,7 +64,7 @@ And then it just returns a `dict` containing those values. 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!} +{!../../../docs_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. diff --git a/docs/tutorial/dependencies/sub-dependencies.md b/docs/en/docs/tutorial/dependencies/sub-dependencies.md similarity index 95% rename from docs/tutorial/dependencies/sub-dependencies.md rename to docs/en/docs/tutorial/dependencies/sub-dependencies.md index 340773380..71b1404d6 100644 --- a/docs/tutorial/dependencies/sub-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/sub-dependencies.md @@ -1,3 +1,5 @@ +# Sub-dependencies + You can create dependencies that have **sub-dependencies**. They can be as **deep** as you need them to be. @@ -9,7 +11,7 @@ They can be as **deep** as you need them to be. You could create a first dependency ("dependable") like: ```Python hl_lines="6 7" -{!./src/dependencies/tutorial005.py!} +{!../../../docs_src/dependencies/tutorial005.py!} ``` It declares an optional query parameter `q` as a `str`, and then it just returns it. @@ -21,7 +23,7 @@ This is quite simple (not very useful), but will help us focus on how the sub-de Then you can create another dependency function (a "dependable") that at the same time declares a dependency of its own (so it is a "dependant" too): ```Python hl_lines="11" -{!./src/dependencies/tutorial005.py!} +{!../../../docs_src/dependencies/tutorial005.py!} ``` Let's focus on the parameters declared: @@ -36,7 +38,7 @@ Let's focus on the parameters declared: Then we can use the dependency with: ```Python hl_lines="19" -{!./src/dependencies/tutorial005.py!} +{!../../../docs_src/dependencies/tutorial005.py!} ``` !!! info diff --git a/docs/tutorial/encoder.md b/docs/en/docs/tutorial/encoder.md similarity index 95% rename from docs/tutorial/encoder.md rename to docs/en/docs/tutorial/encoder.md index 4ce940eca..3879f976a 100644 --- a/docs/tutorial/encoder.md +++ b/docs/en/docs/tutorial/encoder.md @@ -1,3 +1,5 @@ +# JSON Compatible Encoder + There are some cases where you might need to convert a data type (like a Pydantic model) to something compatible with JSON (like a `dict`, `list`, etc). For example, if you need to store it in a database. @@ -19,7 +21,7 @@ You can use `jsonable_encoder` for that. It receives an object, like a Pydantic model, and returns a JSON compatible version: ```Python hl_lines="4 21" -{!./src/encoder/tutorial001.py!} +{!../../../docs_src/encoder/tutorial001.py!} ``` In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`. diff --git a/docs/tutorial/extra-data-types.md b/docs/en/docs/tutorial/extra-data-types.md similarity index 94% rename from docs/tutorial/extra-data-types.md rename to docs/en/docs/tutorial/extra-data-types.md index 7534be86d..07c1ed06f 100644 --- a/docs/tutorial/extra-data-types.md +++ b/docs/en/docs/tutorial/extra-data-types.md @@ -1,3 +1,5 @@ +# Extra Data Types + Up to now, you have been using common data types, like: * `int` @@ -53,11 +55,11 @@ Here are some of the additional data types you can use: Here's an example *path operation* with parameters using some of the above types. ```Python hl_lines="1 2 11 12 13 14 15" -{!./src/extra_data_types/tutorial001.py!} +{!../../../docs_src/extra_data_types/tutorial001.py!} ``` Note that the parameters inside the function have their natural data type, and you can, for example, perform normal date manipulations, like: ```Python hl_lines="17 18" -{!./src/extra_data_types/tutorial001.py!} +{!../../../docs_src/extra_data_types/tutorial001.py!} ``` diff --git a/docs/tutorial/extra-models.md b/docs/en/docs/tutorial/extra-models.md similarity index 95% rename from docs/tutorial/extra-models.md rename to docs/en/docs/tutorial/extra-models.md index 731a73f3d..5b8bf5a2b 100644 --- a/docs/tutorial/extra-models.md +++ b/docs/en/docs/tutorial/extra-models.md @@ -1,3 +1,5 @@ +# Extra Models + Continuing with the previous example, it will be common to have more than one related model. This is especially the case for user models, because: @@ -16,7 +18,7 @@ This is especially the case for user models, because: Here's a general idea of how the models could look like with their password fields and the places where they are used: ```Python hl_lines="7 9 14 20 22 27 28 31 32 33 38 39" -{!./src/extra_models/tutorial001.py!} +{!../../../docs_src/extra_models/tutorial001.py!} ``` ### About `**user_in.dict()` @@ -149,7 +151,7 @@ All the data conversion, validation, documentation, etc. will still work as norm That way, we can declare just the differences between the models (with plaintext `password`, with `hashed_password` and without password): ```Python hl_lines="7 13 14 17 18 21 22" -{!./src/extra_models/tutorial002.py!} +{!../../../docs_src/extra_models/tutorial002.py!} ``` ## `Union` or `anyOf` @@ -161,7 +163,7 @@ It will be defined in OpenAPI with `anyOf`. To do that, use the standard Python type hint `typing.Union`: ```Python hl_lines="1 14 15 18 19 20 33" -{!./src/extra_models/tutorial003.py!} +{!../../../docs_src/extra_models/tutorial003.py!} ``` ## List of models @@ -171,7 +173,7 @@ The same way, you can declare responses of lists of objects. For that, use the standard Python `typing.List`: ```Python hl_lines="1 20" -{!./src/extra_models/tutorial004.py!} +{!../../../docs_src/extra_models/tutorial004.py!} ``` ## Response with arbitrary `dict` @@ -183,7 +185,7 @@ This is useful if you don't know the valid field/attribute names (that would be In this case, you can use `typing.Dict`: ```Python hl_lines="1 8" -{!./src/extra_models/tutorial005.py!} +{!../../../docs_src/extra_models/tutorial005.py!} ``` ## Recap diff --git a/docs/tutorial/first-steps.md b/docs/en/docs/tutorial/first-steps.md similarity index 95% rename from docs/tutorial/first-steps.md rename to docs/en/docs/tutorial/first-steps.md index 639cfed39..2d212762e 100644 --- a/docs/tutorial/first-steps.md +++ b/docs/en/docs/tutorial/first-steps.md @@ -1,7 +1,9 @@ +# First Steps + The simplest FastAPI file could look like this: ```Python -{!./src/first_steps/tutorial001.py!} +{!../../../docs_src/first_steps/tutorial001.py!} ``` Copy that to a file `main.py`. @@ -129,7 +131,7 @@ You could also use it to generate code automatically, for clients that communica ### Step 1: import `FastAPI` ```Python hl_lines="1" -{!./src/first_steps/tutorial001.py!} +{!../../../docs_src/first_steps/tutorial001.py!} ``` `FastAPI` is a Python class that provides all the functionality for your API. @@ -142,7 +144,7 @@ You could also use it to generate code automatically, for clients that communica ### Step 2: create a `FastAPI` "instance" ```Python hl_lines="3" -{!./src/first_steps/tutorial001.py!} +{!../../../docs_src/first_steps/tutorial001.py!} ``` Here the `app` variable will be an "instance" of the class `FastAPI`. @@ -164,7 +166,7 @@ $ uvicorn main:app --reload If you create your app like: ```Python hl_lines="3" -{!./src/first_steps/tutorial002.py!} +{!../../../docs_src/first_steps/tutorial002.py!} ``` And put it in a file `main.py`, then you would call `uvicorn` like: @@ -240,7 +242,7 @@ We are going to call them "**operations**" too. #### Define a *path operation function* ```Python hl_lines="6" -{!./src/first_steps/tutorial001.py!} +{!../../../docs_src/first_steps/tutorial001.py!} ``` The `@app.get("/")` tells **FastAPI** that the function right below is in charge of handling requests that go to: @@ -290,7 +292,7 @@ This is our "**path operation function**": * **function**: is the function below the "decorator" (below `@app.get("/")`). ```Python hl_lines="7" -{!./src/first_steps/tutorial001.py!} +{!../../../docs_src/first_steps/tutorial001.py!} ``` This is a Python function. @@ -304,7 +306,7 @@ In this case, it is an `async` function. You could also define it as a normal function instead of `async def`: ```Python hl_lines="7" -{!./src/first_steps/tutorial003.py!} +{!../../../docs_src/first_steps/tutorial003.py!} ``` !!! note @@ -313,7 +315,7 @@ You could also define it as a normal function instead of `async def`: ### Step 5: return the content ```Python hl_lines="8" -{!./src/first_steps/tutorial001.py!} +{!../../../docs_src/first_steps/tutorial001.py!} ``` You can return a `dict`, `list`, singular values as `str`, `int`, etc. diff --git a/docs/tutorial/handling-errors.md b/docs/en/docs/tutorial/handling-errors.md similarity index 95% rename from docs/tutorial/handling-errors.md rename to docs/en/docs/tutorial/handling-errors.md index 8ae9ff47e..99ecc2dc8 100644 --- a/docs/tutorial/handling-errors.md +++ b/docs/en/docs/tutorial/handling-errors.md @@ -1,3 +1,5 @@ +# Handling Errors + There are many situations in where you need to notify an error to a client that is using your API. This client could be a browser with a frontend, a code from someone else, an IoT device, etc. @@ -24,7 +26,7 @@ To return HTTP responses with errors to the client you use `HTTPException`. ### Import `HTTPException` ```Python hl_lines="1" -{!./src/handling_errors/tutorial001.py!} +{!../../../docs_src/handling_errors/tutorial001.py!} ``` ### Raise an `HTTPException` in your code @@ -40,7 +42,7 @@ The benefit of raising an exception over `return`ing a value will be more eviden In this example, when the client request an item by an ID that doesn't exist, raise an exception with a status code of `404`: ```Python hl_lines="11" -{!./src/handling_errors/tutorial001.py!} +{!../../../docs_src/handling_errors/tutorial001.py!} ``` ### The resulting response @@ -77,7 +79,7 @@ You probably won't need to use it directly in your code. But in case you needed it for an advanced scenario, you can add custom headers: ```Python hl_lines="14" -{!./src/handling_errors/tutorial002.py!} +{!../../../docs_src/handling_errors/tutorial002.py!} ``` ## Install custom exception handlers @@ -91,7 +93,7 @@ And you want to handle this exception globally with FastAPI. You could add a custom exception handler with `@app.exception_handler()`: ```Python hl_lines="5 6 7 13 14 15 16 17 18 24" -{!./src/handling_errors/tutorial003.py!} +{!../../../docs_src/handling_errors/tutorial003.py!} ``` Here, if you request `/unicorns/yolo`, the *path operation* will `raise` a `UnicornException`. @@ -128,7 +130,7 @@ To override it, import the `RequestValidationError` and use it with `@app.except The exception handler will receive a `Request` and the exception. ```Python hl_lines="2 14 15 16" -{!./src/handling_errors/tutorial004.py!} +{!../../../docs_src/handling_errors/tutorial004.py!} ``` Now, if you go to `/items/foo`, instead of getting the default JSON error with: @@ -178,7 +180,7 @@ The same way, you can override the `HTTPException` handler. For example, you could want to return a plain text response instead of JSON for these errors: ```Python hl_lines="3 4 9 10 11 22" -{!./src/handling_errors/tutorial004.py!} +{!../../../docs_src/handling_errors/tutorial004.py!} ``` !!! note "Technical Details" @@ -193,7 +195,7 @@ The `RequestValidationError` contains the `body` it received with invalid data. You could use it while developing your app to log the body and debug it, return it to the user, etc. ```Python hl_lines="14" -{!./src/handling_errors/tutorial005.py!} +{!../../../docs_src/handling_errors/tutorial005.py!} ``` Now try sending an invalid item like: @@ -256,7 +258,7 @@ You could also just want to use the exception somehow, but then use the same def You can import and re-use the default exception handlers from `fastapi.exception_handlers`: ```Python hl_lines="2 3 4 5 15 21" -{!./src/handling_errors/tutorial006.py!} +{!../../../docs_src/handling_errors/tutorial006.py!} ``` In this example, you are just `print`ing the error with a very expressive message. diff --git a/docs/tutorial/header-params.md b/docs/en/docs/tutorial/header-params.md similarity index 92% rename from docs/tutorial/header-params.md rename to docs/en/docs/tutorial/header-params.md index 46c349bd1..738d2a559 100644 --- a/docs/tutorial/header-params.md +++ b/docs/en/docs/tutorial/header-params.md @@ -1,3 +1,5 @@ +# Header Parameters + You can define Header parameters the same way you define `Query`, `Path` and `Cookie` parameters. ## Import `Header` @@ -5,7 +7,7 @@ You can define Header parameters the same way you define `Query`, `Path` and `Co First import `Header`: ```Python hl_lines="1" -{!./src/header_params/tutorial001.py!} +{!../../../docs_src/header_params/tutorial001.py!} ``` ## Declare `Header` parameters @@ -15,7 +17,7 @@ Then declare the header parameters using the same structure as with `Path`, `Que The first value is the default value, you can pass all the extra validation or annotation parameters: ```Python hl_lines="7" -{!./src/header_params/tutorial001.py!} +{!../../../docs_src/header_params/tutorial001.py!} ``` !!! note "Technical Details" @@ -43,7 +45,7 @@ So, you can use `user_agent` as you normally would in Python code, instead of ne If for some reason you need to disable automatic conversion of underscores to hyphens, set the parameter `convert_underscores` of `Header` to `False`: ```Python hl_lines="7" -{!./src/header_params/tutorial002.py!} +{!../../../docs_src/header_params/tutorial002.py!} ``` !!! warning @@ -61,7 +63,7 @@ You will receive all the values from the duplicate header as a Python `list`. For example, to declare a header of `X-Token` that can appear more than once, you can write: ```Python hl_lines="9" -{!./src/header_params/tutorial003.py!} +{!../../../docs_src/header_params/tutorial003.py!} ``` If you communicate with that *path operation* sending two HTTP headers like: diff --git a/docs/tutorial/index.md b/docs/en/docs/tutorial/index.md similarity index 98% rename from docs/tutorial/index.md rename to docs/en/docs/tutorial/index.md index ae073518a..8fb93ab2b 100644 --- a/docs/tutorial/index.md +++ b/docs/en/docs/tutorial/index.md @@ -1,3 +1,5 @@ +# Tutorial - User Guide - Intro + This tutorial shows you how to use **FastAPI** with most of its features, step by step. Each section gradually builds on the previous ones, but it's structured to separate topics, so that you can go directly to any specific one to solve your specific API needs. diff --git a/docs/tutorial/middleware.md b/docs/en/docs/tutorial/middleware.md similarity index 96% rename from docs/tutorial/middleware.md rename to docs/en/docs/tutorial/middleware.md index 5dd779189..6f7ca000a 100644 --- a/docs/tutorial/middleware.md +++ b/docs/en/docs/tutorial/middleware.md @@ -1,3 +1,5 @@ +# Middleware + You can add middleware to **FastAPI** applications. A "middleware" is a function that works with every **request** before it is processed by any specific *path operation*. And also with every **response** before returning it. @@ -27,7 +29,7 @@ The middleware function receives: * You can then modify further the `response` before returning it. ```Python hl_lines="8 9 11 14" -{!./src/middleware/tutorial001.py!} +{!../../../docs_src/middleware/tutorial001.py!} ``` !!! tip @@ -49,7 +51,7 @@ And also after the `response` is generated, before returning it. For example, you could add a custom header `X-Process-Time` containing the time in seconds that it took to process the request and generate a response: ```Python hl_lines="10 12 13" -{!./src/middleware/tutorial001.py!} +{!../../../docs_src/middleware/tutorial001.py!} ``` ## Other middlewares diff --git a/docs/tutorial/path-operation-configuration.md b/docs/en/docs/tutorial/path-operation-configuration.md similarity index 88% rename from docs/tutorial/path-operation-configuration.md rename to docs/en/docs/tutorial/path-operation-configuration.md index cfc970b7a..c2c300894 100644 --- a/docs/tutorial/path-operation-configuration.md +++ b/docs/en/docs/tutorial/path-operation-configuration.md @@ -1,3 +1,5 @@ +# Path Operation Configuration + There are several parameters that you can pass to your *path operation decorator* to configure it. !!! warning @@ -12,7 +14,7 @@ You can pass directly the `int` code, like `404`. But if you don't remember what each number code is for, you can use the shortcut constants in `status`: ```Python hl_lines="3 17" -{!./src/path_operation_configuration/tutorial001.py!} +{!../../../docs_src/path_operation_configuration/tutorial001.py!} ``` That status code will be used in the response and will be added to the OpenAPI schema. @@ -27,7 +29,7 @@ That status code will be used in the response and will be added to the OpenAPI s You can add tags to your *path operation*, pass the parameter `tags` with a `list` of `str` (commonly just one `str`): ```Python hl_lines="17 22 27" -{!./src/path_operation_configuration/tutorial002.py!} +{!../../../docs_src/path_operation_configuration/tutorial002.py!} ``` They will be added to the OpenAPI schema and used by the automatic documentation interfaces: @@ -39,7 +41,7 @@ They will be added to the OpenAPI schema and used by the automatic documentation You can add a `summary` and `description`: ```Python hl_lines="20 21" -{!./src/path_operation_configuration/tutorial003.py!} +{!../../../docs_src/path_operation_configuration/tutorial003.py!} ``` ## Description from docstring @@ -49,7 +51,7 @@ As descriptions tend to be long and cover multiple lines, you can declare the *p You can write Markdown in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation). ```Python hl_lines="19 20 21 22 23 24 25 26 27" -{!./src/path_operation_configuration/tutorial004.py!} +{!../../../docs_src/path_operation_configuration/tutorial004.py!} ``` It will be used in the interactive docs: @@ -61,7 +63,7 @@ It will be used in the interactive docs: You can specify the response description with the parameter `response_description`: ```Python hl_lines="21" -{!./src/path_operation_configuration/tutorial005.py!} +{!../../../docs_src/path_operation_configuration/tutorial005.py!} ``` !!! info @@ -79,7 +81,7 @@ You can specify the response description with the parameter `response_descriptio If you need to mark a *path operation* as deprecated, but without removing it, pass the parameter `deprecated`: ```Python hl_lines="16" -{!./src/path_operation_configuration/tutorial006.py!} +{!../../../docs_src/path_operation_configuration/tutorial006.py!} ``` It will be clearly marked as deprecated in the interactive docs: diff --git a/docs/tutorial/path-params-numeric-validations.md b/docs/en/docs/tutorial/path-params-numeric-validations.md similarity index 89% rename from docs/tutorial/path-params-numeric-validations.md rename to docs/en/docs/tutorial/path-params-numeric-validations.md index 5fe638f5f..9ae4c8b1a 100644 --- a/docs/tutorial/path-params-numeric-validations.md +++ b/docs/en/docs/tutorial/path-params-numeric-validations.md @@ -1,3 +1,5 @@ +# Path Parameters and Numeric Validations + The same way you can declare more validations and metadata for query parameters with `Query`, you can declare the same type of validations and metadata for path parameters with `Path`. ## Import Path @@ -5,7 +7,7 @@ The same way you can declare more validations and metadata for query parameters First, import `Path` from `fastapi`: ```Python hl_lines="1" -{!./src/path_params_numeric_validations/tutorial001.py!} +{!../../../docs_src/path_params_numeric_validations/tutorial001.py!} ``` ## Declare metadata @@ -15,7 +17,7 @@ You can declare all the same parameters as for `Query`. For example, to declare a `title` metadata value for the path parameter `item_id` you can type: ```Python hl_lines="8" -{!./src/path_params_numeric_validations/tutorial001.py!} +{!../../../docs_src/path_params_numeric_validations/tutorial001.py!} ``` !!! note @@ -42,7 +44,7 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names, So, you can declare your function as: ```Python hl_lines="8" -{!./src/path_params_numeric_validations/tutorial002.py!} +{!../../../docs_src/path_params_numeric_validations/tutorial002.py!} ``` ## Order the parameters as you need, tricks @@ -54,7 +56,7 @@ Pass `*`, as the first parameter of the function. Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as kwargs. Even if they don't have a default value. ```Python hl_lines="8" -{!./src/path_params_numeric_validations/tutorial003.py!} +{!../../../docs_src/path_params_numeric_validations/tutorial003.py!} ``` ## Number validations: greater than or equal @@ -64,7 +66,7 @@ With `Query` and `Path` (and other's you'll see later) you can declare string co Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than or `e`qual" to `1`. ```Python hl_lines="8" -{!./src/path_params_numeric_validations/tutorial004.py!} +{!../../../docs_src/path_params_numeric_validations/tutorial004.py!} ``` ## Number validations: greater than and less than or equal @@ -75,7 +77,7 @@ The same applies for: * `le`: `l`ess than or `e`qual ```Python hl_lines="9" -{!./src/path_params_numeric_validations/tutorial005.py!} +{!../../../docs_src/path_params_numeric_validations/tutorial005.py!} ``` ## Number validations: floats, greater than and less than @@ -89,7 +91,7 @@ So, `0.5` would be a valid value. But `0.0` or `0` would not. And the same for lt. ```Python hl_lines="11" -{!./src/path_params_numeric_validations/tutorial006.py!} +{!../../../docs_src/path_params_numeric_validations/tutorial006.py!} ``` ## Recap diff --git a/docs/tutorial/path-params.md b/docs/en/docs/tutorial/path-params.md similarity index 94% rename from docs/tutorial/path-params.md rename to docs/en/docs/tutorial/path-params.md index b4c405455..1c32108bb 100644 --- a/docs/tutorial/path-params.md +++ b/docs/en/docs/tutorial/path-params.md @@ -1,7 +1,9 @@ +# Path Parameters + You can declare path "parameters" or "variables" with the same syntax used by Python format strings: ```Python hl_lines="6 7" -{!./src/path_params/tutorial001.py!} +{!../../../docs_src/path_params/tutorial001.py!} ``` The value of the path parameter `item_id` will be passed to your function as the argument `item_id`. @@ -17,7 +19,7 @@ So, if you run this example and go to regular expression that the parameter should match: ```Python hl_lines="8" -{!./src/query_params_str_validations/tutorial004.py!} +{!../../../docs_src/query_params_str_validations/tutorial004.py!} ``` This specific regular expression checks that the received parameter value: @@ -85,7 +87,7 @@ The same way that you can pass `None` as the first argument to be used as the de Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`: ```Python hl_lines="7" -{!./src/query_params_str_validations/tutorial005.py!} +{!../../../docs_src/query_params_str_validations/tutorial005.py!} ``` !!! note @@ -114,7 +116,7 @@ q: str = Query(None, min_length=3) So, when you need to declare a value as required while using `Query`, you can use `...` as the first argument: ```Python hl_lines="7" -{!./src/query_params_str_validations/tutorial006.py!} +{!../../../docs_src/query_params_str_validations/tutorial006.py!} ``` !!! info @@ -129,7 +131,7 @@ When you define a query parameter explicitly with `Query` you can also declare i For example, to declare a query parameter `q` that can appear multiple times in the URL, you can write: ```Python hl_lines="9" -{!./src/query_params_str_validations/tutorial011.py!} +{!../../../docs_src/query_params_str_validations/tutorial011.py!} ``` Then, with a URL like: @@ -163,7 +165,7 @@ The interactive API docs will update accordingly, to allow multiple values: And you can also define a default `list` of values if none are provided: ```Python hl_lines="9" -{!./src/query_params_str_validations/tutorial012.py!} +{!../../../docs_src/query_params_str_validations/tutorial012.py!} ``` If you go to: @@ -188,7 +190,7 @@ the default of `q` will be: `["foo", "bar"]` and your response will be: You can also use `list` directly instead of `List[str]`: ```Python hl_lines="7" -{!./src/query_params_str_validations/tutorial013.py!} +{!../../../docs_src/query_params_str_validations/tutorial013.py!} ``` !!! note @@ -210,13 +212,13 @@ That information will be included in the generated OpenAPI and used by the docum You can add a `title`: ```Python hl_lines="7" -{!./src/query_params_str_validations/tutorial007.py!} +{!../../../docs_src/query_params_str_validations/tutorial007.py!} ``` And a `description`: ```Python hl_lines="11" -{!./src/query_params_str_validations/tutorial008.py!} +{!../../../docs_src/query_params_str_validations/tutorial008.py!} ``` ## Alias parameters @@ -238,7 +240,7 @@ But you still need it to be exactly `item-query`... Then you can declare an `alias`, and that alias is what will be used to find the parameter value: ```Python hl_lines="7" -{!./src/query_params_str_validations/tutorial009.py!} +{!../../../docs_src/query_params_str_validations/tutorial009.py!} ``` ## Deprecating parameters @@ -250,7 +252,7 @@ You have to leave it there a while because there are clients using it, but you w Then pass the parameter `deprecated=True` to `Query`: ```Python hl_lines="16" -{!./src/query_params_str_validations/tutorial010.py!} +{!../../../docs_src/query_params_str_validations/tutorial010.py!} ``` The docs will show it like this: diff --git a/docs/tutorial/query-params.md b/docs/en/docs/tutorial/query-params.md similarity index 92% rename from docs/tutorial/query-params.md rename to docs/en/docs/tutorial/query-params.md index 5e7230110..0efc57e1b 100644 --- a/docs/tutorial/query-params.md +++ b/docs/en/docs/tutorial/query-params.md @@ -1,7 +1,9 @@ +# Query Parameters + When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters. ```Python hl_lines="9" -{!./src/query_params/tutorial001.py!} +{!../../../docs_src/query_params/tutorial001.py!} ``` The query is the set of key-value pairs that go after the `?` in a URL, separated by `&` characters. @@ -62,7 +64,7 @@ The parameter values in your function will be: The same way, you can declare optional query parameters, by setting their default to `None`: ```Python hl_lines="7" -{!./src/query_params/tutorial002.py!} +{!../../../docs_src/query_params/tutorial002.py!} ``` In this case, the function parameter `q` will be optional, and will be `None` by default. @@ -75,7 +77,7 @@ In this case, the function parameter `q` will be optional, and will be `None` by You can also declare `bool` types, and they will be converted: ```Python hl_lines="7" -{!./src/query_params/tutorial003.py!} +{!../../../docs_src/query_params/tutorial003.py!} ``` In this case, if you go to: @@ -120,7 +122,7 @@ And you don't have to declare them in any specific order. They will be detected by name: ```Python hl_lines="6 8" -{!./src/query_params/tutorial004.py!} +{!../../../docs_src/query_params/tutorial004.py!} ``` ## Required query parameters @@ -132,7 +134,7 @@ If you don't want to add a specific value but just make it optional, set the def But when you want to make a query parameter required, you can just not declare any default value: ```Python hl_lines="6 7" -{!./src/query_params/tutorial005.py!} +{!../../../docs_src/query_params/tutorial005.py!} ``` Here the query parameter `needy` is a required query parameter of type `str`. @@ -178,7 +180,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy And of course, you can define some parameters as required, some as having a default value, and some entirely optional: ```Python hl_lines="7" -{!./src/query_params/tutorial006.py!} +{!../../../docs_src/query_params/tutorial006.py!} ``` In this case, there are 3 query parameters: @@ -220,5 +222,5 @@ limit: Optional[int] = None In a *path operation* that could look like: ```Python hl_lines="9" -{!./src/query_params/tutorial007.py!} +{!../../../docs_src/query_params/tutorial007.py!} ``` diff --git a/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md similarity index 96% rename from docs/tutorial/request-files.md rename to docs/en/docs/tutorial/request-files.md index b14f45c70..260a5e190 100644 --- a/docs/tutorial/request-files.md +++ b/docs/en/docs/tutorial/request-files.md @@ -1,3 +1,5 @@ +# Request Files + You can define files to be uploaded by the client using `File`. !!! info @@ -12,7 +14,7 @@ You can define files to be uploaded by the client using `File`. Import `File` and `UploadFile` from `fastapi`: ```Python hl_lines="1" -{!./src/request_files/tutorial001.py!} +{!../../../docs_src/request_files/tutorial001.py!} ``` ## Define `File` parameters @@ -20,7 +22,7 @@ Import `File` and `UploadFile` from `fastapi`: Create file parameters the same way you would for `Body` or `Form`: ```Python hl_lines="7" -{!./src/request_files/tutorial001.py!} +{!../../../docs_src/request_files/tutorial001.py!} ``` !!! info @@ -44,7 +46,7 @@ But there are several cases in where you might benefit from using `UploadFile`. Define a `File` parameter with a type of `UploadFile`: ```Python hl_lines="12" -{!./src/request_files/tutorial001.py!} +{!../../../docs_src/request_files/tutorial001.py!} ``` Using `UploadFile` has several advantages over `bytes`: @@ -120,7 +122,7 @@ They would be associated to the same "form field" sent using "form data". To use that, declare a `List` of `bytes` or `UploadFile`: ```Python hl_lines="10 15" -{!./src/request_files/tutorial002.py!} +{!../../../docs_src/request_files/tutorial002.py!} ``` You will receive, as declared, a `list` of `bytes` or `UploadFile`s. diff --git a/docs/tutorial/request-forms-and-files.md b/docs/en/docs/tutorial/request-forms-and-files.md similarity index 88% rename from docs/tutorial/request-forms-and-files.md rename to docs/en/docs/tutorial/request-forms-and-files.md index 51ba78638..6844f8c65 100644 --- a/docs/tutorial/request-forms-and-files.md +++ b/docs/en/docs/tutorial/request-forms-and-files.md @@ -1,3 +1,5 @@ +# Request Forms and Files + You can define files and form fields at the same time using `File` and `Form`. !!! info @@ -8,7 +10,7 @@ You can define files and form fields at the same time using `File` and `Form`. ## Import `File` and `Form` ```Python hl_lines="1" -{!./src/request_forms_and_files/tutorial001.py!} +{!../../../docs_src/request_forms_and_files/tutorial001.py!} ``` ## Define `File` and `Form` parameters @@ -16,7 +18,7 @@ You can define files and form fields at the same time using `File` and `Form`. Create file and form parameters the same way you would for `Body` or `Query`: ```Python hl_lines="8" -{!./src/request_forms_and_files/tutorial001.py!} +{!../../../docs_src/request_forms_and_files/tutorial001.py!} ``` The files and form fields will be uploaded as form data and you will receive the files and form fields. diff --git a/docs/tutorial/request-forms.md b/docs/en/docs/tutorial/request-forms.md similarity index 95% rename from docs/tutorial/request-forms.md rename to docs/en/docs/tutorial/request-forms.md index edb9af641..b5495a400 100644 --- a/docs/tutorial/request-forms.md +++ b/docs/en/docs/tutorial/request-forms.md @@ -1,3 +1,5 @@ +# Form Data + When you need to receive form fields instead of JSON, you can use `Form`. !!! info @@ -10,7 +12,7 @@ When you need to receive form fields instead of JSON, you can use `Form`. Import `Form` from `fastapi`: ```Python hl_lines="1" -{!./src/request_forms/tutorial001.py!} +{!../../../docs_src/request_forms/tutorial001.py!} ``` ## Define `Form` parameters @@ -18,7 +20,7 @@ Import `Form` from `fastapi`: Create form parameters the same way you would for `Body` or `Query`: ```Python hl_lines="7" -{!./src/request_forms/tutorial001.py!} +{!../../../docs_src/request_forms/tutorial001.py!} ``` For example, in one of the ways the OAuth2 specification can be used (called "password flow") it is required to send a `username` and `password` as form fields. diff --git a/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md similarity index 92% rename from docs/tutorial/response-model.md rename to docs/en/docs/tutorial/response-model.md index 1f1288ca7..3f06cd4d5 100644 --- a/docs/tutorial/response-model.md +++ b/docs/en/docs/tutorial/response-model.md @@ -1,3 +1,5 @@ +# Response Model + You can declare the model used for the response with the parameter `response_model` in any of the *path operations*: * `@app.get()` @@ -7,7 +9,7 @@ You can declare the model used for the response with the parameter `response_mod * etc. ```Python hl_lines="17" -{!./src/response_model/tutorial001.py!} +{!../../../docs_src/response_model/tutorial001.py!} ``` !!! note @@ -34,13 +36,13 @@ But most importantly: Here we are declaring a `UserIn` model, it will contain a plaintext password: ```Python hl_lines="7 9" -{!./src/response_model/tutorial002.py!} +{!../../../docs_src/response_model/tutorial002.py!} ``` And we are using this model to declare our input and the same model to declare our output: ```Python hl_lines="15 16" -{!./src/response_model/tutorial002.py!} +{!../../../docs_src/response_model/tutorial002.py!} ``` Now, whenever a browser is creating a user with a password, the API will return the same password in the response. @@ -57,19 +59,19 @@ But if we use the same model for another *path operation*, we could be sending o We can instead create an input model with the plaintext password and an output model without it: ```Python hl_lines="7 9 14" -{!./src/response_model/tutorial003.py!} +{!../../../docs_src/response_model/tutorial003.py!} ``` Here, even though our *path operation function* is returning the same input user that contains the password: ```Python hl_lines="22" -{!./src/response_model/tutorial003.py!} +{!../../../docs_src/response_model/tutorial003.py!} ``` ...we declared the `response_model` to be our model `UserOut`, that doesn't include the password: ```Python hl_lines="20" -{!./src/response_model/tutorial003.py!} +{!../../../docs_src/response_model/tutorial003.py!} ``` So, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic). @@ -89,7 +91,7 @@ And both models will be used for the interactive API documentation: Your response model could have default values, like: ```Python hl_lines="11 13 14" -{!./src/response_model/tutorial004.py!} +{!../../../docs_src/response_model/tutorial004.py!} ``` * `description: str = None` has a default of `None`. @@ -105,7 +107,7 @@ For example, if you have models with many optional attributes in a NoSQL databas You can set the *path operation decorator* parameter `response_model_exclude_unset=True`: ```Python hl_lines="24" -{!./src/response_model/tutorial004.py!} +{!../../../docs_src/response_model/tutorial004.py!} ``` and those default values won't be included in the response, only the values actually set. @@ -174,7 +176,7 @@ This can be used as a quick shortcut if you have only one Pydantic model and wan This is because the JSON Schema generated in your app's OpenAPI (and the docs) will still be the one for the complete model, even if you use `response_model_include` or `response_model_exclude` to omit some attributes. ```Python hl_lines="29 35" -{!./src/response_model/tutorial005.py!} +{!../../../docs_src/response_model/tutorial005.py!} ``` !!! tip @@ -187,7 +189,7 @@ This can be used as a quick shortcut if you have only one Pydantic model and wan If you forget to use a `set` and use a `list` or `tuple` instead, FastAPI will still convert it to a `set` and it will work correctly: ```Python hl_lines="29 35" -{!./src/response_model/tutorial006.py!} +{!../../../docs_src/response_model/tutorial006.py!} ``` ## Recap diff --git a/docs/tutorial/response-status-code.md b/docs/en/docs/tutorial/response-status-code.md similarity index 94% rename from docs/tutorial/response-status-code.md rename to docs/en/docs/tutorial/response-status-code.md index 3f77272de..29b8521fc 100644 --- a/docs/tutorial/response-status-code.md +++ b/docs/en/docs/tutorial/response-status-code.md @@ -1,3 +1,5 @@ +# Response Status Code + The same way you can specify a response model, you can also declare the HTTP status code used for the response with the parameter `status_code` in any of the *path operations*: * `@app.get()` @@ -7,7 +9,7 @@ The same way you can specify a response model, you can also declare the HTTP sta * etc. ```Python hl_lines="6" -{!./src/response_status_code/tutorial001.py!} +{!../../../docs_src/response_status_code/tutorial001.py!} ``` !!! note @@ -57,7 +59,7 @@ In short: Let's see the previous example again: ```Python hl_lines="6" -{!./src/response_status_code/tutorial001.py!} +{!../../../docs_src/response_status_code/tutorial001.py!} ``` `201` is the status code for "Created". @@ -67,7 +69,7 @@ But you don't have to memorize what each of these codes mean. You can use the convenience variables from `fastapi.status`. ```Python hl_lines="1 6" -{!./src/response_status_code/tutorial002.py!} +{!../../../docs_src/response_status_code/tutorial002.py!} ``` They are just a convenience, they hold the same number, but that way you can use the editor's autocomplete to find them: diff --git a/docs/tutorial/security/first-steps.md b/docs/en/docs/tutorial/security/first-steps.md similarity index 97% rename from docs/tutorial/security/first-steps.md rename to docs/en/docs/tutorial/security/first-steps.md index 6fef16235..c14ec2ad9 100644 --- a/docs/tutorial/security/first-steps.md +++ b/docs/en/docs/tutorial/security/first-steps.md @@ -1,3 +1,5 @@ +# Security - First Steps + Let's imagine that you have your **backend** API in some domain. And you have a **frontend** in another domain or in a different path of the same domain (or in a mobile application). @@ -19,7 +21,7 @@ Let's first just use the code and see how it works, and then we'll come back to Copy the example in a file `main.py`: ```Python -{!./src/security/tutorial001.py!} +{!../../../docs_src/security/tutorial001.py!} ``` ## Run it @@ -115,7 +117,7 @@ In this example we are going to use **OAuth2**, with the **Password** flow, usin `OAuth2PasswordBearer` is a class that we create passing a parameter of the URL in where the client (the frontend running in the user's browser) can use to send the `username` and `password` and get a token. ```Python hl_lines="6" -{!./src/security/tutorial001.py!} +{!../../../docs_src/security/tutorial001.py!} ``` It doesn't create that endpoint / *path operation*, but declares that that URL is the one that the client should use to get the token. That information is used in OpenAPI, and then in the interactive API documentation systems. @@ -140,7 +142,7 @@ So, it can be used with `Depends`. Now you can pass that `oauth2_scheme` in a dependency with `Depends`. ```Python hl_lines="10" -{!./src/security/tutorial001.py!} +{!../../../docs_src/security/tutorial001.py!} ``` This dependency will provide a `str` that is assigned to the parameter `token` of the *path operation function*. diff --git a/docs/tutorial/security/get-current-user.md b/docs/en/docs/tutorial/security/get-current-user.md similarity index 92% rename from docs/tutorial/security/get-current-user.md rename to docs/en/docs/tutorial/security/get-current-user.md index e2d6b7924..3fc0164c3 100644 --- a/docs/tutorial/security/get-current-user.md +++ b/docs/en/docs/tutorial/security/get-current-user.md @@ -1,7 +1,9 @@ +# Get Current User + In the previous chapter the security system (which is based on the dependency injection system) was giving the *path operation function* a `token` as a `str`: ```Python hl_lines="10" -{!./src/security/tutorial001.py!} +{!../../../docs_src/security/tutorial001.py!} ``` But that is still not that useful. @@ -15,7 +17,7 @@ First, let's create a Pydantic user model. The same way we use Pydantic to declare bodies, we can use it anywhere else: ```Python hl_lines="5 12 13 14 15 16" -{!./src/security/tutorial002.py!} +{!../../../docs_src/security/tutorial002.py!} ``` ## Create a `get_current_user` dependency @@ -29,7 +31,7 @@ Remember that dependencies can have sub-dependencies? The same as we were doing before in the *path operation* directly, our new dependency `get_current_user` will receive a `token` as a `str` from the sub-dependency `oauth2_scheme`: ```Python hl_lines="25" -{!./src/security/tutorial002.py!} +{!../../../docs_src/security/tutorial002.py!} ``` ## Get the user @@ -37,7 +39,7 @@ The same as we were doing before in the *path operation* directly, our new depen `get_current_user` will use a (fake) utility function we created, that takes a token as a `str` and returns our Pydantic `User` model: ```Python hl_lines="19 20 21 22 26 27" -{!./src/security/tutorial002.py!} +{!../../../docs_src/security/tutorial002.py!} ``` ## Inject the current user @@ -45,7 +47,7 @@ The same as we were doing before in the *path operation* directly, our new depen So now we can use the same `Depends` with our `get_current_user` in the *path operation*: ```Python hl_lines="31" -{!./src/security/tutorial002.py!} +{!../../../docs_src/security/tutorial002.py!} ``` Notice that we declare the type of `current_user` as the Pydantic model `User`. @@ -97,7 +99,7 @@ And all of them (or any portion of them that you want) can take the advantage of And all these thousands of *path operations* can be as small as 3 lines: ```Python hl_lines="30 31 32" -{!./src/security/tutorial002.py!} +{!../../../docs_src/security/tutorial002.py!} ``` ## Recap diff --git a/docs/tutorial/security/index.md b/docs/en/docs/tutorial/security/index.md similarity index 99% rename from docs/tutorial/security/index.md rename to docs/en/docs/tutorial/security/index.md index 96c941dd5..9aed2adb5 100644 --- a/docs/tutorial/security/index.md +++ b/docs/en/docs/tutorial/security/index.md @@ -1,3 +1,5 @@ +# Security Intro + There are many ways to handle security, authentication and authorization. And it normally is a complex and "difficult" topic. diff --git a/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md similarity index 97% rename from docs/tutorial/security/oauth2-jwt.md rename to docs/en/docs/tutorial/security/oauth2-jwt.md index cd15cb9d2..18b4e0e30 100644 --- a/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -1,3 +1,5 @@ +# OAuth2 with Password (and hashing), Bearer with JWT tokens + Now that we have all the security flow, let's make the application actually secure, using JWT tokens and secure password hashing. This code is something you can actually use in your application, save the password hashes in your database, etc. @@ -99,7 +101,7 @@ And another utility to verify if a received password matches the hash stored. And another one to authenticate and return a user. ```Python hl_lines="7 48 55 56 59 60 69 70 71 72 73 74 75" -{!./src/security/tutorial004.py!} +{!../../../docs_src/security/tutorial004.py!} ``` !!! note @@ -134,7 +136,7 @@ Define a Pydantic Model that will be used in the token endpoint for the response Create a utility function to generate a new access token. ```Python hl_lines="3 6 12 13 14 28 29 30 78 79 80 81 82 83 84 85 86" -{!./src/security/tutorial004.py!} +{!../../../docs_src/security/tutorial004.py!} ``` ## Update the dependencies @@ -146,7 +148,7 @@ Decode the received token, verify it, and return the current user. If the token is invalid, return an HTTP error right away. ```Python hl_lines="89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106" -{!./src/security/tutorial004.py!} +{!../../../docs_src/security/tutorial004.py!} ``` ## Update the `/token` *path operation* @@ -156,7 +158,7 @@ Create a `timedelta` with the expiration time of the token. Create a real JWT access token and return it. ```Python hl_lines="115 116 117 118 119 120 121 122 123 124 125 126 127 128" -{!./src/security/tutorial004.py!} +{!../../../docs_src/security/tutorial004.py!} ``` ### Technical details about the JWT "subject" `sub` diff --git a/docs/tutorial/security/simple-oauth2.md b/docs/en/docs/tutorial/security/simple-oauth2.md similarity index 97% rename from docs/tutorial/security/simple-oauth2.md rename to docs/en/docs/tutorial/security/simple-oauth2.md index d7507a1ec..c95c6aa6b 100644 --- a/docs/tutorial/security/simple-oauth2.md +++ b/docs/en/docs/tutorial/security/simple-oauth2.md @@ -1,3 +1,5 @@ +# Simple OAuth2 with Password and Bearer + Now let's build from the previous chapter and add the missing parts to have a complete security flow. ## Get the `username` and `password` @@ -48,7 +50,7 @@ Now let's use the utilities provided by **FastAPI** to handle this. First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` for the path `/token`: ```Python hl_lines="2 74" -{!./src/security/tutorial003.py!} +{!../../../docs_src/security/tutorial003.py!} ``` `OAuth2PasswordRequestForm` is a class dependency that declares a form body with: @@ -89,7 +91,7 @@ If there is no such user, we return an error saying "incorrect username or passw For the error, we use the exception `HTTPException`: ```Python hl_lines="1 75 76 77" -{!./src/security/tutorial003.py!} +{!../../../docs_src/security/tutorial003.py!} ``` ### Check the password @@ -117,7 +119,7 @@ If your database is stolen, the thief won't have your users' plaintext passwords So, the thief won't be able to try to use those same passwords in another system (as many users use the same password everywhere, this would be dangerous). ```Python hl_lines="78 79 80 81" -{!./src/security/tutorial003.py!} +{!../../../docs_src/security/tutorial003.py!} ``` #### About `**user_dict` @@ -155,7 +157,7 @@ For this simple example, we are going to just be completely insecure and return But for now, let's focus on the specific details we need. ```Python hl_lines="83" -{!./src/security/tutorial003.py!} +{!../../../docs_src/security/tutorial003.py!} ``` !!! tip @@ -180,7 +182,7 @@ Both of these dependencies will just return an HTTP error if the user doesn't ex So, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active: ```Python hl_lines="56 57 58 59 60 61 62 63 64 65 67 68 69 70 88" -{!./src/security/tutorial003.py!} +{!../../../docs_src/security/tutorial003.py!} ``` !!! info diff --git a/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md similarity index 95% rename from docs/tutorial/sql-databases.md rename to docs/en/docs/tutorial/sql-databases.md index ba4b83648..179e75f0a 100644 --- a/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -1,3 +1,5 @@ +# SQL (Relational) Databases + **FastAPI** doesn't require you to use a SQL (relational) database. But you can use any relational database that you want. @@ -85,13 +87,13 @@ Let's refer to the file `sql_app/database.py`. ### Import the SQLAlchemy parts ```Python hl_lines="1 2 3" -{!./src/sql_databases/sql_app/database.py!} +{!../../../docs_src/sql_databases/sql_app/database.py!} ``` ### Create a database URL for SQLAlchemy ```Python hl_lines="5 6" -{!./src/sql_databases/sql_app/database.py!} +{!../../../docs_src/sql_databases/sql_app/database.py!} ``` In this example, we are "connecting" to a SQLite database (opening a file with the SQLite database). @@ -119,7 +121,7 @@ The first step is to create a SQLAlchemy "engine". We will later use this `engine` in other places. ```Python hl_lines="8 9 10" -{!./src/sql_databases/sql_app/database.py!} +{!../../../docs_src/sql_databases/sql_app/database.py!} ``` #### Note @@ -155,7 +157,7 @@ We will use `Session` (the one imported from SQLAlchemy) later. To create the `SessionLocal` class, use the function `sessionmaker`: ```Python hl_lines="11" -{!./src/sql_databases/sql_app/database.py!} +{!../../../docs_src/sql_databases/sql_app/database.py!} ``` ### Create a `Base` class @@ -165,7 +167,7 @@ Now we will use the function `declarative_base()` that returns a class. Later we will inherit from this class to create each of the database models or classes (the ORM models): ```Python hl_lines="13" -{!./src/sql_databases/sql_app/database.py!} +{!../../../docs_src/sql_databases/sql_app/database.py!} ``` ## Create the database models @@ -188,7 +190,7 @@ Create classes that inherit from it. These classes are the SQLAlchemy models. ```Python hl_lines="4 7 8 18 19" -{!./src/sql_databases/sql_app/models.py!} +{!../../../docs_src/sql_databases/sql_app/models.py!} ``` The `__tablename__` attribute tells SQLAlchemy the name of the table to use in the database for each of these models. @@ -204,7 +206,7 @@ We use `Column` from SQLAlchemy as the default value. And we pass a SQLAlchemy class "type", as `Integer`, `String`, and `Boolean`, that defines the type in the database, as an argument. ```Python hl_lines="1 10 11 12 13 21 22 23 24" -{!./src/sql_databases/sql_app/models.py!} +{!../../../docs_src/sql_databases/sql_app/models.py!} ``` ### Create the relationships @@ -216,7 +218,7 @@ For this, we use `relationship` provided by SQLAlchemy ORM. This will become, more or less, a "magic" attribute that will contain the values from other tables related to this one. ```Python hl_lines="2 15 26" -{!./src/sql_databases/sql_app/models.py!} +{!../../../docs_src/sql_databases/sql_app/models.py!} ``` When accessing the attribute `items` in a `User`, as in `my_user.items`, it will have a list of `Item` SQLAlchemy models (from the `items` table) that have a foreign key pointing to this record in the `users` table. @@ -247,7 +249,7 @@ So, the user will also have a `password` when creating it. But for security, the `password` won't be in other Pydantic *models*, for example, it won't be sent from the API when reading a user. ```Python hl_lines="3 6 7 8 11 12 23 24 27 28" -{!./src/sql_databases/sql_app/schemas.py!} +{!../../../docs_src/sql_databases/sql_app/schemas.py!} ``` #### SQLAlchemy style and Pydantic style @@ -277,7 +279,7 @@ The same way, when reading a user, we can now declare that `items` will contain Not only the IDs of those items, but all the data that we defined in the Pydantic *model* for reading items: `Item`. ```Python hl_lines="15 16 17 31 32 33 34" -{!./src/sql_databases/sql_app/schemas.py!} +{!../../../docs_src/sql_databases/sql_app/schemas.py!} ``` !!! tip @@ -292,7 +294,7 @@ This Starlette, testing **FastAPI** applications is easy and enjoyable. It is based on Requests, so it's very familiar and intuitive. @@ -17,7 +19,7 @@ Use the `TestClient` object the same way as you do with `requests`. Write simple `assert` statements with the standard Python expressions that you need to check (again, standard `pytest`). ```Python hl_lines="2 12 15 16 17 18" -{!./src/app_testing/tutorial001.py!} +{!../../../docs_src/app_testing/tutorial001.py!} ``` !!! tip @@ -43,7 +45,7 @@ And your **FastAPI** application might also be composed of several files/modules Let's say you have a file `main.py` with your **FastAPI** app: ```Python -{!./src/app_testing/main.py!} +{!../../../docs_src/app_testing/main.py!} ``` ### Testing file @@ -51,7 +53,7 @@ Let's say you have a file `main.py` with your **FastAPI** app: Then you could have a file `test_main.py` with your tests, and import your `app` from the `main` module (`main.py`): ```Python -{!./src/app_testing/test_main.py!} +{!../../../docs_src/app_testing/test_main.py!} ``` ## Testing: extended example @@ -69,7 +71,7 @@ It has a `POST` operation that could return several errors. Both *path operations* require an `X-Token` header. ```Python -{!./src/app_testing/main_b.py!} +{!../../../docs_src/app_testing/main_b.py!} ``` ### Extended testing file @@ -77,7 +79,7 @@ Both *path operations* require an `X-Token` header. You could then have a `test_main_b.py`, the same as before, with the extended tests: ```Python -{!./src/app_testing/test_main_b.py!} +{!../../../docs_src/app_testing/test_main_b.py!} ``` Whenever you need the client to pass information in the request and you don't know how to, you can search (Google) how to do it in `requests`. diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml new file mode 100644 index 000000000..eb3b54e94 --- /dev/null +++ b/docs/en/mkdocs.yml @@ -0,0 +1,147 @@ +site_name: FastAPI +site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production +site_url: https://fastapi.tiangolo.com/ +theme: + name: material + palette: + primary: teal + accent: amber + logo: img/icon-white.svg + favicon: img/favicon.png + language: en +repo_name: tiangolo/fastapi +repo_url: https://github.com/tiangolo/fastapi +edit_uri: '' +google_analytics: +- UA-133183413-1 +- auto +nav: +- FastAPI: index.md +- Languages: + - en: / + - es: /es/ +- features.md +- python-types.md +- Tutorial - User Guide: + - tutorial/index.md + - tutorial/first-steps.md + - tutorial/path-params.md + - tutorial/query-params.md + - tutorial/body.md + - tutorial/query-params-str-validations.md + - tutorial/path-params-numeric-validations.md + - tutorial/body-multiple-params.md + - tutorial/body-fields.md + - tutorial/body-nested-models.md + - tutorial/extra-data-types.md + - tutorial/cookie-params.md + - tutorial/header-params.md + - tutorial/response-model.md + - tutorial/extra-models.md + - tutorial/response-status-code.md + - tutorial/request-forms.md + - tutorial/request-files.md + - tutorial/request-forms-and-files.md + - tutorial/handling-errors.md + - tutorial/path-operation-configuration.md + - tutorial/encoder.md + - tutorial/body-updates.md + - Dependencies: + - tutorial/dependencies/index.md + - tutorial/dependencies/classes-as-dependencies.md + - tutorial/dependencies/sub-dependencies.md + - tutorial/dependencies/dependencies-in-path-operation-decorators.md + - tutorial/dependencies/dependencies-with-yield.md + - Security: + - tutorial/security/index.md + - tutorial/security/first-steps.md + - tutorial/security/get-current-user.md + - tutorial/security/simple-oauth2.md + - tutorial/security/oauth2-jwt.md + - tutorial/middleware.md + - tutorial/cors.md + - tutorial/sql-databases.md + - tutorial/bigger-applications.md + - tutorial/background-tasks.md + - tutorial/application-configuration.md + - tutorial/static-files.md + - tutorial/testing.md + - tutorial/debugging.md +- Advanced User Guide: + - advanced/index.md + - advanced/path-operation-advanced-configuration.md + - advanced/additional-status-codes.md + - advanced/response-directly.md + - advanced/custom-response.md + - advanced/additional-responses.md + - advanced/response-cookies.md + - advanced/response-headers.md + - advanced/response-change-status-code.md + - advanced/advanced-dependencies.md + - Advanced Security: + - advanced/security/index.md + - advanced/security/oauth2-scopes.md + - advanced/security/http-basic-auth.md + - advanced/using-request-directly.md + - advanced/middleware.md + - advanced/sql-databases-peewee.md + - advanced/async-sql-databases.md + - advanced/nosql-databases.md + - advanced/sub-applications-proxy.md + - advanced/templates.md + - advanced/graphql.md + - advanced/websockets.md + - advanced/events.md + - advanced/custom-request-and-route.md + - advanced/testing-websockets.md + - advanced/testing-events.md + - advanced/testing-dependencies.md + - advanced/extending-openapi.md + - advanced/openapi-callbacks.md + - advanced/wsgi.md +- async.md +- deployment.md +- project-generation.md +- alternatives.md +- history-design-future.md +- external-links.md +- benchmarks.md +- help-fastapi.md +- contributing.md +- release-notes.md +markdown_extensions: +- toc: + permalink: true +- markdown.extensions.codehilite: + guess_lang: false +- markdown_include.include: + base_path: docs +- admonition +- codehilite +- extra +- pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_div_format '' +extra: + social: + - type: github + link: https://github.com/tiangolo/typer + - type: twitter + link: https://twitter.com/tiangolo + - type: linkedin + link: https://www.linkedin.com/in/tiangolo + - type: rss + link: https://dev.to/tiangolo + - type: medium + link: https://medium.com/@tiangolo + - type: globe + link: https://tiangolo.com +extra_css: +- css/termynal.css +- css/custom.css +extra_javascript: +- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js +- js/termynal.js +- js/custom.js diff --git a/docs/es/docs/index.md b/docs/es/docs/index.md new file mode 100644 index 000000000..11c945372 --- /dev/null +++ b/docs/es/docs/index.md @@ -0,0 +1,437 @@ +

+ FastAPI +

+

+ FastAPI framework, high performance, easy to learn, fast to code, ready for production +

+

+ + Build Status + + + Coverage + + + Package version + + + Join the chat at https://gitter.im/tiangolo/fastapi + +

+ +--- + +**Documentation**: https://fastapi.tiangolo.com + +**Source Code**: https://github.com/tiangolo/fastapi + +--- + +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints. + +The key features are: + +* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). + +* **Fast to code**: Increase the speed to develop features by about 200% to 300% *. +* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. + +* estimation based on tests on an internal development team, building production applications. + +## Opinions + +"*[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products.*" + +
Kabir Khan - Microsoft (ref)
+ +--- + +"*I’m over the moon excited about **FastAPI**. It’s so fun!*" + +
Brian Okken - Python Bytes podcast host (ref)
+ +--- + +"*Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that.*" + +
Timothy Crosley - Hug creator (ref)
+ +--- + +"*If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]*" + +"*We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]*" + +
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +"*We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]*" + +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
+ +--- + +## **Typer**, the FastAPI of CLIs + + + +If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**. + +**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀 + +## Requirements + +Python 3.6+ + +FastAPI stands on the shoulders of giants: + +* Starlette for the web parts. +* Pydantic for the data parts. + +## Installation + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+ +You will also need an ASGI server, for production such as Uvicorn or Hypercorn. + +
+ +```console +$ pip install uvicorn + +---> 100% +``` + +
+ +## Example + +### Create it + +* Create a file `main.py` with: + +```Python +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: str = None): + return {"item_id": item_id, "q": q} +``` + +
+Or use async def... + +If your code uses `async` / `await`, use `async def`: + +```Python hl_lines="7 12" +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: int, q: str = None): + return {"item_id": item_id, "q": q} +``` + +**Note**: + +If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs. + +
+ +### Run it + +Run the server with: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+About the command uvicorn main:app --reload... + +The command `uvicorn main:app` refers to: + +* `main`: the file `main.py` (the Python "module"). +* `app`: the object created inside of `main.py` with the line `app = FastAPI()`. +* `--reload`: make the server restart after code changes. Only do this for development. + +
+ +### Check it + +Open your browser at http://127.0.0.1:8000/items/5?q=somequery. + +You will see the JSON response as: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +You already created an API that: + +* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`. +* Both _paths_ take `GET` operations (also known as HTTP _methods_). +* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`. +* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`. + +### Interactive API docs + +Now go to http://127.0.0.1:8000/docs. + +You will see the automatic interactive API documentation (provided by Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Alternative API docs + +And now, go to http://127.0.0.1:8000/redoc. + +You will see the alternative automatic documentation (provided by ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Example upgrade + +Now modify the file `main.py` to receive a body from a `PUT` request. + +Declare the body using standard Python types, thanks to Pydantic. + +```Python hl_lines="2 7 8 9 10 23 24 25" +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: bool = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: str = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} +``` + +The server should reload automatically (because you added `--reload` to the `uvicorn` command above). + +### Interactive API docs upgrade + +Now go to http://127.0.0.1:8000/docs. + +* The interactive API documentation will be automatically updated, including the new body: + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) + +* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) + +### Alternative API docs upgrade + +And now, go to http://127.0.0.1:8000/redoc. + +* The alternative documentation will also reflect the new query parameter and body: + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Recap + +In summary, you declare **once** the types of parameters, body, etc. as function parameters. + +You do that with standard modern Python types. + +You don't have to learn a new syntax, the methods or classes of a specific library, etc. + +Just standard **Python 3.6+**. + +For example, for an `int`: + +```Python +item_id: int +``` + +or for a more complex `Item` model: + +```Python +item: Item +``` + +...and with that single declaration you get: + +* Editor support, including: + * Completion. + * Type checks. +* Validation of data: + * Automatic and clear errors when the data is invalid. + * Validation even for deeply nested JSON objects. +* Conversion of input data: coming from the network to Python data and types. Reading from: + * JSON. + * Path parameters. + * Query parameters. + * Cookies. + * Headers. + * Forms. + * Files. +* Conversion of output data: converting from Python data and types to network data (as JSON): + * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc). + * `datetime` objects. + * `UUID` objects. + * Database models. + * ...and many more. +* Automatic interactive API documentation, including 2 alternative user interfaces: + * Swagger UI. + * ReDoc. + +--- + +Coming back to the previous code example, **FastAPI** will: + +* Validate that there is an `item_id` in the path for `GET` and `PUT` requests. +* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests. + * If it is not, the client will see a useful, clear error. +* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests. + * As the `q` parameter is declared with `= None`, it is optional. + * Without the `None` it would be required (as is the body in the case with `PUT`). +* For `PUT` requests to `/items/{item_id}`, Read the body as JSON: + * Check that it has a required attribute `name` that should be a `str`. + * Check that it has a required attribute `price` that has to be a `float`. + * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present. + * All this would also work for deeply nested JSON objects. +* Convert from and to JSON automatically. +* Document everything with OpenAPI, that can be used by: + * Interactive documentation systems. + * Automatic client code generation systems, for many languages. +* Provide 2 interactive documentation web interfaces directly. + +--- + +We just scratched the surface, but you already get the idea of how it all works. + +Try changing the line with: + +```Python + return {"item_name": item.name, "item_id": item_id} +``` + +...from: + +```Python + ... "item_name": item.name ... +``` + +...to: + +```Python + ... "item_price": item.price ... +``` + +...and see how your editor will auto-complete the attributes and know their types: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +For a more complete example including more features, see the Tutorial - User Guide. + +**Spoiler alert**: the tutorial - user guide includes: + +* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**. +* How to set **validation constraints** as `maximum_length` or `regex`. +* A very powerful and easy to use **Dependency Injection** system. +* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. +* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). +* Many extra features (thanks to Starlette) as: + * **WebSockets** + * **GraphQL** + * extremely easy tests based on `requests` and `pytest` + * **CORS** + * **Cookie Sessions** + * ...and more. + +## Performance + +Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*) + +To understand more about it, see the section Benchmarks. + +## Optional Dependencies + +Used by Pydantic: + +* ujson - for faster JSON "parsing". +* email_validator - for email validation. + +Used by Starlette: + +* requests - Required if you want to use the `TestClient`. +* aiofiles - Required if you want to use `FileResponse` or `StaticFiles`. +* jinja2 - Required if you want to use the default template configuration. +* python-multipart - Required if you want to support form "parsing", with `request.form()`. +* itsdangerous - Required for `SessionMiddleware` support. +* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI). +* graphene - Required for `GraphQLApp` support. +* ujson - Required if you want to use `UJSONResponse`. + +Used by FastAPI / Starlette: + +* uvicorn - for the server that loads and serves your application. +* orjson - Required if you want to use `ORJSONResponse`. + +You can install all of these with `pip install fastapi[all]`. + +## License + +This project is licensed under the terms of the MIT license. diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml new file mode 100644 index 000000000..8fb7cf469 --- /dev/null +++ b/docs/es/mkdocs.yml @@ -0,0 +1,58 @@ +site_name: FastAPI +site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production +site_url: https://fastapi.tiangolo.com/es/ +theme: + name: material + palette: + primary: teal + accent: amber + logo: https://fastapi.tiangolo.com/img/icon-white.svg + favicon: https://fastapi.tiangolo.com/img/favicon.png + language: es +repo_name: tiangolo/fastapi +repo_url: https://github.com/tiangolo/fastapi +edit_uri: '' +google_analytics: +- UA-133183413-1 +- auto +nav: +- FastAPI: index.md +- Languages: + - en: / + - es: /es/ +markdown_extensions: +- toc: + permalink: true +- markdown.extensions.codehilite: + guess_lang: false +- markdown_include.include: + base_path: docs +- admonition +- codehilite +- extra +- pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_div_format '' +extra: + social: + - type: github + link: https://github.com/tiangolo/typer + - type: twitter + link: https://twitter.com/tiangolo + - type: linkedin + link: https://www.linkedin.com/in/tiangolo + - type: rss + link: https://dev.to/tiangolo + - type: medium + link: https://medium.com/@tiangolo + - type: globe + link: https://tiangolo.com +extra_css: +- https://fastapi.tiangolo.com/css/termynal.css +- https://fastapi.tiangolo.com/css/custom.css +extra_javascript: +- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js +- https://fastapi.tiangolo.com/js/termynal.js +- https://fastapi.tiangolo.com/js/custom.js diff --git a/docs/missing-translation.md b/docs/missing-translation.md new file mode 100644 index 000000000..32b6016f9 --- /dev/null +++ b/docs/missing-translation.md @@ -0,0 +1,4 @@ +!!! warning + The current page still doesn't have a translation for this language. + + But you can help translating it: [Contributing](https://fastapi.tiangolo.com/contributing/){.internal-link target=_blank}. diff --git a/docs/src/additional_responses/tutorial001.py b/docs_src/additional_responses/tutorial001.py similarity index 100% rename from docs/src/additional_responses/tutorial001.py rename to docs_src/additional_responses/tutorial001.py diff --git a/docs/src/additional_responses/tutorial002.py b/docs_src/additional_responses/tutorial002.py similarity index 100% rename from docs/src/additional_responses/tutorial002.py rename to docs_src/additional_responses/tutorial002.py diff --git a/docs/src/additional_responses/tutorial003.py b/docs_src/additional_responses/tutorial003.py similarity index 100% rename from docs/src/additional_responses/tutorial003.py rename to docs_src/additional_responses/tutorial003.py diff --git a/docs/src/additional_responses/tutorial004.py b/docs_src/additional_responses/tutorial004.py similarity index 100% rename from docs/src/additional_responses/tutorial004.py rename to docs_src/additional_responses/tutorial004.py diff --git a/docs/src/additional_status_codes/tutorial001.py b/docs_src/additional_status_codes/tutorial001.py similarity index 100% rename from docs/src/additional_status_codes/tutorial001.py rename to docs_src/additional_status_codes/tutorial001.py diff --git a/docs/src/advanced_middleware/tutorial001.py b/docs_src/advanced_middleware/tutorial001.py similarity index 100% rename from docs/src/advanced_middleware/tutorial001.py rename to docs_src/advanced_middleware/tutorial001.py diff --git a/docs/src/advanced_middleware/tutorial002.py b/docs_src/advanced_middleware/tutorial002.py similarity index 100% rename from docs/src/advanced_middleware/tutorial002.py rename to docs_src/advanced_middleware/tutorial002.py diff --git a/docs/src/advanced_middleware/tutorial003.py b/docs_src/advanced_middleware/tutorial003.py similarity index 100% rename from docs/src/advanced_middleware/tutorial003.py rename to docs_src/advanced_middleware/tutorial003.py diff --git a/docs/src/app_testing/__init__.py b/docs_src/app_testing/__init__.py similarity index 100% rename from docs/src/app_testing/__init__.py rename to docs_src/app_testing/__init__.py diff --git a/docs/src/app_testing/main.py b/docs_src/app_testing/main.py similarity index 100% rename from docs/src/app_testing/main.py rename to docs_src/app_testing/main.py diff --git a/docs/src/app_testing/main_b.py b/docs_src/app_testing/main_b.py similarity index 100% rename from docs/src/app_testing/main_b.py rename to docs_src/app_testing/main_b.py diff --git a/docs/src/app_testing/test_main.py b/docs_src/app_testing/test_main.py similarity index 100% rename from docs/src/app_testing/test_main.py rename to docs_src/app_testing/test_main.py diff --git a/docs/src/app_testing/test_main_b.py b/docs_src/app_testing/test_main_b.py similarity index 100% rename from docs/src/app_testing/test_main_b.py rename to docs_src/app_testing/test_main_b.py diff --git a/docs/src/app_testing/tutorial001.py b/docs_src/app_testing/tutorial001.py similarity index 100% rename from docs/src/app_testing/tutorial001.py rename to docs_src/app_testing/tutorial001.py diff --git a/docs/src/app_testing/tutorial002.py b/docs_src/app_testing/tutorial002.py similarity index 100% rename from docs/src/app_testing/tutorial002.py rename to docs_src/app_testing/tutorial002.py diff --git a/docs/src/app_testing/tutorial003.py b/docs_src/app_testing/tutorial003.py similarity index 100% rename from docs/src/app_testing/tutorial003.py rename to docs_src/app_testing/tutorial003.py diff --git a/docs/src/application_configuration/tutorial001.py b/docs_src/application_configuration/tutorial001.py similarity index 100% rename from docs/src/application_configuration/tutorial001.py rename to docs_src/application_configuration/tutorial001.py diff --git a/docs/src/application_configuration/tutorial002.py b/docs_src/application_configuration/tutorial002.py similarity index 100% rename from docs/src/application_configuration/tutorial002.py rename to docs_src/application_configuration/tutorial002.py diff --git a/docs/src/application_configuration/tutorial003.py b/docs_src/application_configuration/tutorial003.py similarity index 100% rename from docs/src/application_configuration/tutorial003.py rename to docs_src/application_configuration/tutorial003.py diff --git a/docs/src/async_sql_databases/tutorial001.py b/docs_src/async_sql_databases/tutorial001.py similarity index 100% rename from docs/src/async_sql_databases/tutorial001.py rename to docs_src/async_sql_databases/tutorial001.py diff --git a/docs/src/background_tasks/tutorial001.py b/docs_src/background_tasks/tutorial001.py similarity index 100% rename from docs/src/background_tasks/tutorial001.py rename to docs_src/background_tasks/tutorial001.py diff --git a/docs/src/background_tasks/tutorial002.py b/docs_src/background_tasks/tutorial002.py similarity index 100% rename from docs/src/background_tasks/tutorial002.py rename to docs_src/background_tasks/tutorial002.py diff --git a/docs/src/bigger_applications/__init__.py b/docs_src/bigger_applications/__init__.py similarity index 100% rename from docs/src/bigger_applications/__init__.py rename to docs_src/bigger_applications/__init__.py diff --git a/docs/src/bigger_applications/app/__init__.py b/docs_src/bigger_applications/app/__init__.py similarity index 100% rename from docs/src/bigger_applications/app/__init__.py rename to docs_src/bigger_applications/app/__init__.py diff --git a/docs/src/bigger_applications/app/main.py b/docs_src/bigger_applications/app/main.py similarity index 100% rename from docs/src/bigger_applications/app/main.py rename to docs_src/bigger_applications/app/main.py diff --git a/docs/src/bigger_applications/app/routers/__init__.py b/docs_src/bigger_applications/app/routers/__init__.py similarity index 100% rename from docs/src/bigger_applications/app/routers/__init__.py rename to docs_src/bigger_applications/app/routers/__init__.py diff --git a/docs/src/bigger_applications/app/routers/items.py b/docs_src/bigger_applications/app/routers/items.py similarity index 100% rename from docs/src/bigger_applications/app/routers/items.py rename to docs_src/bigger_applications/app/routers/items.py diff --git a/docs/src/bigger_applications/app/routers/users.py b/docs_src/bigger_applications/app/routers/users.py similarity index 100% rename from docs/src/bigger_applications/app/routers/users.py rename to docs_src/bigger_applications/app/routers/users.py diff --git a/docs/src/body/tutorial001.py b/docs_src/body/tutorial001.py similarity index 100% rename from docs/src/body/tutorial001.py rename to docs_src/body/tutorial001.py diff --git a/docs/src/body/tutorial002.py b/docs_src/body/tutorial002.py similarity index 100% rename from docs/src/body/tutorial002.py rename to docs_src/body/tutorial002.py diff --git a/docs/src/body/tutorial003.py b/docs_src/body/tutorial003.py similarity index 100% rename from docs/src/body/tutorial003.py rename to docs_src/body/tutorial003.py diff --git a/docs/src/body/tutorial004.py b/docs_src/body/tutorial004.py similarity index 100% rename from docs/src/body/tutorial004.py rename to docs_src/body/tutorial004.py diff --git a/docs/src/body_fields/tutorial001.py b/docs_src/body_fields/tutorial001.py similarity index 100% rename from docs/src/body_fields/tutorial001.py rename to docs_src/body_fields/tutorial001.py diff --git a/docs/src/body_fields/tutorial002.py b/docs_src/body_fields/tutorial002.py similarity index 100% rename from docs/src/body_fields/tutorial002.py rename to docs_src/body_fields/tutorial002.py diff --git a/docs/src/body_multiple_params/tutorial001.py b/docs_src/body_multiple_params/tutorial001.py similarity index 100% rename from docs/src/body_multiple_params/tutorial001.py rename to docs_src/body_multiple_params/tutorial001.py diff --git a/docs/src/body_multiple_params/tutorial002.py b/docs_src/body_multiple_params/tutorial002.py similarity index 100% rename from docs/src/body_multiple_params/tutorial002.py rename to docs_src/body_multiple_params/tutorial002.py diff --git a/docs/src/body_multiple_params/tutorial003.py b/docs_src/body_multiple_params/tutorial003.py similarity index 100% rename from docs/src/body_multiple_params/tutorial003.py rename to docs_src/body_multiple_params/tutorial003.py diff --git a/docs/src/body_multiple_params/tutorial004.py b/docs_src/body_multiple_params/tutorial004.py similarity index 100% rename from docs/src/body_multiple_params/tutorial004.py rename to docs_src/body_multiple_params/tutorial004.py diff --git a/docs/src/body_multiple_params/tutorial005.py b/docs_src/body_multiple_params/tutorial005.py similarity index 100% rename from docs/src/body_multiple_params/tutorial005.py rename to docs_src/body_multiple_params/tutorial005.py diff --git a/docs/src/body_nested_models/tutorial001.py b/docs_src/body_nested_models/tutorial001.py similarity index 100% rename from docs/src/body_nested_models/tutorial001.py rename to docs_src/body_nested_models/tutorial001.py diff --git a/docs/src/body_nested_models/tutorial002.py b/docs_src/body_nested_models/tutorial002.py similarity index 100% rename from docs/src/body_nested_models/tutorial002.py rename to docs_src/body_nested_models/tutorial002.py diff --git a/docs/src/body_nested_models/tutorial003.py b/docs_src/body_nested_models/tutorial003.py similarity index 100% rename from docs/src/body_nested_models/tutorial003.py rename to docs_src/body_nested_models/tutorial003.py diff --git a/docs/src/body_nested_models/tutorial004.py b/docs_src/body_nested_models/tutorial004.py similarity index 100% rename from docs/src/body_nested_models/tutorial004.py rename to docs_src/body_nested_models/tutorial004.py diff --git a/docs/src/body_nested_models/tutorial005.py b/docs_src/body_nested_models/tutorial005.py similarity index 100% rename from docs/src/body_nested_models/tutorial005.py rename to docs_src/body_nested_models/tutorial005.py diff --git a/docs/src/body_nested_models/tutorial006.py b/docs_src/body_nested_models/tutorial006.py similarity index 100% rename from docs/src/body_nested_models/tutorial006.py rename to docs_src/body_nested_models/tutorial006.py diff --git a/docs/src/body_nested_models/tutorial007.py b/docs_src/body_nested_models/tutorial007.py similarity index 100% rename from docs/src/body_nested_models/tutorial007.py rename to docs_src/body_nested_models/tutorial007.py diff --git a/docs/src/body_nested_models/tutorial008.py b/docs_src/body_nested_models/tutorial008.py similarity index 100% rename from docs/src/body_nested_models/tutorial008.py rename to docs_src/body_nested_models/tutorial008.py diff --git a/docs/src/body_nested_models/tutorial009.py b/docs_src/body_nested_models/tutorial009.py similarity index 100% rename from docs/src/body_nested_models/tutorial009.py rename to docs_src/body_nested_models/tutorial009.py diff --git a/docs/src/body_updates/tutorial001.py b/docs_src/body_updates/tutorial001.py similarity index 100% rename from docs/src/body_updates/tutorial001.py rename to docs_src/body_updates/tutorial001.py diff --git a/docs/src/body_updates/tutorial002.py b/docs_src/body_updates/tutorial002.py similarity index 100% rename from docs/src/body_updates/tutorial002.py rename to docs_src/body_updates/tutorial002.py diff --git a/docs/src/cookie_params/tutorial001.py b/docs_src/cookie_params/tutorial001.py similarity index 100% rename from docs/src/cookie_params/tutorial001.py rename to docs_src/cookie_params/tutorial001.py diff --git a/docs/src/cors/tutorial001.py b/docs_src/cors/tutorial001.py similarity index 100% rename from docs/src/cors/tutorial001.py rename to docs_src/cors/tutorial001.py diff --git a/docs/src/custom_request_and_route/tutorial001.py b/docs_src/custom_request_and_route/tutorial001.py similarity index 100% rename from docs/src/custom_request_and_route/tutorial001.py rename to docs_src/custom_request_and_route/tutorial001.py diff --git a/docs/src/custom_request_and_route/tutorial002.py b/docs_src/custom_request_and_route/tutorial002.py similarity index 100% rename from docs/src/custom_request_and_route/tutorial002.py rename to docs_src/custom_request_and_route/tutorial002.py diff --git a/docs/src/custom_request_and_route/tutorial003.py b/docs_src/custom_request_and_route/tutorial003.py similarity index 100% rename from docs/src/custom_request_and_route/tutorial003.py rename to docs_src/custom_request_and_route/tutorial003.py diff --git a/docs/src/custom_response/tutorial001.py b/docs_src/custom_response/tutorial001.py similarity index 100% rename from docs/src/custom_response/tutorial001.py rename to docs_src/custom_response/tutorial001.py diff --git a/docs/src/custom_response/tutorial001b.py b/docs_src/custom_response/tutorial001b.py similarity index 100% rename from docs/src/custom_response/tutorial001b.py rename to docs_src/custom_response/tutorial001b.py diff --git a/docs/src/custom_response/tutorial002.py b/docs_src/custom_response/tutorial002.py similarity index 100% rename from docs/src/custom_response/tutorial002.py rename to docs_src/custom_response/tutorial002.py diff --git a/docs/src/custom_response/tutorial003.py b/docs_src/custom_response/tutorial003.py similarity index 100% rename from docs/src/custom_response/tutorial003.py rename to docs_src/custom_response/tutorial003.py diff --git a/docs/src/custom_response/tutorial004.py b/docs_src/custom_response/tutorial004.py similarity index 100% rename from docs/src/custom_response/tutorial004.py rename to docs_src/custom_response/tutorial004.py diff --git a/docs/src/custom_response/tutorial005.py b/docs_src/custom_response/tutorial005.py similarity index 100% rename from docs/src/custom_response/tutorial005.py rename to docs_src/custom_response/tutorial005.py diff --git a/docs/src/custom_response/tutorial006.py b/docs_src/custom_response/tutorial006.py similarity index 100% rename from docs/src/custom_response/tutorial006.py rename to docs_src/custom_response/tutorial006.py diff --git a/docs/src/custom_response/tutorial007.py b/docs_src/custom_response/tutorial007.py similarity index 100% rename from docs/src/custom_response/tutorial007.py rename to docs_src/custom_response/tutorial007.py diff --git a/docs/src/custom_response/tutorial008.py b/docs_src/custom_response/tutorial008.py similarity index 100% rename from docs/src/custom_response/tutorial008.py rename to docs_src/custom_response/tutorial008.py diff --git a/docs/src/custom_response/tutorial009.py b/docs_src/custom_response/tutorial009.py similarity index 100% rename from docs/src/custom_response/tutorial009.py rename to docs_src/custom_response/tutorial009.py diff --git a/docs/src/debugging/tutorial001.py b/docs_src/debugging/tutorial001.py similarity index 100% rename from docs/src/debugging/tutorial001.py rename to docs_src/debugging/tutorial001.py diff --git a/docs/src/dependencies/tutorial001.py b/docs_src/dependencies/tutorial001.py similarity index 100% rename from docs/src/dependencies/tutorial001.py rename to docs_src/dependencies/tutorial001.py diff --git a/docs/src/dependencies/tutorial002.py b/docs_src/dependencies/tutorial002.py similarity index 100% rename from docs/src/dependencies/tutorial002.py rename to docs_src/dependencies/tutorial002.py diff --git a/docs/src/dependencies/tutorial003.py b/docs_src/dependencies/tutorial003.py similarity index 100% rename from docs/src/dependencies/tutorial003.py rename to docs_src/dependencies/tutorial003.py diff --git a/docs/src/dependencies/tutorial004.py b/docs_src/dependencies/tutorial004.py similarity index 100% rename from docs/src/dependencies/tutorial004.py rename to docs_src/dependencies/tutorial004.py diff --git a/docs/src/dependencies/tutorial005.py b/docs_src/dependencies/tutorial005.py similarity index 100% rename from docs/src/dependencies/tutorial005.py rename to docs_src/dependencies/tutorial005.py diff --git a/docs/src/dependencies/tutorial006.py b/docs_src/dependencies/tutorial006.py similarity index 100% rename from docs/src/dependencies/tutorial006.py rename to docs_src/dependencies/tutorial006.py diff --git a/docs/src/dependencies/tutorial007.py b/docs_src/dependencies/tutorial007.py similarity index 100% rename from docs/src/dependencies/tutorial007.py rename to docs_src/dependencies/tutorial007.py diff --git a/docs/src/dependencies/tutorial008.py b/docs_src/dependencies/tutorial008.py similarity index 100% rename from docs/src/dependencies/tutorial008.py rename to docs_src/dependencies/tutorial008.py diff --git a/docs/src/dependencies/tutorial009.py b/docs_src/dependencies/tutorial009.py similarity index 100% rename from docs/src/dependencies/tutorial009.py rename to docs_src/dependencies/tutorial009.py diff --git a/docs/src/dependencies/tutorial010.py b/docs_src/dependencies/tutorial010.py similarity index 100% rename from docs/src/dependencies/tutorial010.py rename to docs_src/dependencies/tutorial010.py diff --git a/docs/src/dependencies/tutorial011.py b/docs_src/dependencies/tutorial011.py similarity index 100% rename from docs/src/dependencies/tutorial011.py rename to docs_src/dependencies/tutorial011.py diff --git a/docs/src/dependency_testing/tutorial001.py b/docs_src/dependency_testing/tutorial001.py similarity index 100% rename from docs/src/dependency_testing/tutorial001.py rename to docs_src/dependency_testing/tutorial001.py diff --git a/docs/src/encoder/tutorial001.py b/docs_src/encoder/tutorial001.py similarity index 100% rename from docs/src/encoder/tutorial001.py rename to docs_src/encoder/tutorial001.py diff --git a/docs/src/events/tutorial001.py b/docs_src/events/tutorial001.py similarity index 100% rename from docs/src/events/tutorial001.py rename to docs_src/events/tutorial001.py diff --git a/docs/src/events/tutorial002.py b/docs_src/events/tutorial002.py similarity index 100% rename from docs/src/events/tutorial002.py rename to docs_src/events/tutorial002.py diff --git a/docs/src/extending_openapi/tutorial001.py b/docs_src/extending_openapi/tutorial001.py similarity index 100% rename from docs/src/extending_openapi/tutorial001.py rename to docs_src/extending_openapi/tutorial001.py diff --git a/docs/src/extending_openapi/tutorial002.py b/docs_src/extending_openapi/tutorial002.py similarity index 100% rename from docs/src/extending_openapi/tutorial002.py rename to docs_src/extending_openapi/tutorial002.py diff --git a/docs/src/extra_data_types/tutorial001.py b/docs_src/extra_data_types/tutorial001.py similarity index 100% rename from docs/src/extra_data_types/tutorial001.py rename to docs_src/extra_data_types/tutorial001.py diff --git a/docs/src/extra_models/tutorial001.py b/docs_src/extra_models/tutorial001.py similarity index 100% rename from docs/src/extra_models/tutorial001.py rename to docs_src/extra_models/tutorial001.py diff --git a/docs/src/extra_models/tutorial002.py b/docs_src/extra_models/tutorial002.py similarity index 100% rename from docs/src/extra_models/tutorial002.py rename to docs_src/extra_models/tutorial002.py diff --git a/docs/src/extra_models/tutorial003.py b/docs_src/extra_models/tutorial003.py similarity index 100% rename from docs/src/extra_models/tutorial003.py rename to docs_src/extra_models/tutorial003.py diff --git a/docs/src/extra_models/tutorial004.py b/docs_src/extra_models/tutorial004.py similarity index 100% rename from docs/src/extra_models/tutorial004.py rename to docs_src/extra_models/tutorial004.py diff --git a/docs/src/extra_models/tutorial005.py b/docs_src/extra_models/tutorial005.py similarity index 100% rename from docs/src/extra_models/tutorial005.py rename to docs_src/extra_models/tutorial005.py diff --git a/docs/src/first_steps/tutorial001.py b/docs_src/first_steps/tutorial001.py similarity index 100% rename from docs/src/first_steps/tutorial001.py rename to docs_src/first_steps/tutorial001.py diff --git a/docs/src/first_steps/tutorial002.py b/docs_src/first_steps/tutorial002.py similarity index 100% rename from docs/src/first_steps/tutorial002.py rename to docs_src/first_steps/tutorial002.py diff --git a/docs/src/first_steps/tutorial003.py b/docs_src/first_steps/tutorial003.py similarity index 100% rename from docs/src/first_steps/tutorial003.py rename to docs_src/first_steps/tutorial003.py diff --git a/docs/src/graphql/tutorial001.py b/docs_src/graphql/tutorial001.py similarity index 100% rename from docs/src/graphql/tutorial001.py rename to docs_src/graphql/tutorial001.py diff --git a/docs/src/handling_errors/tutorial001.py b/docs_src/handling_errors/tutorial001.py similarity index 100% rename from docs/src/handling_errors/tutorial001.py rename to docs_src/handling_errors/tutorial001.py diff --git a/docs/src/handling_errors/tutorial002.py b/docs_src/handling_errors/tutorial002.py similarity index 100% rename from docs/src/handling_errors/tutorial002.py rename to docs_src/handling_errors/tutorial002.py diff --git a/docs/src/handling_errors/tutorial003.py b/docs_src/handling_errors/tutorial003.py similarity index 100% rename from docs/src/handling_errors/tutorial003.py rename to docs_src/handling_errors/tutorial003.py diff --git a/docs/src/handling_errors/tutorial004.py b/docs_src/handling_errors/tutorial004.py similarity index 100% rename from docs/src/handling_errors/tutorial004.py rename to docs_src/handling_errors/tutorial004.py diff --git a/docs/src/handling_errors/tutorial005.py b/docs_src/handling_errors/tutorial005.py similarity index 100% rename from docs/src/handling_errors/tutorial005.py rename to docs_src/handling_errors/tutorial005.py diff --git a/docs/src/handling_errors/tutorial006.py b/docs_src/handling_errors/tutorial006.py similarity index 100% rename from docs/src/handling_errors/tutorial006.py rename to docs_src/handling_errors/tutorial006.py diff --git a/docs/src/header_params/tutorial001.py b/docs_src/header_params/tutorial001.py similarity index 100% rename from docs/src/header_params/tutorial001.py rename to docs_src/header_params/tutorial001.py diff --git a/docs/src/header_params/tutorial002.py b/docs_src/header_params/tutorial002.py similarity index 100% rename from docs/src/header_params/tutorial002.py rename to docs_src/header_params/tutorial002.py diff --git a/docs/src/header_params/tutorial003.py b/docs_src/header_params/tutorial003.py similarity index 100% rename from docs/src/header_params/tutorial003.py rename to docs_src/header_params/tutorial003.py diff --git a/docs/src/middleware/tutorial001.py b/docs_src/middleware/tutorial001.py similarity index 100% rename from docs/src/middleware/tutorial001.py rename to docs_src/middleware/tutorial001.py diff --git a/docs/src/nosql_databases/tutorial001.py b/docs_src/nosql_databases/tutorial001.py similarity index 100% rename from docs/src/nosql_databases/tutorial001.py rename to docs_src/nosql_databases/tutorial001.py diff --git a/docs/src/openapi_callbacks/tutorial001.py b/docs_src/openapi_callbacks/tutorial001.py similarity index 100% rename from docs/src/openapi_callbacks/tutorial001.py rename to docs_src/openapi_callbacks/tutorial001.py diff --git a/docs/src/path_operation_advanced_configuration/tutorial001.py b/docs_src/path_operation_advanced_configuration/tutorial001.py similarity index 100% rename from docs/src/path_operation_advanced_configuration/tutorial001.py rename to docs_src/path_operation_advanced_configuration/tutorial001.py diff --git a/docs/src/path_operation_advanced_configuration/tutorial002.py b/docs_src/path_operation_advanced_configuration/tutorial002.py similarity index 100% rename from docs/src/path_operation_advanced_configuration/tutorial002.py rename to docs_src/path_operation_advanced_configuration/tutorial002.py diff --git a/docs/src/path_operation_advanced_configuration/tutorial003.py b/docs_src/path_operation_advanced_configuration/tutorial003.py similarity index 100% rename from docs/src/path_operation_advanced_configuration/tutorial003.py rename to docs_src/path_operation_advanced_configuration/tutorial003.py diff --git a/docs/src/path_operation_advanced_configuration/tutorial004.py b/docs_src/path_operation_advanced_configuration/tutorial004.py similarity index 100% rename from docs/src/path_operation_advanced_configuration/tutorial004.py rename to docs_src/path_operation_advanced_configuration/tutorial004.py diff --git a/docs/src/path_operation_configuration/tutorial001.py b/docs_src/path_operation_configuration/tutorial001.py similarity index 100% rename from docs/src/path_operation_configuration/tutorial001.py rename to docs_src/path_operation_configuration/tutorial001.py diff --git a/docs/src/path_operation_configuration/tutorial002.py b/docs_src/path_operation_configuration/tutorial002.py similarity index 100% rename from docs/src/path_operation_configuration/tutorial002.py rename to docs_src/path_operation_configuration/tutorial002.py diff --git a/docs/src/path_operation_configuration/tutorial003.py b/docs_src/path_operation_configuration/tutorial003.py similarity index 100% rename from docs/src/path_operation_configuration/tutorial003.py rename to docs_src/path_operation_configuration/tutorial003.py diff --git a/docs/src/path_operation_configuration/tutorial004.py b/docs_src/path_operation_configuration/tutorial004.py similarity index 100% rename from docs/src/path_operation_configuration/tutorial004.py rename to docs_src/path_operation_configuration/tutorial004.py diff --git a/docs/src/path_operation_configuration/tutorial005.py b/docs_src/path_operation_configuration/tutorial005.py similarity index 100% rename from docs/src/path_operation_configuration/tutorial005.py rename to docs_src/path_operation_configuration/tutorial005.py diff --git a/docs/src/path_operation_configuration/tutorial006.py b/docs_src/path_operation_configuration/tutorial006.py similarity index 100% rename from docs/src/path_operation_configuration/tutorial006.py rename to docs_src/path_operation_configuration/tutorial006.py diff --git a/docs/src/path_params/tutorial001.py b/docs_src/path_params/tutorial001.py similarity index 100% rename from docs/src/path_params/tutorial001.py rename to docs_src/path_params/tutorial001.py diff --git a/docs/src/path_params/tutorial002.py b/docs_src/path_params/tutorial002.py similarity index 100% rename from docs/src/path_params/tutorial002.py rename to docs_src/path_params/tutorial002.py diff --git a/docs/src/path_params/tutorial003.py b/docs_src/path_params/tutorial003.py similarity index 100% rename from docs/src/path_params/tutorial003.py rename to docs_src/path_params/tutorial003.py diff --git a/docs/src/path_params/tutorial004.py b/docs_src/path_params/tutorial004.py similarity index 100% rename from docs/src/path_params/tutorial004.py rename to docs_src/path_params/tutorial004.py diff --git a/docs/src/path_params/tutorial005.py b/docs_src/path_params/tutorial005.py similarity index 100% rename from docs/src/path_params/tutorial005.py rename to docs_src/path_params/tutorial005.py diff --git a/docs/src/path_params_numeric_validations/tutorial001.py b/docs_src/path_params_numeric_validations/tutorial001.py similarity index 100% rename from docs/src/path_params_numeric_validations/tutorial001.py rename to docs_src/path_params_numeric_validations/tutorial001.py diff --git a/docs/src/path_params_numeric_validations/tutorial002.py b/docs_src/path_params_numeric_validations/tutorial002.py similarity index 100% rename from docs/src/path_params_numeric_validations/tutorial002.py rename to docs_src/path_params_numeric_validations/tutorial002.py diff --git a/docs/src/path_params_numeric_validations/tutorial003.py b/docs_src/path_params_numeric_validations/tutorial003.py similarity index 100% rename from docs/src/path_params_numeric_validations/tutorial003.py rename to docs_src/path_params_numeric_validations/tutorial003.py diff --git a/docs/src/path_params_numeric_validations/tutorial004.py b/docs_src/path_params_numeric_validations/tutorial004.py similarity index 100% rename from docs/src/path_params_numeric_validations/tutorial004.py rename to docs_src/path_params_numeric_validations/tutorial004.py diff --git a/docs/src/path_params_numeric_validations/tutorial005.py b/docs_src/path_params_numeric_validations/tutorial005.py similarity index 100% rename from docs/src/path_params_numeric_validations/tutorial005.py rename to docs_src/path_params_numeric_validations/tutorial005.py diff --git a/docs/src/path_params_numeric_validations/tutorial006.py b/docs_src/path_params_numeric_validations/tutorial006.py similarity index 100% rename from docs/src/path_params_numeric_validations/tutorial006.py rename to docs_src/path_params_numeric_validations/tutorial006.py diff --git a/docs/src/python_types/tutorial001.py b/docs_src/python_types/tutorial001.py similarity index 100% rename from docs/src/python_types/tutorial001.py rename to docs_src/python_types/tutorial001.py diff --git a/docs/src/python_types/tutorial002.py b/docs_src/python_types/tutorial002.py similarity index 100% rename from docs/src/python_types/tutorial002.py rename to docs_src/python_types/tutorial002.py diff --git a/docs/src/python_types/tutorial003.py b/docs_src/python_types/tutorial003.py similarity index 100% rename from docs/src/python_types/tutorial003.py rename to docs_src/python_types/tutorial003.py diff --git a/docs/src/python_types/tutorial004.py b/docs_src/python_types/tutorial004.py similarity index 100% rename from docs/src/python_types/tutorial004.py rename to docs_src/python_types/tutorial004.py diff --git a/docs/src/python_types/tutorial005.py b/docs_src/python_types/tutorial005.py similarity index 100% rename from docs/src/python_types/tutorial005.py rename to docs_src/python_types/tutorial005.py diff --git a/docs/src/python_types/tutorial006.py b/docs_src/python_types/tutorial006.py similarity index 100% rename from docs/src/python_types/tutorial006.py rename to docs_src/python_types/tutorial006.py diff --git a/docs/src/python_types/tutorial007.py b/docs_src/python_types/tutorial007.py similarity index 100% rename from docs/src/python_types/tutorial007.py rename to docs_src/python_types/tutorial007.py diff --git a/docs/src/python_types/tutorial008.py b/docs_src/python_types/tutorial008.py similarity index 100% rename from docs/src/python_types/tutorial008.py rename to docs_src/python_types/tutorial008.py diff --git a/docs/src/python_types/tutorial009.py b/docs_src/python_types/tutorial009.py similarity index 100% rename from docs/src/python_types/tutorial009.py rename to docs_src/python_types/tutorial009.py diff --git a/docs/src/python_types/tutorial010.py b/docs_src/python_types/tutorial010.py similarity index 100% rename from docs/src/python_types/tutorial010.py rename to docs_src/python_types/tutorial010.py diff --git a/docs/src/query_params/tutorial001.py b/docs_src/query_params/tutorial001.py similarity index 100% rename from docs/src/query_params/tutorial001.py rename to docs_src/query_params/tutorial001.py diff --git a/docs/src/query_params/tutorial002.py b/docs_src/query_params/tutorial002.py similarity index 100% rename from docs/src/query_params/tutorial002.py rename to docs_src/query_params/tutorial002.py diff --git a/docs/src/query_params/tutorial003.py b/docs_src/query_params/tutorial003.py similarity index 100% rename from docs/src/query_params/tutorial003.py rename to docs_src/query_params/tutorial003.py diff --git a/docs/src/query_params/tutorial004.py b/docs_src/query_params/tutorial004.py similarity index 100% rename from docs/src/query_params/tutorial004.py rename to docs_src/query_params/tutorial004.py diff --git a/docs/src/query_params/tutorial005.py b/docs_src/query_params/tutorial005.py similarity index 100% rename from docs/src/query_params/tutorial005.py rename to docs_src/query_params/tutorial005.py diff --git a/docs/src/query_params/tutorial006.py b/docs_src/query_params/tutorial006.py similarity index 100% rename from docs/src/query_params/tutorial006.py rename to docs_src/query_params/tutorial006.py diff --git a/docs/src/query_params/tutorial007.py b/docs_src/query_params/tutorial007.py similarity index 100% rename from docs/src/query_params/tutorial007.py rename to docs_src/query_params/tutorial007.py diff --git a/docs/src/query_params_str_validations/tutorial001.py b/docs_src/query_params_str_validations/tutorial001.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial001.py rename to docs_src/query_params_str_validations/tutorial001.py diff --git a/docs/src/query_params_str_validations/tutorial002.py b/docs_src/query_params_str_validations/tutorial002.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial002.py rename to docs_src/query_params_str_validations/tutorial002.py diff --git a/docs/src/query_params_str_validations/tutorial003.py b/docs_src/query_params_str_validations/tutorial003.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial003.py rename to docs_src/query_params_str_validations/tutorial003.py diff --git a/docs/src/query_params_str_validations/tutorial004.py b/docs_src/query_params_str_validations/tutorial004.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial004.py rename to docs_src/query_params_str_validations/tutorial004.py diff --git a/docs/src/query_params_str_validations/tutorial005.py b/docs_src/query_params_str_validations/tutorial005.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial005.py rename to docs_src/query_params_str_validations/tutorial005.py diff --git a/docs/src/query_params_str_validations/tutorial006.py b/docs_src/query_params_str_validations/tutorial006.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial006.py rename to docs_src/query_params_str_validations/tutorial006.py diff --git a/docs/src/query_params_str_validations/tutorial007.py b/docs_src/query_params_str_validations/tutorial007.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial007.py rename to docs_src/query_params_str_validations/tutorial007.py diff --git a/docs/src/query_params_str_validations/tutorial008.py b/docs_src/query_params_str_validations/tutorial008.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial008.py rename to docs_src/query_params_str_validations/tutorial008.py diff --git a/docs/src/query_params_str_validations/tutorial009.py b/docs_src/query_params_str_validations/tutorial009.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial009.py rename to docs_src/query_params_str_validations/tutorial009.py diff --git a/docs/src/query_params_str_validations/tutorial010.py b/docs_src/query_params_str_validations/tutorial010.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial010.py rename to docs_src/query_params_str_validations/tutorial010.py diff --git a/docs/src/query_params_str_validations/tutorial011.py b/docs_src/query_params_str_validations/tutorial011.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial011.py rename to docs_src/query_params_str_validations/tutorial011.py diff --git a/docs/src/query_params_str_validations/tutorial012.py b/docs_src/query_params_str_validations/tutorial012.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial012.py rename to docs_src/query_params_str_validations/tutorial012.py diff --git a/docs/src/query_params_str_validations/tutorial013.py b/docs_src/query_params_str_validations/tutorial013.py similarity index 100% rename from docs/src/query_params_str_validations/tutorial013.py rename to docs_src/query_params_str_validations/tutorial013.py diff --git a/docs/src/request_files/tutorial001.py b/docs_src/request_files/tutorial001.py similarity index 100% rename from docs/src/request_files/tutorial001.py rename to docs_src/request_files/tutorial001.py diff --git a/docs/src/request_files/tutorial002.py b/docs_src/request_files/tutorial002.py similarity index 100% rename from docs/src/request_files/tutorial002.py rename to docs_src/request_files/tutorial002.py diff --git a/docs/src/request_forms/tutorial001.py b/docs_src/request_forms/tutorial001.py similarity index 100% rename from docs/src/request_forms/tutorial001.py rename to docs_src/request_forms/tutorial001.py diff --git a/docs/src/request_forms_and_files/tutorial001.py b/docs_src/request_forms_and_files/tutorial001.py similarity index 100% rename from docs/src/request_forms_and_files/tutorial001.py rename to docs_src/request_forms_and_files/tutorial001.py diff --git a/docs/src/response_change_status_code/tutorial001.py b/docs_src/response_change_status_code/tutorial001.py similarity index 100% rename from docs/src/response_change_status_code/tutorial001.py rename to docs_src/response_change_status_code/tutorial001.py diff --git a/docs/src/response_cookies/tutorial001.py b/docs_src/response_cookies/tutorial001.py similarity index 100% rename from docs/src/response_cookies/tutorial001.py rename to docs_src/response_cookies/tutorial001.py diff --git a/docs/src/response_cookies/tutorial002.py b/docs_src/response_cookies/tutorial002.py similarity index 100% rename from docs/src/response_cookies/tutorial002.py rename to docs_src/response_cookies/tutorial002.py diff --git a/docs/src/response_directly/tutorial001.py b/docs_src/response_directly/tutorial001.py similarity index 100% rename from docs/src/response_directly/tutorial001.py rename to docs_src/response_directly/tutorial001.py diff --git a/docs/src/response_directly/tutorial002.py b/docs_src/response_directly/tutorial002.py similarity index 100% rename from docs/src/response_directly/tutorial002.py rename to docs_src/response_directly/tutorial002.py diff --git a/docs/src/response_headers/tutorial001.py b/docs_src/response_headers/tutorial001.py similarity index 100% rename from docs/src/response_headers/tutorial001.py rename to docs_src/response_headers/tutorial001.py diff --git a/docs/src/response_headers/tutorial002.py b/docs_src/response_headers/tutorial002.py similarity index 100% rename from docs/src/response_headers/tutorial002.py rename to docs_src/response_headers/tutorial002.py diff --git a/docs/src/response_model/tutorial001.py b/docs_src/response_model/tutorial001.py similarity index 100% rename from docs/src/response_model/tutorial001.py rename to docs_src/response_model/tutorial001.py diff --git a/docs/src/response_model/tutorial002.py b/docs_src/response_model/tutorial002.py similarity index 100% rename from docs/src/response_model/tutorial002.py rename to docs_src/response_model/tutorial002.py diff --git a/docs/src/response_model/tutorial003.py b/docs_src/response_model/tutorial003.py similarity index 100% rename from docs/src/response_model/tutorial003.py rename to docs_src/response_model/tutorial003.py diff --git a/docs/src/response_model/tutorial004.py b/docs_src/response_model/tutorial004.py similarity index 100% rename from docs/src/response_model/tutorial004.py rename to docs_src/response_model/tutorial004.py diff --git a/docs/src/response_model/tutorial005.py b/docs_src/response_model/tutorial005.py similarity index 100% rename from docs/src/response_model/tutorial005.py rename to docs_src/response_model/tutorial005.py diff --git a/docs/src/response_model/tutorial006.py b/docs_src/response_model/tutorial006.py similarity index 100% rename from docs/src/response_model/tutorial006.py rename to docs_src/response_model/tutorial006.py diff --git a/docs/src/response_status_code/tutorial001.py b/docs_src/response_status_code/tutorial001.py similarity index 100% rename from docs/src/response_status_code/tutorial001.py rename to docs_src/response_status_code/tutorial001.py diff --git a/docs/src/response_status_code/tutorial002.py b/docs_src/response_status_code/tutorial002.py similarity index 100% rename from docs/src/response_status_code/tutorial002.py rename to docs_src/response_status_code/tutorial002.py diff --git a/docs/src/security/tutorial001.py b/docs_src/security/tutorial001.py similarity index 100% rename from docs/src/security/tutorial001.py rename to docs_src/security/tutorial001.py diff --git a/docs/src/security/tutorial002.py b/docs_src/security/tutorial002.py similarity index 100% rename from docs/src/security/tutorial002.py rename to docs_src/security/tutorial002.py diff --git a/docs/src/security/tutorial003.py b/docs_src/security/tutorial003.py similarity index 100% rename from docs/src/security/tutorial003.py rename to docs_src/security/tutorial003.py diff --git a/docs/src/security/tutorial004.py b/docs_src/security/tutorial004.py similarity index 100% rename from docs/src/security/tutorial004.py rename to docs_src/security/tutorial004.py diff --git a/docs/src/security/tutorial005.py b/docs_src/security/tutorial005.py similarity index 100% rename from docs/src/security/tutorial005.py rename to docs_src/security/tutorial005.py diff --git a/docs/src/security/tutorial006.py b/docs_src/security/tutorial006.py similarity index 100% rename from docs/src/security/tutorial006.py rename to docs_src/security/tutorial006.py diff --git a/docs/src/security/tutorial007.py b/docs_src/security/tutorial007.py similarity index 100% rename from docs/src/security/tutorial007.py rename to docs_src/security/tutorial007.py diff --git a/docs/src/sql_databases/__init__.py b/docs_src/sql_databases/__init__.py similarity index 100% rename from docs/src/sql_databases/__init__.py rename to docs_src/sql_databases/__init__.py diff --git a/docs/src/sql_databases/sql_app/__init__.py b/docs_src/sql_databases/sql_app/__init__.py similarity index 100% rename from docs/src/sql_databases/sql_app/__init__.py rename to docs_src/sql_databases/sql_app/__init__.py diff --git a/docs/src/sql_databases/sql_app/alt_main.py b/docs_src/sql_databases/sql_app/alt_main.py similarity index 100% rename from docs/src/sql_databases/sql_app/alt_main.py rename to docs_src/sql_databases/sql_app/alt_main.py diff --git a/docs/src/sql_databases/sql_app/crud.py b/docs_src/sql_databases/sql_app/crud.py similarity index 100% rename from docs/src/sql_databases/sql_app/crud.py rename to docs_src/sql_databases/sql_app/crud.py diff --git a/docs/src/sql_databases/sql_app/database.py b/docs_src/sql_databases/sql_app/database.py similarity index 100% rename from docs/src/sql_databases/sql_app/database.py rename to docs_src/sql_databases/sql_app/database.py diff --git a/docs/src/sql_databases/sql_app/main.py b/docs_src/sql_databases/sql_app/main.py similarity index 100% rename from docs/src/sql_databases/sql_app/main.py rename to docs_src/sql_databases/sql_app/main.py diff --git a/docs/src/sql_databases/sql_app/models.py b/docs_src/sql_databases/sql_app/models.py similarity index 100% rename from docs/src/sql_databases/sql_app/models.py rename to docs_src/sql_databases/sql_app/models.py diff --git a/docs/src/sql_databases/sql_app/schemas.py b/docs_src/sql_databases/sql_app/schemas.py similarity index 100% rename from docs/src/sql_databases/sql_app/schemas.py rename to docs_src/sql_databases/sql_app/schemas.py diff --git a/docs/src/sql_databases_peewee/__init__.py b/docs_src/sql_databases_peewee/__init__.py similarity index 100% rename from docs/src/sql_databases_peewee/__init__.py rename to docs_src/sql_databases_peewee/__init__.py diff --git a/docs/src/sql_databases_peewee/sql_app/__init__.py b/docs_src/sql_databases_peewee/sql_app/__init__.py similarity index 100% rename from docs/src/sql_databases_peewee/sql_app/__init__.py rename to docs_src/sql_databases_peewee/sql_app/__init__.py diff --git a/docs/src/sql_databases_peewee/sql_app/crud.py b/docs_src/sql_databases_peewee/sql_app/crud.py similarity index 100% rename from docs/src/sql_databases_peewee/sql_app/crud.py rename to docs_src/sql_databases_peewee/sql_app/crud.py diff --git a/docs/src/sql_databases_peewee/sql_app/database.py b/docs_src/sql_databases_peewee/sql_app/database.py similarity index 100% rename from docs/src/sql_databases_peewee/sql_app/database.py rename to docs_src/sql_databases_peewee/sql_app/database.py diff --git a/docs/src/sql_databases_peewee/sql_app/main.py b/docs_src/sql_databases_peewee/sql_app/main.py similarity index 100% rename from docs/src/sql_databases_peewee/sql_app/main.py rename to docs_src/sql_databases_peewee/sql_app/main.py diff --git a/docs/src/sql_databases_peewee/sql_app/models.py b/docs_src/sql_databases_peewee/sql_app/models.py similarity index 100% rename from docs/src/sql_databases_peewee/sql_app/models.py rename to docs_src/sql_databases_peewee/sql_app/models.py diff --git a/docs/src/sql_databases_peewee/sql_app/schemas.py b/docs_src/sql_databases_peewee/sql_app/schemas.py similarity index 100% rename from docs/src/sql_databases_peewee/sql_app/schemas.py rename to docs_src/sql_databases_peewee/sql_app/schemas.py diff --git a/docs/src/static_files/tutorial001.py b/docs_src/static_files/tutorial001.py similarity index 100% rename from docs/src/static_files/tutorial001.py rename to docs_src/static_files/tutorial001.py diff --git a/docs/src/sub_applications/tutorial001.py b/docs_src/sub_applications/tutorial001.py similarity index 100% rename from docs/src/sub_applications/tutorial001.py rename to docs_src/sub_applications/tutorial001.py diff --git a/docs/src/templates/static/styles.css b/docs_src/templates/static/styles.css similarity index 100% rename from docs/src/templates/static/styles.css rename to docs_src/templates/static/styles.css diff --git a/docs/src/templates/templates/item.html b/docs_src/templates/templates/item.html similarity index 100% rename from docs/src/templates/templates/item.html rename to docs_src/templates/templates/item.html diff --git a/docs/src/templates/tutorial001.py b/docs_src/templates/tutorial001.py similarity index 100% rename from docs/src/templates/tutorial001.py rename to docs_src/templates/tutorial001.py diff --git a/docs/src/using_request_directly/tutorial001.py b/docs_src/using_request_directly/tutorial001.py similarity index 100% rename from docs/src/using_request_directly/tutorial001.py rename to docs_src/using_request_directly/tutorial001.py diff --git a/docs/src/websockets/__init__.py b/docs_src/websockets/__init__.py similarity index 100% rename from docs/src/websockets/__init__.py rename to docs_src/websockets/__init__.py diff --git a/docs/src/websockets/tutorial001.py b/docs_src/websockets/tutorial001.py similarity index 100% rename from docs/src/websockets/tutorial001.py rename to docs_src/websockets/tutorial001.py diff --git a/docs/src/websockets/tutorial002.py b/docs_src/websockets/tutorial002.py similarity index 100% rename from docs/src/websockets/tutorial002.py rename to docs_src/websockets/tutorial002.py diff --git a/docs/src/wsgi/tutorial001.py b/docs_src/wsgi/tutorial001.py similarity index 100% rename from docs/src/wsgi/tutorial001.py rename to docs_src/wsgi/tutorial001.py diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index bacae9bac..000000000 --- a/mkdocs.yml +++ /dev/null @@ -1,150 +0,0 @@ -site_name: FastAPI -site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production -site_url: https://fastapi.tiangolo.com/ - -theme: - name: 'material' - palette: - primary: 'teal' - accent: 'amber' - logo: 'img/icon-white.svg' - favicon: 'img/favicon.png' - -repo_name: tiangolo/fastapi -repo_url: https://github.com/tiangolo/fastapi -edit_uri: '' -google_analytics: - - 'UA-133183413-1' - - 'auto' - -nav: - - FastAPI: 'index.md' - - Features: 'features.md' - - Python types intro: 'python-types.md' - - Tutorial - User Guide: - - Tutorial - User Guide - Intro: 'tutorial/index.md' - - First Steps: 'tutorial/first-steps.md' - - Path Parameters: 'tutorial/path-params.md' - - Query Parameters: 'tutorial/query-params.md' - - Request Body: 'tutorial/body.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 - Fields: 'tutorial/body-fields.md' - - Body - Nested Models: 'tutorial/body-nested-models.md' - - Extra data types: 'tutorial/extra-data-types.md' - - Cookie Parameters: 'tutorial/cookie-params.md' - - Header Parameters: 'tutorial/header-params.md' - - Response Model: 'tutorial/response-model.md' - - Extra Models: 'tutorial/extra-models.md' - - Response Status Code: 'tutorial/response-status-code.md' - - Form Data: 'tutorial/request-forms.md' - - Request Files: 'tutorial/request-files.md' - - Request Forms and Files: 'tutorial/request-forms-and-files.md' - - Handling Errors: 'tutorial/handling-errors.md' - - Path Operation Configuration: 'tutorial/path-operation-configuration.md' - - JSON Compatible Encoder: 'tutorial/encoder.md' - - Body - updates: 'tutorial/body-updates.md' - - Dependencies: - - First Steps: 'tutorial/dependencies/index.md' - - Classes as Dependencies: 'tutorial/dependencies/classes-as-dependencies.md' - - Sub-dependencies: 'tutorial/dependencies/sub-dependencies.md' - - Dependencies in path operation decorators: 'tutorial/dependencies/dependencies-in-path-operation-decorators.md' - - Dependencies with yield: 'tutorial/dependencies/dependencies-with-yield.md' - - Security: - - Security Intro: 'tutorial/security/index.md' - - First Steps: 'tutorial/security/first-steps.md' - - Get Current User: 'tutorial/security/get-current-user.md' - - Simple OAuth2 with Password and Bearer: 'tutorial/security/simple-oauth2.md' - - OAuth2 with Password (and hashing), Bearer with JWT tokens: 'tutorial/security/oauth2-jwt.md' - - Middleware: 'tutorial/middleware.md' - - CORS (Cross-Origin Resource Sharing): 'tutorial/cors.md' - - SQL (Relational) Databases: 'tutorial/sql-databases.md' - - Bigger Applications - Multiple Files: 'tutorial/bigger-applications.md' - - Background Tasks: 'tutorial/background-tasks.md' - - Application Configuration: 'tutorial/application-configuration.md' - - Static Files: 'tutorial/static-files.md' - - Testing: 'tutorial/testing.md' - - Debugging: 'tutorial/debugging.md' - - Advanced User Guide: - - Advanced User Guide - Intro: 'advanced/index.md' - - Path Operation Advanced Configuration: 'advanced/path-operation-advanced-configuration.md' - - Additional Status Codes: 'advanced/additional-status-codes.md' - - Return a Response Directly: 'advanced/response-directly.md' - - Custom Response - HTML, Stream, File, others: 'advanced/custom-response.md' - - Additional Responses in OpenAPI: 'advanced/additional-responses.md' - - Response Cookies: 'advanced/response-cookies.md' - - Response Headers: 'advanced/response-headers.md' - - Response - Change Status Code: 'advanced/response-change-status-code.md' - - Advanced Dependencies: 'advanced/advanced-dependencies.md' - - Advanced Security: - - Advanced Security - Intro: 'advanced/security/index.md' - - OAuth2 scopes: 'advanced/security/oauth2-scopes.md' - - HTTP Basic Auth: 'advanced/security/http-basic-auth.md' - - Using the Request Directly: 'advanced/using-request-directly.md' - - Advanced Middleware: 'advanced/middleware.md' - - SQL (Relational) Databases with Peewee: 'advanced/sql-databases-peewee.md' - - Async SQL (Relational) Databases: 'advanced/async-sql-databases.md' - - NoSQL (Distributed / Big Data) Databases: 'advanced/nosql-databases.md' - - Sub Applications - Behind a Proxy, Mounts: 'advanced/sub-applications-proxy.md' - - Templates: 'advanced/templates.md' - - GraphQL: 'advanced/graphql.md' - - WebSockets: 'advanced/websockets.md' - - 'Events: startup - shutdown': 'advanced/events.md' - - Custom Request and APIRoute class: 'advanced/custom-request-and-route.md' - - Testing WebSockets: 'advanced/testing-websockets.md' - - 'Testing Events: startup - shutdown': 'advanced/testing-events.md' - - Testing Dependencies with Overrides: 'advanced/testing-dependencies.md' - - Extending OpenAPI: 'advanced/extending-openapi.md' - - OpenAPI Callbacks: 'advanced/openapi-callbacks.md' - - Including WSGI - Flask, Django, others: 'advanced/wsgi.md' - - Concurrency and async / await: 'async.md' - - Deployment: 'deployment.md' - - Project Generation - Template: 'project-generation.md' - - Alternatives, Inspiration and Comparisons: 'alternatives.md' - - History, Design and Future: 'history-design-future.md' - - External Links and Articles: 'external-links.md' - - Benchmarks: 'benchmarks.md' - - Help FastAPI - Get Help: 'help-fastapi.md' - - Development - Contributing: 'contributing.md' - - Release Notes: 'release-notes.md' - -markdown_extensions: - - toc: - permalink: true - - markdown.extensions.codehilite: - guess_lang: false - - markdown_include.include: - base_path: docs - - admonition - - codehilite - - extra - - pymdownx.superfences: - custom_fences: - - name: mermaid - class: mermaid - format: !!python/name:pymdownx.superfences.fence_div_format - -extra: - social: - - type: 'github' - link: 'https://github.com/tiangolo/typer' - - type: 'twitter' - link: 'https://twitter.com/tiangolo' - - type: 'linkedin' - link: 'https://www.linkedin.com/in/tiangolo' - - type: 'rss' - link: 'https://dev.to/tiangolo' - - type: 'medium' - link: 'https://medium.com/@tiangolo' - - type: 'globe' - link: 'https://tiangolo.com' - -extra_css: - - 'css/termynal.css' - - 'css/custom.css' - -extra_javascript: - - 'https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js' - - 'js/termynal.js' - - 'js/custom.js' diff --git a/pyproject.toml b/pyproject.toml index 58e53c3ee..eadff42bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,7 +64,10 @@ test = [ doc = [ "mkdocs", "mkdocs-material", - "markdown-include" + "markdown-include", + "typer", + "typer-cli", + "pyyaml" ] dev = [ "pyjwt", diff --git a/scripts/build-docs.sh b/scripts/build-docs.sh index 4f4ae2f74..383ad3f44 100755 --- a/scripts/build-docs.sh +++ b/scripts/build-docs.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -python -m mkdocs build +set -e +set -x -cp ./docs/index.md ./README.md +python ./scripts/docs.py build-all diff --git a/scripts/docs.py b/scripts/docs.py new file mode 100644 index 000000000..490f05264 --- /dev/null +++ b/scripts/docs.py @@ -0,0 +1,340 @@ +import os +import shutil +from http.server import HTTPServer, SimpleHTTPRequestHandler +from pathlib import Path +from typing import Dict, Optional, Tuple + +import mkdocs.commands.build +import mkdocs.commands.serve +import mkdocs.config +import mkdocs.utils +import typer +import yaml + +app = typer.Typer() + +mkdocs_name = "mkdocs.yml" + +missing_translation_snippet = """ +{!../../../docs/missing-translation.md!} +""" + +docs_path = Path("docs") + + +def lang_callback(lang: Optional[str]): + if lang is None: + return + if not lang.isalpha() or len(lang) != 2: + typer.echo("Use a 2 letter language code, like: es") + raise typer.Abort() + lang = lang.lower() + return lang + + +def complete_existing_lang(incomplete: str): + lang_path: Path + for lang_path in docs_path.iterdir(): + if lang_path.is_dir() and lang_path.name.startswith(incomplete): + yield lang_path.name + + +@app.command() +def new_lang(lang: str = typer.Argument(..., callback=lang_callback)): + """ + Generate a new docs translation directory for the language LANG. + + LANG should be a 2-letter language code, like: en, es, de, pt, etc. + """ + new_path: Path = Path("docs") / lang + if new_path.exists(): + typer.echo(f"The language was already created: {lang}") + raise typer.Abort() + new_path.mkdir() + en_docs_path = Path("docs/en") + en_config_path: Path = en_docs_path / mkdocs_name + en_config: dict = mkdocs.utils.yaml_load(en_config_path.read_text()) + fastapi_url_base = "https://fastapi.tiangolo.com/" + new_config = {} + new_config["site_name"] = en_config["site_name"] + new_config["site_description"] = en_config["site_description"] + new_config["site_url"] = en_config["site_url"] + f"{lang}/" + new_config["theme"] = en_config["theme"] + new_config["theme"]["logo"] = fastapi_url_base + en_config["theme"]["logo"] + new_config["theme"]["favicon"] = fastapi_url_base + en_config["theme"]["favicon"] + new_config["theme"]["language"] = lang + new_config["repo_name"] = en_config["repo_name"] + new_config["repo_url"] = en_config["repo_url"] + new_config["edit_uri"] = en_config["edit_uri"] + new_config["google_analytics"] = en_config["google_analytics"] + new_config["nav"] = en_config["nav"][:2] + + new_config["markdown_extensions"] = en_config["markdown_extensions"] + new_config["extra"] = en_config["extra"] + + extra_css = [] + css: str + for css in en_config["extra_css"]: + if css.startswith("http"): + extra_css.append(css) + else: + extra_css.append(fastapi_url_base + css) + new_config["extra_css"] = extra_css + + extra_js = [] + js: str + for js in en_config["extra_javascript"]: + if js.startswith("http"): + extra_js.append(js) + else: + extra_js.append(fastapi_url_base + js) + new_config["extra_javascript"] = extra_js + new_config_path: Path = Path(new_path) / mkdocs_name + new_config_path.write_text(yaml.dump(new_config, sort_keys=False, width=200)) + new_config_docs_path: Path = new_path / "docs" + new_config_docs_path.mkdir() + en_index_path: Path = en_docs_path / "docs" / "index.md" + new_index_path: Path = new_config_docs_path / "index.md" + en_index_content = en_index_path.read_text() + new_index_content = f"{missing_translation_snippet}\n\n{en_index_content}" + new_index_path.write_text(new_index_content) + typer.secho(f"Successfully initialized: {new_path}", color=typer.colors.GREEN) + update_languages(lang=None) + + +@app.command() +def build_lang( + lang: str = typer.Argument( + ..., callback=lang_callback, autocompletion=complete_existing_lang + ) +): + """ + Build the docs for a language, filling missing pages with translation notifications. + """ + lang_path: Path = Path("docs") / lang + if not lang_path.is_dir(): + typer.echo(f"The language translation doesn't seem to exist yet: {lang}") + raise typer.Abort() + typer.echo(f"Building docs for: {lang}") + build_dir_path = Path("docs_build") + build_dir_path.mkdir(exist_ok=True) + build_lang_path = build_dir_path / lang + en_lang_path = Path("docs/en") + site_path = Path("site").absolute() + if lang == "en": + dist_path = site_path + else: + dist_path: Path = site_path / lang + shutil.rmtree(build_lang_path, ignore_errors=True) + shutil.copytree(lang_path, build_lang_path) + en_config_path: Path = en_lang_path / mkdocs_name + en_config: dict = mkdocs.utils.yaml_load(en_config_path.read_text()) + nav = en_config["nav"] + lang_config_path: Path = lang_path / mkdocs_name + lang_config: dict = mkdocs.utils.yaml_load(lang_config_path.read_text()) + lang_nav = lang_config["nav"] + # Exclude first 2 entries FastAPI and Languages, for custom handling + use_nav = nav[2:] + lang_use_nav = lang_nav[2:] + file_to_nav = get_file_to_nav_map(use_nav) + sections = get_sections(use_nav) + lang_file_to_nav = get_file_to_nav_map(lang_use_nav) + use_lang_file_to_nav = get_file_to_nav_map(lang_use_nav) + for file in file_to_nav: + file_path = Path(file) + lang_file_path: Path = build_lang_path / "docs" / file_path + en_file_path: Path = en_lang_path / "docs" / file_path + lang_file_path.parent.mkdir(parents=True, exist_ok=True) + if not lang_file_path.is_file(): + en_text = en_file_path.read_text() + lang_text = get_text_with_translate_missing(en_text) + lang_file_path.write_text(lang_text) + file_key = file_to_nav[file] + use_lang_file_to_nav[file] = file_key + if file_key: + composite_key = () + new_key = () + for key_part in file_key: + composite_key += (key_part,) + key_first_file = sections[composite_key] + if key_first_file in lang_file_to_nav: + new_key = lang_file_to_nav[key_first_file] + else: + new_key += (key_part,) + use_lang_file_to_nav[file] = new_key + key_to_section = {(): []} + for file, file_key in use_lang_file_to_nav.items(): + section = get_key_section(key_to_section=key_to_section, key=file_key) + section.append(file) + new_nav = key_to_section[()] + export_lang_nav = [lang_nav[0], nav[1]] + new_nav + lang_config["nav"] = export_lang_nav + build_lang_config_path: Path = build_lang_path / mkdocs_name + build_lang_config_path.write_text( + yaml.dump(lang_config, sort_keys=False, width=200) + ) + current_dir = os.getcwd() + os.chdir(build_lang_path) + mkdocs.commands.build.build(mkdocs.config.load_config(site_dir=str(dist_path))) + os.chdir(current_dir) + typer.secho(f"Successfully built docs for: {lang}", color=typer.colors.GREEN) + + +@app.command() +def build_all(): + """ + Build mkdocs site for en, and then build each language inside, end result is located + at directory ./site/ with each language inside. + """ + site_path = Path("site").absolute() + update_languages(lang=None) + en_build_path: Path = docs_path / "en" + current_dir = os.getcwd() + os.chdir(en_build_path) + typer.echo(f"Building docs for: en") + mkdocs.commands.build.build(mkdocs.config.load_config(site_dir=str(site_path))) + os.chdir(current_dir) + for lang in docs_path.iterdir(): + if lang == en_build_path or not lang.is_dir(): + continue + build_lang(lang.name) + typer.echo("Copying en index.md to README.md") + en_index = en_build_path / "docs" / "index.md" + shutil.copyfile(en_index, "README.md") + + +@app.command() +def update_languages( + lang: str = typer.Argument( + None, callback=lang_callback, autocompletion=complete_existing_lang + ) +): + """ + Update the mkdocs.yml file Languages section including all the available languages. + + The LANG argument is a 2-letter language code. If it's not provided, update all the + mkdocs.yml files (for all the languages). + """ + if lang is None: + for lang_path in docs_path.iterdir(): + if lang_path.is_dir(): + typer.echo(f"Updating {lang_path.name}") + update_config(lang_path.name) + else: + typer.echo(f"Updating {lang}") + update_config(lang) + + +@app.command() +def serve(): + """ + A quick server to preview a built site with translations. + + For development, prefer the command live (or just mkdocs serve). + + This is here only to preview a site with translations already built. + + Make sure you run the build-all command first. + """ + typer.echo( + "Warning: this is a very simple server." + + "For development, use mkdocs serve instead." + ) + typer.echo("This is here only to preview a site with translations already built.") + typer.echo("Make sure you run the build-all command first.") + os.chdir("site") + server_address = ("", 8008) + server = HTTPServer(server_address, SimpleHTTPRequestHandler) + typer.echo(f"Serving at: http://0.0.0.0:8008") + server.serve_forever() + + +@app.command() +def live( + lang: str = typer.Argument( + None, callback=lang_callback, autocompletion=complete_existing_lang + ) +): + """ + Serve with livereload a docs site for a specific language. + + This only shows the actual translated files, not the placeholders created with + build-all. + + Takes an optional LANG argument with the name of the language to serve, by default + en. + """ + if lang is None: + lang = "en" + lang_path: Path = docs_path / lang + os.chdir(lang_path) + mkdocs.commands.serve.serve(dev_addr="0.0.0.0:8008") + + +def update_config(lang: str): + lang_path: Path = docs_path / lang + config_path = lang_path / mkdocs_name + config: dict = mkdocs.utils.yaml_load(config_path.read_text()) + languages = [{"en": "/"}] + for lang in docs_path.iterdir(): + if lang.name == "en" or not lang.is_dir(): + continue + name = lang.name + languages.append({name: f"/{name}/"}) + config["nav"][1] = {"Languages": languages} + config_path.write_text(yaml.dump(config, sort_keys=False, width=200)) + + +def get_key_section( + *, key_to_section: Dict[Tuple[str, ...], list], key: Tuple[str, ...] +) -> list: + if key in key_to_section: + return key_to_section[key] + super_key = key[:-1] + title = key[-1] + super_section = get_key_section(key_to_section=key_to_section, key=super_key) + new_section = [] + super_section.append({title: new_section}) + key_to_section[key] = new_section + return new_section + + +def get_text_with_translate_missing(text: str) -> str: + lines = text.splitlines() + lines.insert(1, missing_translation_snippet) + new_text = "\n".join(lines) + return new_text + + +def get_file_to_nav_map(nav: list) -> Dict[str, Tuple[str, ...]]: + file_to_nav = {} + for item in nav: + if type(item) is str: + file_to_nav[item] = tuple() + elif type(item) is dict: + item_key = list(item.keys())[0] + sub_nav = item[item_key] + sub_file_to_nav = get_file_to_nav_map(sub_nav) + for k, v in sub_file_to_nav.items(): + file_to_nav[k] = (item_key,) + v + return file_to_nav + + +def get_sections(nav: list) -> Dict[Tuple[str, ...], str]: + sections = {} + for item in nav: + if type(item) is str: + continue + elif type(item) is dict: + item_key = list(item.keys())[0] + sub_nav = item[item_key] + sections[(item_key,)] = sub_nav[0] + sub_sections = get_sections(sub_nav) + for k, v in sub_sections.items(): + new_key = (item_key,) + k + sections[new_key] = v + return sections + + +if __name__ == "__main__": + app() diff --git a/scripts/format-imports.sh b/scripts/format-imports.sh index cfa66bbd4..d2c0b7a58 100755 --- a/scripts/format-imports.sh +++ b/scripts/format-imports.sh @@ -2,5 +2,5 @@ set -x # Sort imports one per line, so autoflake can remove unused imports -isort --recursive --force-single-line-imports --thirdparty fastapi --apply fastapi tests docs/src +isort --recursive --force-single-line-imports --thirdparty fastapi --apply fastapi tests docs_src scripts sh ./scripts/format.sh diff --git a/scripts/format.sh b/scripts/format.sh index c11eaf749..bbcb04354 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -1,6 +1,6 @@ #!/bin/sh -e set -x -autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place docs/src/ fastapi tests --exclude=__init__.py -black fastapi tests docs/src -isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --thirdparty fastapi --apply fastapi tests docs/src +autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place docs_src fastapi tests scripts --exclude=__init__.py +black fastapi tests docs_src scripts +isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --thirdparty fastapi --apply fastapi tests docs_src scripts diff --git a/scripts/test.sh b/scripts/test.sh index d1a4cf630..468b2c667 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -9,6 +9,6 @@ if [ -f ./test.db ]; then fi bash ./scripts/lint.sh # Check README.md is up to date -diff --brief docs/index.md README.md -export PYTHONPATH=./docs/src -pytest --cov=fastapi --cov=tests --cov=docs/src --cov-report=term-missing ${@} +diff --brief docs/en/docs/index.md README.md +export PYTHONPATH=./docs_src +pytest --cov=fastapi --cov=tests --cov=docs/src --cov-report=term-missing tests ${@} diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial002.py b/tests/test_tutorial/test_additional_responses/test_tutorial002.py index 09a06d957..998070b3d 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial002.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial002.py @@ -107,7 +107,7 @@ def test_path_operation(): def test_path_operation_img(): - shutil.copy("./docs/img/favicon.png", "./image.png") + shutil.copy("./docs/en/docs/img/favicon.png", "./image.png") response = client.get("/items/foo?img=1") assert response.status_code == 200 assert response.headers["Content-Type"] == "image/png" diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial004.py b/tests/test_tutorial/test_additional_responses/test_tutorial004.py index d1285c8ea..11f1227e4 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial004.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial004.py @@ -110,7 +110,7 @@ def test_path_operation(): def test_path_operation_img(): - shutil.copy("./docs/img/favicon.png", "./image.png") + shutil.copy("./docs/en/docs/img/favicon.png", "./image.png") response = client.get("/items/foo?img=1") assert response.status_code == 200 assert response.headers["Content-Type"] == "image/png" diff --git a/tests/test_tutorial/test_templates/test_tutorial001.py b/tests/test_tutorial/test_templates/test_tutorial001.py index 48d6456b4..95c5b1ed3 100644 --- a/tests/test_tutorial/test_templates/test_tutorial001.py +++ b/tests/test_tutorial/test_templates/test_tutorial001.py @@ -4,8 +4,8 @@ from fastapi.testclient import TestClient def test_main(): - shutil.copytree("./docs/src/templates/templates/", "./templates") - shutil.copytree("./docs/src/templates/static/", "./static") + shutil.copytree("./docs_src/templates/templates/", "./templates") + shutil.copytree("./docs_src/templates/static/", "./static") from templates.tutorial001 import app client = TestClient(app)