]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
:sparkles: Add support for docs translations (#1168)
authorSebastián Ramírez <tiangolo@gmail.com>
Thu, 26 Mar 2020 19:09:53 +0000 (20:09 +0100)
committerGitHub <noreply@github.com>
Thu, 26 Mar 2020 19:09:53 +0000 (20:09 +0100)
* :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

391 files changed:
.github/workflows/deploy-docs.yml
.gitignore
docs/contributing.md [deleted file]
docs/en/docs/advanced/additional-responses.md [moved from docs/advanced/additional-responses.md with 97% similarity]
docs/en/docs/advanced/additional-status-codes.md [moved from docs/advanced/additional-status-codes.md with 95% similarity]
docs/en/docs/advanced/advanced-dependencies.md [moved from docs/advanced/advanced-dependencies.md with 91% similarity]
docs/en/docs/advanced/async-sql-databases.md [moved from docs/advanced/async-sql-databases.md with 90% similarity]
docs/en/docs/advanced/custom-request-and-route.md [moved from docs/advanced/custom-request-and-route.md with 91% similarity]
docs/en/docs/advanced/custom-response.md [moved from docs/advanced/custom-response.md with 92% similarity]
docs/en/docs/advanced/events.md [moved from docs/advanced/events.md with 93% similarity]
docs/en/docs/advanced/extending-openapi.md [moved from docs/advanced/extending-openapi.md with 94% similarity]
docs/en/docs/advanced/graphql.md [moved from docs/advanced/graphql.md with 93% similarity]
docs/en/docs/advanced/index.md [moved from docs/advanced/index.md with 95% similarity]
docs/en/docs/advanced/middleware.md [moved from docs/advanced/middleware.md with 95% similarity]
docs/en/docs/advanced/nosql-databases.md [moved from docs/advanced/nosql-databases.md with 91% similarity]
docs/en/docs/advanced/openapi-callbacks.md [moved from docs/advanced/openapi-callbacks.md with 97% similarity]
docs/en/docs/advanced/path-operation-advanced-configuration.md [moved from docs/advanced/path-operation-advanced-configuration.md with 82% similarity]
docs/en/docs/advanced/response-change-status-code.md [moved from docs/advanced/response-change-status-code.md with 93% similarity]
docs/en/docs/advanced/response-cookies.md [moved from docs/advanced/response-cookies.md with 94% similarity]
docs/en/docs/advanced/response-directly.md [moved from docs/advanced/response-directly.md with 95% similarity]
docs/en/docs/advanced/response-headers.md [moved from docs/advanced/response-headers.md with 94% similarity]
docs/en/docs/advanced/security/http-basic-auth.md [moved from docs/advanced/security/http-basic-auth.md with 96% similarity]
docs/en/docs/advanced/security/index.md [moved from docs/advanced/security/index.md with 95% similarity]
docs/en/docs/advanced/security/oauth2-scopes.md [moved from docs/advanced/security/oauth2-scopes.md with 97% similarity]
docs/en/docs/advanced/sql-databases-peewee.md [moved from docs/advanced/sql-databases-peewee.md with 95% similarity]
docs/en/docs/advanced/sub-applications-proxy.md [moved from docs/advanced/sub-applications-proxy.md with 94% similarity]
docs/en/docs/advanced/templates.md [moved from docs/advanced/templates.md with 91% similarity]
docs/en/docs/advanced/testing-dependencies.md [moved from docs/advanced/testing-dependencies.md with 96% similarity]
docs/en/docs/advanced/testing-events.md [moved from docs/advanced/testing-events.md with 67% similarity]
docs/en/docs/advanced/testing-websockets.md [moved from docs/advanced/testing-websockets.md with 72% similarity]
docs/en/docs/advanced/using-request-directly.md [moved from docs/advanced/using-request-directly.md with 96% similarity]
docs/en/docs/advanced/websockets.md [moved from docs/advanced/websockets.md with 94% similarity]
docs/en/docs/advanced/wsgi.md [moved from docs/advanced/wsgi.md with 92% similarity]
docs/en/docs/alternatives.md [moved from docs/alternatives.md with 99% similarity]
docs/en/docs/async.md [moved from docs/async.md with 99% similarity]
docs/en/docs/benchmarks.md [moved from docs/benchmarks.md with 99% similarity]
docs/en/docs/contributing.md [new file with mode: 0644]
docs/en/docs/css/custom.css [moved from docs/css/custom.css with 100% similarity]
docs/en/docs/css/termynal.css [moved from docs/css/termynal.css with 100% similarity]
docs/en/docs/deployment.md [moved from docs/deployment.md with 99% similarity]
docs/en/docs/external-links.md [moved from docs/external-links.md with 99% similarity]
docs/en/docs/features.md [moved from docs/features.md with 96% similarity]
docs/en/docs/help-fastapi.md [moved from docs/help-fastapi.md with 99% similarity]
docs/en/docs/history-design-future.md [moved from docs/history-design-future.md with 99% similarity]
docs/en/docs/img/favicon.png [moved from docs/img/favicon.png with 100% similarity]
docs/en/docs/img/github-social-preview.png [moved from docs/img/github-social-preview.png with 100% similarity]
docs/en/docs/img/github-social-preview.svg [moved from docs/img/github-social-preview.svg with 100% similarity]
docs/en/docs/img/icon-transparent-bg.png [moved from docs/img/icon-transparent-bg.png with 100% similarity]
docs/en/docs/img/icon-white-bg.png [moved from docs/img/icon-white-bg.png with 100% similarity]
docs/en/docs/img/icon-white.svg [moved from docs/img/icon-white.svg with 100% similarity]
docs/en/docs/img/index/index-01-swagger-ui-simple.png [moved from docs/img/index/index-01-swagger-ui-simple.png with 100% similarity]
docs/en/docs/img/index/index-02-redoc-simple.png [moved from docs/img/index/index-02-redoc-simple.png with 100% similarity]
docs/en/docs/img/index/index-03-swagger-02.png [moved from docs/img/index/index-03-swagger-02.png with 100% similarity]
docs/en/docs/img/index/index-04-swagger-03.png [moved from docs/img/index/index-04-swagger-03.png with 100% similarity]
docs/en/docs/img/index/index-05-swagger-04.png [moved from docs/img/index/index-05-swagger-04.png with 100% similarity]
docs/en/docs/img/index/index-06-redoc-02.png [moved from docs/img/index/index-06-redoc-02.png with 100% similarity]
docs/en/docs/img/logo-margin/logo-teal-vector.svg [moved from docs/img/logo-margin/logo-teal-vector.svg with 100% similarity]
docs/en/docs/img/logo-margin/logo-teal.png [moved from docs/img/logo-margin/logo-teal.png with 100% similarity]
docs/en/docs/img/logo-margin/logo-teal.svg [moved from docs/img/logo-margin/logo-teal.svg with 100% similarity]
docs/en/docs/img/logo-margin/logo-white-bg.png [moved from docs/img/logo-margin/logo-white-bg.png with 100% similarity]
docs/en/docs/img/logo-teal-vector.svg [moved from docs/img/logo-teal-vector.svg with 100% similarity]
docs/en/docs/img/logo-teal.svg [moved from docs/img/logo-teal.svg with 100% similarity]
docs/en/docs/img/pycharm-completion.png [moved from docs/img/pycharm-completion.png with 100% similarity]
docs/en/docs/img/python-types/image01.png [moved from docs/img/python-types/image01.png with 100% similarity]
docs/en/docs/img/python-types/image02.png [moved from docs/img/python-types/image02.png with 100% similarity]
docs/en/docs/img/python-types/image03.png [moved from docs/img/python-types/image03.png with 100% similarity]
docs/en/docs/img/python-types/image04.png [moved from docs/img/python-types/image04.png with 100% similarity]
docs/en/docs/img/python-types/image05.png [moved from docs/img/python-types/image05.png with 100% similarity]
docs/en/docs/img/python-types/image06.png [moved from docs/img/python-types/image06.png with 100% similarity]
docs/en/docs/img/tutorial/additional-responses/image01.png [moved from docs/img/tutorial/additional-responses/image01.png with 100% similarity]
docs/en/docs/img/tutorial/application-configuration/image01.png [moved from docs/img/tutorial/application-configuration/image01.png with 100% similarity]
docs/en/docs/img/tutorial/async-sql-databases/image01.png [moved from docs/img/tutorial/async-sql-databases/image01.png with 100% similarity]
docs/en/docs/img/tutorial/bigger-applications/image01.png [moved from docs/img/tutorial/bigger-applications/image01.png with 100% similarity]
docs/en/docs/img/tutorial/body-fields/image01.png [moved from docs/img/tutorial/body-fields/image01.png with 100% similarity]
docs/en/docs/img/tutorial/body-nested-models/image01.png [moved from docs/img/tutorial/body-nested-models/image01.png with 100% similarity]
docs/en/docs/img/tutorial/body/image01.png [moved from docs/img/tutorial/body/image01.png with 100% similarity]
docs/en/docs/img/tutorial/body/image02.png [moved from docs/img/tutorial/body/image02.png with 100% similarity]
docs/en/docs/img/tutorial/body/image03.png [moved from docs/img/tutorial/body/image03.png with 100% similarity]
docs/en/docs/img/tutorial/body/image04.png [moved from docs/img/tutorial/body/image04.png with 100% similarity]
docs/en/docs/img/tutorial/body/image05.png [moved from docs/img/tutorial/body/image05.png with 100% similarity]
docs/en/docs/img/tutorial/custom-response/image01.png [moved from docs/img/tutorial/custom-response/image01.png with 100% similarity]
docs/en/docs/img/tutorial/debugging/image01.png [moved from docs/img/tutorial/debugging/image01.png with 100% similarity]
docs/en/docs/img/tutorial/dependencies/image01.png [moved from docs/img/tutorial/dependencies/image01.png with 100% similarity]
docs/en/docs/img/tutorial/dependencies/image02.png [moved from docs/img/tutorial/dependencies/image02.png with 100% similarity]
docs/en/docs/img/tutorial/extending-openapi/image01.png [moved from docs/img/tutorial/extending-openapi/image01.png with 100% similarity]
docs/en/docs/img/tutorial/graphql/image01.png [moved from docs/img/tutorial/graphql/image01.png with 100% similarity]
docs/en/docs/img/tutorial/openapi-callbacks/image01.png [moved from docs/img/tutorial/openapi-callbacks/image01.png with 100% similarity]
docs/en/docs/img/tutorial/path-operation-configuration/image01.png [moved from docs/img/tutorial/path-operation-configuration/image01.png with 100% similarity]
docs/en/docs/img/tutorial/path-operation-configuration/image02.png [moved from docs/img/tutorial/path-operation-configuration/image02.png with 100% similarity]
docs/en/docs/img/tutorial/path-operation-configuration/image03.png [moved from docs/img/tutorial/path-operation-configuration/image03.png with 100% similarity]
docs/en/docs/img/tutorial/path-operation-configuration/image04.png [moved from docs/img/tutorial/path-operation-configuration/image04.png with 100% similarity]
docs/en/docs/img/tutorial/path-operation-configuration/image05.png [moved from docs/img/tutorial/path-operation-configuration/image05.png with 100% similarity]
docs/en/docs/img/tutorial/path-params/image01.png [moved from docs/img/tutorial/path-params/image01.png with 100% similarity]
docs/en/docs/img/tutorial/path-params/image02.png [moved from docs/img/tutorial/path-params/image02.png with 100% similarity]
docs/en/docs/img/tutorial/path-params/image03.png [moved from docs/img/tutorial/path-params/image03.png with 100% similarity]
docs/en/docs/img/tutorial/query-params-str-validations/image01.png [moved from docs/img/tutorial/query-params-str-validations/image01.png with 100% similarity]
docs/en/docs/img/tutorial/query-params-str-validations/image02.png [moved from docs/img/tutorial/query-params-str-validations/image02.png with 100% similarity]
docs/en/docs/img/tutorial/response-model/image01.png [moved from docs/img/tutorial/response-model/image01.png with 100% similarity]
docs/en/docs/img/tutorial/response-model/image02.png [moved from docs/img/tutorial/response-model/image02.png with 100% similarity]
docs/en/docs/img/tutorial/response-status-code/image01.png [moved from docs/img/tutorial/response-status-code/image01.png with 100% similarity]
docs/en/docs/img/tutorial/response-status-code/image02.png [moved from docs/img/tutorial/response-status-code/image02.png with 100% similarity]
docs/en/docs/img/tutorial/security/image01.png [moved from docs/img/tutorial/security/image01.png with 100% similarity]
docs/en/docs/img/tutorial/security/image02.png [moved from docs/img/tutorial/security/image02.png with 100% similarity]
docs/en/docs/img/tutorial/security/image03.png [moved from docs/img/tutorial/security/image03.png with 100% similarity]
docs/en/docs/img/tutorial/security/image04.png [moved from docs/img/tutorial/security/image04.png with 100% similarity]
docs/en/docs/img/tutorial/security/image05.png [moved from docs/img/tutorial/security/image05.png with 100% similarity]
docs/en/docs/img/tutorial/security/image06.png [moved from docs/img/tutorial/security/image06.png with 100% similarity]
docs/en/docs/img/tutorial/security/image07.png [moved from docs/img/tutorial/security/image07.png with 100% similarity]
docs/en/docs/img/tutorial/security/image08.png [moved from docs/img/tutorial/security/image08.png with 100% similarity]
docs/en/docs/img/tutorial/security/image09.png [moved from docs/img/tutorial/security/image09.png with 100% similarity]
docs/en/docs/img/tutorial/security/image10.png [moved from docs/img/tutorial/security/image10.png with 100% similarity]
docs/en/docs/img/tutorial/security/image11.png [moved from docs/img/tutorial/security/image11.png with 100% similarity]
docs/en/docs/img/tutorial/security/image12.png [moved from docs/img/tutorial/security/image12.png with 100% similarity]
docs/en/docs/img/tutorial/sql-databases/image01.png [moved from docs/img/tutorial/sql-databases/image01.png with 100% similarity]
docs/en/docs/img/tutorial/sql-databases/image02.png [moved from docs/img/tutorial/sql-databases/image02.png with 100% similarity]
docs/en/docs/img/tutorial/sub-applications/image01.png [moved from docs/img/tutorial/sub-applications/image01.png with 100% similarity]
docs/en/docs/img/tutorial/sub-applications/image02.png [moved from docs/img/tutorial/sub-applications/image02.png with 100% similarity]
docs/en/docs/img/tutorial/websockets/image01.png [moved from docs/img/tutorial/websockets/image01.png with 100% similarity]
docs/en/docs/img/tutorial/websockets/image02.png [moved from docs/img/tutorial/websockets/image02.png with 100% similarity]
docs/en/docs/img/tutorial/websockets/image03.png [moved from docs/img/tutorial/websockets/image03.png with 100% similarity]
docs/en/docs/img/tutorial/websockets/image04.png [moved from docs/img/tutorial/websockets/image04.png with 100% similarity]
docs/en/docs/img/vscode-completion.png [moved from docs/img/vscode-completion.png with 100% similarity]
docs/en/docs/index.md [moved from docs/index.md with 100% similarity]
docs/en/docs/js/custom.js [moved from docs/js/custom.js with 100% similarity]
docs/en/docs/js/termynal.js [moved from docs/js/termynal.js with 100% similarity]
docs/en/docs/project-generation.md [moved from docs/project-generation.md with 99% similarity]
docs/en/docs/python-types.md [moved from docs/python-types.md with 92% similarity]
docs/en/docs/release-notes.md [moved from docs/release-notes.md with 99% similarity]
docs/en/docs/tutorial/application-configuration.md [moved from docs/tutorial/application-configuration.md with 87% similarity]
docs/en/docs/tutorial/background-tasks.md [moved from docs/tutorial/background-tasks.md with 95% similarity]
docs/en/docs/tutorial/bigger-applications.md [moved from docs/tutorial/bigger-applications.md with 95% similarity]
docs/en/docs/tutorial/body-fields.md [moved from docs/tutorial/body-fields.md with 93% similarity]
docs/en/docs/tutorial/body-multiple-params.md [moved from docs/tutorial/body-multiple-params.md with 93% similarity]
docs/en/docs/tutorial/body-nested-models.md [moved from docs/tutorial/body-nested-models.md with 90% similarity]
docs/en/docs/tutorial/body-updates.md [moved from docs/tutorial/body-updates.md with 94% similarity]
docs/en/docs/tutorial/body.md [moved from docs/tutorial/body.md with 95% similarity]
docs/en/docs/tutorial/cookie-params.md [moved from docs/tutorial/cookie-params.md with 88% similarity]
docs/en/docs/tutorial/cors.md [moved from docs/tutorial/cors.md with 98% similarity]
docs/en/docs/tutorial/debugging.md [moved from docs/tutorial/debugging.md with 97% similarity]
docs/en/docs/tutorial/dependencies/classes-as-dependencies.md [moved from docs/tutorial/dependencies/classes-as-dependencies.md with 93% similarity]
docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md [moved from docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md with 89% similarity]
docs/en/docs/tutorial/dependencies/dependencies-with-yield.md [moved from docs/tutorial/dependencies/dependencies-with-yield.md with 96% similarity]
docs/en/docs/tutorial/dependencies/index.md [moved from docs/tutorial/dependencies/index.md with 97% similarity]
docs/en/docs/tutorial/dependencies/sub-dependencies.md [moved from docs/tutorial/dependencies/sub-dependencies.md with 95% similarity]
docs/en/docs/tutorial/encoder.md [moved from docs/tutorial/encoder.md with 95% similarity]
docs/en/docs/tutorial/extra-data-types.md [moved from docs/tutorial/extra-data-types.md with 94% similarity]
docs/en/docs/tutorial/extra-models.md [moved from docs/tutorial/extra-models.md with 95% similarity]
docs/en/docs/tutorial/first-steps.md [moved from docs/tutorial/first-steps.md with 95% similarity]
docs/en/docs/tutorial/handling-errors.md [moved from docs/tutorial/handling-errors.md with 95% similarity]
docs/en/docs/tutorial/header-params.md [moved from docs/tutorial/header-params.md with 92% similarity]
docs/en/docs/tutorial/index.md [moved from docs/tutorial/index.md with 98% similarity]
docs/en/docs/tutorial/middleware.md [moved from docs/tutorial/middleware.md with 96% similarity]
docs/en/docs/tutorial/path-operation-configuration.md [moved from docs/tutorial/path-operation-configuration.md with 88% similarity]
docs/en/docs/tutorial/path-params-numeric-validations.md [moved from docs/tutorial/path-params-numeric-validations.md with 89% similarity]
docs/en/docs/tutorial/path-params.md [moved from docs/tutorial/path-params.md with 94% similarity]
docs/en/docs/tutorial/query-params-str-validations.md [moved from docs/tutorial/query-params-str-validations.md with 87% similarity]
docs/en/docs/tutorial/query-params.md [moved from docs/tutorial/query-params.md with 92% similarity]
docs/en/docs/tutorial/request-files.md [moved from docs/tutorial/request-files.md with 96% similarity]
docs/en/docs/tutorial/request-forms-and-files.md [moved from docs/tutorial/request-forms-and-files.md with 88% similarity]
docs/en/docs/tutorial/request-forms.md [moved from docs/tutorial/request-forms.md with 95% similarity]
docs/en/docs/tutorial/response-model.md [moved from docs/tutorial/response-model.md with 92% similarity]
docs/en/docs/tutorial/response-status-code.md [moved from docs/tutorial/response-status-code.md with 94% similarity]
docs/en/docs/tutorial/security/first-steps.md [moved from docs/tutorial/security/first-steps.md with 97% similarity]
docs/en/docs/tutorial/security/get-current-user.md [moved from docs/tutorial/security/get-current-user.md with 92% similarity]
docs/en/docs/tutorial/security/index.md [moved from docs/tutorial/security/index.md with 99% similarity]
docs/en/docs/tutorial/security/oauth2-jwt.md [moved from docs/tutorial/security/oauth2-jwt.md with 97% similarity]
docs/en/docs/tutorial/security/simple-oauth2.md [moved from docs/tutorial/security/simple-oauth2.md with 97% similarity]
docs/en/docs/tutorial/sql-databases.md [moved from docs/tutorial/sql-databases.md with 95% similarity]
docs/en/docs/tutorial/static-files.md [moved from docs/tutorial/static-files.md with 96% similarity]
docs/en/docs/tutorial/testing.md [moved from docs/tutorial/testing.md with 94% similarity]
docs/en/mkdocs.yml [new file with mode: 0644]
docs/es/docs/index.md [new file with mode: 0644]
docs/es/mkdocs.yml [new file with mode: 0644]
docs/missing-translation.md [new file with mode: 0644]
docs_src/additional_responses/tutorial001.py [moved from docs/src/additional_responses/tutorial001.py with 100% similarity]
docs_src/additional_responses/tutorial002.py [moved from docs/src/additional_responses/tutorial002.py with 100% similarity]
docs_src/additional_responses/tutorial003.py [moved from docs/src/additional_responses/tutorial003.py with 100% similarity]
docs_src/additional_responses/tutorial004.py [moved from docs/src/additional_responses/tutorial004.py with 100% similarity]
docs_src/additional_status_codes/tutorial001.py [moved from docs/src/additional_status_codes/tutorial001.py with 100% similarity]
docs_src/advanced_middleware/tutorial001.py [moved from docs/src/advanced_middleware/tutorial001.py with 100% similarity]
docs_src/advanced_middleware/tutorial002.py [moved from docs/src/advanced_middleware/tutorial002.py with 100% similarity]
docs_src/advanced_middleware/tutorial003.py [moved from docs/src/advanced_middleware/tutorial003.py with 100% similarity]
docs_src/app_testing/__init__.py [moved from docs/src/app_testing/__init__.py with 100% similarity]
docs_src/app_testing/main.py [moved from docs/src/app_testing/main.py with 100% similarity]
docs_src/app_testing/main_b.py [moved from docs/src/app_testing/main_b.py with 100% similarity]
docs_src/app_testing/test_main.py [moved from docs/src/app_testing/test_main.py with 100% similarity]
docs_src/app_testing/test_main_b.py [moved from docs/src/app_testing/test_main_b.py with 100% similarity]
docs_src/app_testing/tutorial001.py [moved from docs/src/app_testing/tutorial001.py with 100% similarity]
docs_src/app_testing/tutorial002.py [moved from docs/src/app_testing/tutorial002.py with 100% similarity]
docs_src/app_testing/tutorial003.py [moved from docs/src/app_testing/tutorial003.py with 100% similarity]
docs_src/application_configuration/tutorial001.py [moved from docs/src/application_configuration/tutorial001.py with 100% similarity]
docs_src/application_configuration/tutorial002.py [moved from docs/src/application_configuration/tutorial002.py with 100% similarity]
docs_src/application_configuration/tutorial003.py [moved from docs/src/application_configuration/tutorial003.py with 100% similarity]
docs_src/async_sql_databases/tutorial001.py [moved from docs/src/async_sql_databases/tutorial001.py with 100% similarity]
docs_src/background_tasks/tutorial001.py [moved from docs/src/background_tasks/tutorial001.py with 100% similarity]
docs_src/background_tasks/tutorial002.py [moved from docs/src/background_tasks/tutorial002.py with 100% similarity]
docs_src/bigger_applications/__init__.py [moved from docs/src/bigger_applications/__init__.py with 100% similarity]
docs_src/bigger_applications/app/__init__.py [moved from docs/src/bigger_applications/app/__init__.py with 100% similarity]
docs_src/bigger_applications/app/main.py [moved from docs/src/bigger_applications/app/main.py with 100% similarity]
docs_src/bigger_applications/app/routers/__init__.py [moved from docs/src/bigger_applications/app/routers/__init__.py with 100% similarity]
docs_src/bigger_applications/app/routers/items.py [moved from docs/src/bigger_applications/app/routers/items.py with 100% similarity]
docs_src/bigger_applications/app/routers/users.py [moved from docs/src/bigger_applications/app/routers/users.py with 100% similarity]
docs_src/body/tutorial001.py [moved from docs/src/body/tutorial001.py with 100% similarity]
docs_src/body/tutorial002.py [moved from docs/src/body/tutorial002.py with 100% similarity]
docs_src/body/tutorial003.py [moved from docs/src/body/tutorial003.py with 100% similarity]
docs_src/body/tutorial004.py [moved from docs/src/body/tutorial004.py with 100% similarity]
docs_src/body_fields/tutorial001.py [moved from docs/src/body_fields/tutorial001.py with 100% similarity]
docs_src/body_fields/tutorial002.py [moved from docs/src/body_fields/tutorial002.py with 100% similarity]
docs_src/body_multiple_params/tutorial001.py [moved from docs/src/body_multiple_params/tutorial001.py with 100% similarity]
docs_src/body_multiple_params/tutorial002.py [moved from docs/src/body_multiple_params/tutorial002.py with 100% similarity]
docs_src/body_multiple_params/tutorial003.py [moved from docs/src/body_multiple_params/tutorial003.py with 100% similarity]
docs_src/body_multiple_params/tutorial004.py [moved from docs/src/body_multiple_params/tutorial004.py with 100% similarity]
docs_src/body_multiple_params/tutorial005.py [moved from docs/src/body_multiple_params/tutorial005.py with 100% similarity]
docs_src/body_nested_models/tutorial001.py [moved from docs/src/body_nested_models/tutorial001.py with 100% similarity]
docs_src/body_nested_models/tutorial002.py [moved from docs/src/body_nested_models/tutorial002.py with 100% similarity]
docs_src/body_nested_models/tutorial003.py [moved from docs/src/body_nested_models/tutorial003.py with 100% similarity]
docs_src/body_nested_models/tutorial004.py [moved from docs/src/body_nested_models/tutorial004.py with 100% similarity]
docs_src/body_nested_models/tutorial005.py [moved from docs/src/body_nested_models/tutorial005.py with 100% similarity]
docs_src/body_nested_models/tutorial006.py [moved from docs/src/body_nested_models/tutorial006.py with 100% similarity]
docs_src/body_nested_models/tutorial007.py [moved from docs/src/body_nested_models/tutorial007.py with 100% similarity]
docs_src/body_nested_models/tutorial008.py [moved from docs/src/body_nested_models/tutorial008.py with 100% similarity]
docs_src/body_nested_models/tutorial009.py [moved from docs/src/body_nested_models/tutorial009.py with 100% similarity]
docs_src/body_updates/tutorial001.py [moved from docs/src/body_updates/tutorial001.py with 100% similarity]
docs_src/body_updates/tutorial002.py [moved from docs/src/body_updates/tutorial002.py with 100% similarity]
docs_src/cookie_params/tutorial001.py [moved from docs/src/cookie_params/tutorial001.py with 100% similarity]
docs_src/cors/tutorial001.py [moved from docs/src/cors/tutorial001.py with 100% similarity]
docs_src/custom_request_and_route/tutorial001.py [moved from docs/src/custom_request_and_route/tutorial001.py with 100% similarity]
docs_src/custom_request_and_route/tutorial002.py [moved from docs/src/custom_request_and_route/tutorial002.py with 100% similarity]
docs_src/custom_request_and_route/tutorial003.py [moved from docs/src/custom_request_and_route/tutorial003.py with 100% similarity]
docs_src/custom_response/tutorial001.py [moved from docs/src/custom_response/tutorial001.py with 100% similarity]
docs_src/custom_response/tutorial001b.py [moved from docs/src/custom_response/tutorial001b.py with 100% similarity]
docs_src/custom_response/tutorial002.py [moved from docs/src/custom_response/tutorial002.py with 100% similarity]
docs_src/custom_response/tutorial003.py [moved from docs/src/custom_response/tutorial003.py with 100% similarity]
docs_src/custom_response/tutorial004.py [moved from docs/src/custom_response/tutorial004.py with 100% similarity]
docs_src/custom_response/tutorial005.py [moved from docs/src/custom_response/tutorial005.py with 100% similarity]
docs_src/custom_response/tutorial006.py [moved from docs/src/custom_response/tutorial006.py with 100% similarity]
docs_src/custom_response/tutorial007.py [moved from docs/src/custom_response/tutorial007.py with 100% similarity]
docs_src/custom_response/tutorial008.py [moved from docs/src/custom_response/tutorial008.py with 100% similarity]
docs_src/custom_response/tutorial009.py [moved from docs/src/custom_response/tutorial009.py with 100% similarity]
docs_src/debugging/tutorial001.py [moved from docs/src/debugging/tutorial001.py with 100% similarity]
docs_src/dependencies/tutorial001.py [moved from docs/src/dependencies/tutorial001.py with 100% similarity]
docs_src/dependencies/tutorial002.py [moved from docs/src/dependencies/tutorial002.py with 100% similarity]
docs_src/dependencies/tutorial003.py [moved from docs/src/dependencies/tutorial003.py with 100% similarity]
docs_src/dependencies/tutorial004.py [moved from docs/src/dependencies/tutorial004.py with 100% similarity]
docs_src/dependencies/tutorial005.py [moved from docs/src/dependencies/tutorial005.py with 100% similarity]
docs_src/dependencies/tutorial006.py [moved from docs/src/dependencies/tutorial006.py with 100% similarity]
docs_src/dependencies/tutorial007.py [moved from docs/src/dependencies/tutorial007.py with 100% similarity]
docs_src/dependencies/tutorial008.py [moved from docs/src/dependencies/tutorial008.py with 100% similarity]
docs_src/dependencies/tutorial009.py [moved from docs/src/dependencies/tutorial009.py with 100% similarity]
docs_src/dependencies/tutorial010.py [moved from docs/src/dependencies/tutorial010.py with 100% similarity]
docs_src/dependencies/tutorial011.py [moved from docs/src/dependencies/tutorial011.py with 100% similarity]
docs_src/dependency_testing/tutorial001.py [moved from docs/src/dependency_testing/tutorial001.py with 100% similarity]
docs_src/encoder/tutorial001.py [moved from docs/src/encoder/tutorial001.py with 100% similarity]
docs_src/events/tutorial001.py [moved from docs/src/events/tutorial001.py with 100% similarity]
docs_src/events/tutorial002.py [moved from docs/src/events/tutorial002.py with 100% similarity]
docs_src/extending_openapi/tutorial001.py [moved from docs/src/extending_openapi/tutorial001.py with 100% similarity]
docs_src/extending_openapi/tutorial002.py [moved from docs/src/extending_openapi/tutorial002.py with 100% similarity]
docs_src/extra_data_types/tutorial001.py [moved from docs/src/extra_data_types/tutorial001.py with 100% similarity]
docs_src/extra_models/tutorial001.py [moved from docs/src/extra_models/tutorial001.py with 100% similarity]
docs_src/extra_models/tutorial002.py [moved from docs/src/extra_models/tutorial002.py with 100% similarity]
docs_src/extra_models/tutorial003.py [moved from docs/src/extra_models/tutorial003.py with 100% similarity]
docs_src/extra_models/tutorial004.py [moved from docs/src/extra_models/tutorial004.py with 100% similarity]
docs_src/extra_models/tutorial005.py [moved from docs/src/extra_models/tutorial005.py with 100% similarity]
docs_src/first_steps/tutorial001.py [moved from docs/src/first_steps/tutorial001.py with 100% similarity]
docs_src/first_steps/tutorial002.py [moved from docs/src/first_steps/tutorial002.py with 100% similarity]
docs_src/first_steps/tutorial003.py [moved from docs/src/first_steps/tutorial003.py with 100% similarity]
docs_src/graphql/tutorial001.py [moved from docs/src/graphql/tutorial001.py with 100% similarity]
docs_src/handling_errors/tutorial001.py [moved from docs/src/handling_errors/tutorial001.py with 100% similarity]
docs_src/handling_errors/tutorial002.py [moved from docs/src/handling_errors/tutorial002.py with 100% similarity]
docs_src/handling_errors/tutorial003.py [moved from docs/src/handling_errors/tutorial003.py with 100% similarity]
docs_src/handling_errors/tutorial004.py [moved from docs/src/handling_errors/tutorial004.py with 100% similarity]
docs_src/handling_errors/tutorial005.py [moved from docs/src/handling_errors/tutorial005.py with 100% similarity]
docs_src/handling_errors/tutorial006.py [moved from docs/src/handling_errors/tutorial006.py with 100% similarity]
docs_src/header_params/tutorial001.py [moved from docs/src/header_params/tutorial001.py with 100% similarity]
docs_src/header_params/tutorial002.py [moved from docs/src/header_params/tutorial002.py with 100% similarity]
docs_src/header_params/tutorial003.py [moved from docs/src/header_params/tutorial003.py with 100% similarity]
docs_src/middleware/tutorial001.py [moved from docs/src/middleware/tutorial001.py with 100% similarity]
docs_src/nosql_databases/tutorial001.py [moved from docs/src/nosql_databases/tutorial001.py with 100% similarity]
docs_src/openapi_callbacks/tutorial001.py [moved from docs/src/openapi_callbacks/tutorial001.py with 100% similarity]
docs_src/path_operation_advanced_configuration/tutorial001.py [moved from docs/src/path_operation_advanced_configuration/tutorial001.py with 100% similarity]
docs_src/path_operation_advanced_configuration/tutorial002.py [moved from docs/src/path_operation_advanced_configuration/tutorial002.py with 100% similarity]
docs_src/path_operation_advanced_configuration/tutorial003.py [moved from docs/src/path_operation_advanced_configuration/tutorial003.py with 100% similarity]
docs_src/path_operation_advanced_configuration/tutorial004.py [moved from docs/src/path_operation_advanced_configuration/tutorial004.py with 100% similarity]
docs_src/path_operation_configuration/tutorial001.py [moved from docs/src/path_operation_configuration/tutorial001.py with 100% similarity]
docs_src/path_operation_configuration/tutorial002.py [moved from docs/src/path_operation_configuration/tutorial002.py with 100% similarity]
docs_src/path_operation_configuration/tutorial003.py [moved from docs/src/path_operation_configuration/tutorial003.py with 100% similarity]
docs_src/path_operation_configuration/tutorial004.py [moved from docs/src/path_operation_configuration/tutorial004.py with 100% similarity]
docs_src/path_operation_configuration/tutorial005.py [moved from docs/src/path_operation_configuration/tutorial005.py with 100% similarity]
docs_src/path_operation_configuration/tutorial006.py [moved from docs/src/path_operation_configuration/tutorial006.py with 100% similarity]
docs_src/path_params/tutorial001.py [moved from docs/src/path_params/tutorial001.py with 100% similarity]
docs_src/path_params/tutorial002.py [moved from docs/src/path_params/tutorial002.py with 100% similarity]
docs_src/path_params/tutorial003.py [moved from docs/src/path_params/tutorial003.py with 100% similarity]
docs_src/path_params/tutorial004.py [moved from docs/src/path_params/tutorial004.py with 100% similarity]
docs_src/path_params/tutorial005.py [moved from docs/src/path_params/tutorial005.py with 100% similarity]
docs_src/path_params_numeric_validations/tutorial001.py [moved from docs/src/path_params_numeric_validations/tutorial001.py with 100% similarity]
docs_src/path_params_numeric_validations/tutorial002.py [moved from docs/src/path_params_numeric_validations/tutorial002.py with 100% similarity]
docs_src/path_params_numeric_validations/tutorial003.py [moved from docs/src/path_params_numeric_validations/tutorial003.py with 100% similarity]
docs_src/path_params_numeric_validations/tutorial004.py [moved from docs/src/path_params_numeric_validations/tutorial004.py with 100% similarity]
docs_src/path_params_numeric_validations/tutorial005.py [moved from docs/src/path_params_numeric_validations/tutorial005.py with 100% similarity]
docs_src/path_params_numeric_validations/tutorial006.py [moved from docs/src/path_params_numeric_validations/tutorial006.py with 100% similarity]
docs_src/python_types/tutorial001.py [moved from docs/src/python_types/tutorial001.py with 100% similarity]
docs_src/python_types/tutorial002.py [moved from docs/src/python_types/tutorial002.py with 100% similarity]
docs_src/python_types/tutorial003.py [moved from docs/src/python_types/tutorial003.py with 100% similarity]
docs_src/python_types/tutorial004.py [moved from docs/src/python_types/tutorial004.py with 100% similarity]
docs_src/python_types/tutorial005.py [moved from docs/src/python_types/tutorial005.py with 100% similarity]
docs_src/python_types/tutorial006.py [moved from docs/src/python_types/tutorial006.py with 100% similarity]
docs_src/python_types/tutorial007.py [moved from docs/src/python_types/tutorial007.py with 100% similarity]
docs_src/python_types/tutorial008.py [moved from docs/src/python_types/tutorial008.py with 100% similarity]
docs_src/python_types/tutorial009.py [moved from docs/src/python_types/tutorial009.py with 100% similarity]
docs_src/python_types/tutorial010.py [moved from docs/src/python_types/tutorial010.py with 100% similarity]
docs_src/query_params/tutorial001.py [moved from docs/src/query_params/tutorial001.py with 100% similarity]
docs_src/query_params/tutorial002.py [moved from docs/src/query_params/tutorial002.py with 100% similarity]
docs_src/query_params/tutorial003.py [moved from docs/src/query_params/tutorial003.py with 100% similarity]
docs_src/query_params/tutorial004.py [moved from docs/src/query_params/tutorial004.py with 100% similarity]
docs_src/query_params/tutorial005.py [moved from docs/src/query_params/tutorial005.py with 100% similarity]
docs_src/query_params/tutorial006.py [moved from docs/src/query_params/tutorial006.py with 100% similarity]
docs_src/query_params/tutorial007.py [moved from docs/src/query_params/tutorial007.py with 100% similarity]
docs_src/query_params_str_validations/tutorial001.py [moved from docs/src/query_params_str_validations/tutorial001.py with 100% similarity]
docs_src/query_params_str_validations/tutorial002.py [moved from docs/src/query_params_str_validations/tutorial002.py with 100% similarity]
docs_src/query_params_str_validations/tutorial003.py [moved from docs/src/query_params_str_validations/tutorial003.py with 100% similarity]
docs_src/query_params_str_validations/tutorial004.py [moved from docs/src/query_params_str_validations/tutorial004.py with 100% similarity]
docs_src/query_params_str_validations/tutorial005.py [moved from docs/src/query_params_str_validations/tutorial005.py with 100% similarity]
docs_src/query_params_str_validations/tutorial006.py [moved from docs/src/query_params_str_validations/tutorial006.py with 100% similarity]
docs_src/query_params_str_validations/tutorial007.py [moved from docs/src/query_params_str_validations/tutorial007.py with 100% similarity]
docs_src/query_params_str_validations/tutorial008.py [moved from docs/src/query_params_str_validations/tutorial008.py with 100% similarity]
docs_src/query_params_str_validations/tutorial009.py [moved from docs/src/query_params_str_validations/tutorial009.py with 100% similarity]
docs_src/query_params_str_validations/tutorial010.py [moved from docs/src/query_params_str_validations/tutorial010.py with 100% similarity]
docs_src/query_params_str_validations/tutorial011.py [moved from docs/src/query_params_str_validations/tutorial011.py with 100% similarity]
docs_src/query_params_str_validations/tutorial012.py [moved from docs/src/query_params_str_validations/tutorial012.py with 100% similarity]
docs_src/query_params_str_validations/tutorial013.py [moved from docs/src/query_params_str_validations/tutorial013.py with 100% similarity]
docs_src/request_files/tutorial001.py [moved from docs/src/request_files/tutorial001.py with 100% similarity]
docs_src/request_files/tutorial002.py [moved from docs/src/request_files/tutorial002.py with 100% similarity]
docs_src/request_forms/tutorial001.py [moved from docs/src/request_forms/tutorial001.py with 100% similarity]
docs_src/request_forms_and_files/tutorial001.py [moved from docs/src/request_forms_and_files/tutorial001.py with 100% similarity]
docs_src/response_change_status_code/tutorial001.py [moved from docs/src/response_change_status_code/tutorial001.py with 100% similarity]
docs_src/response_cookies/tutorial001.py [moved from docs/src/response_cookies/tutorial001.py with 100% similarity]
docs_src/response_cookies/tutorial002.py [moved from docs/src/response_cookies/tutorial002.py with 100% similarity]
docs_src/response_directly/tutorial001.py [moved from docs/src/response_directly/tutorial001.py with 100% similarity]
docs_src/response_directly/tutorial002.py [moved from docs/src/response_directly/tutorial002.py with 100% similarity]
docs_src/response_headers/tutorial001.py [moved from docs/src/response_headers/tutorial001.py with 100% similarity]
docs_src/response_headers/tutorial002.py [moved from docs/src/response_headers/tutorial002.py with 100% similarity]
docs_src/response_model/tutorial001.py [moved from docs/src/response_model/tutorial001.py with 100% similarity]
docs_src/response_model/tutorial002.py [moved from docs/src/response_model/tutorial002.py with 100% similarity]
docs_src/response_model/tutorial003.py [moved from docs/src/response_model/tutorial003.py with 100% similarity]
docs_src/response_model/tutorial004.py [moved from docs/src/response_model/tutorial004.py with 100% similarity]
docs_src/response_model/tutorial005.py [moved from docs/src/response_model/tutorial005.py with 100% similarity]
docs_src/response_model/tutorial006.py [moved from docs/src/response_model/tutorial006.py with 100% similarity]
docs_src/response_status_code/tutorial001.py [moved from docs/src/response_status_code/tutorial001.py with 100% similarity]
docs_src/response_status_code/tutorial002.py [moved from docs/src/response_status_code/tutorial002.py with 100% similarity]
docs_src/security/tutorial001.py [moved from docs/src/security/tutorial001.py with 100% similarity]
docs_src/security/tutorial002.py [moved from docs/src/security/tutorial002.py with 100% similarity]
docs_src/security/tutorial003.py [moved from docs/src/security/tutorial003.py with 100% similarity]
docs_src/security/tutorial004.py [moved from docs/src/security/tutorial004.py with 100% similarity]
docs_src/security/tutorial005.py [moved from docs/src/security/tutorial005.py with 100% similarity]
docs_src/security/tutorial006.py [moved from docs/src/security/tutorial006.py with 100% similarity]
docs_src/security/tutorial007.py [moved from docs/src/security/tutorial007.py with 100% similarity]
docs_src/sql_databases/__init__.py [moved from docs/src/sql_databases/__init__.py with 100% similarity]
docs_src/sql_databases/sql_app/__init__.py [moved from docs/src/sql_databases/sql_app/__init__.py with 100% similarity]
docs_src/sql_databases/sql_app/alt_main.py [moved from docs/src/sql_databases/sql_app/alt_main.py with 100% similarity]
docs_src/sql_databases/sql_app/crud.py [moved from docs/src/sql_databases/sql_app/crud.py with 100% similarity]
docs_src/sql_databases/sql_app/database.py [moved from docs/src/sql_databases/sql_app/database.py with 100% similarity]
docs_src/sql_databases/sql_app/main.py [moved from docs/src/sql_databases/sql_app/main.py with 100% similarity]
docs_src/sql_databases/sql_app/models.py [moved from docs/src/sql_databases/sql_app/models.py with 100% similarity]
docs_src/sql_databases/sql_app/schemas.py [moved from docs/src/sql_databases/sql_app/schemas.py with 100% similarity]
docs_src/sql_databases_peewee/__init__.py [moved from docs/src/sql_databases_peewee/__init__.py with 100% similarity]
docs_src/sql_databases_peewee/sql_app/__init__.py [moved from docs/src/sql_databases_peewee/sql_app/__init__.py with 100% similarity]
docs_src/sql_databases_peewee/sql_app/crud.py [moved from docs/src/sql_databases_peewee/sql_app/crud.py with 100% similarity]
docs_src/sql_databases_peewee/sql_app/database.py [moved from docs/src/sql_databases_peewee/sql_app/database.py with 100% similarity]
docs_src/sql_databases_peewee/sql_app/main.py [moved from docs/src/sql_databases_peewee/sql_app/main.py with 100% similarity]
docs_src/sql_databases_peewee/sql_app/models.py [moved from docs/src/sql_databases_peewee/sql_app/models.py with 100% similarity]
docs_src/sql_databases_peewee/sql_app/schemas.py [moved from docs/src/sql_databases_peewee/sql_app/schemas.py with 100% similarity]
docs_src/static_files/tutorial001.py [moved from docs/src/static_files/tutorial001.py with 100% similarity]
docs_src/sub_applications/tutorial001.py [moved from docs/src/sub_applications/tutorial001.py with 100% similarity]
docs_src/templates/static/styles.css [moved from docs/src/templates/static/styles.css with 100% similarity]
docs_src/templates/templates/item.html [moved from docs/src/templates/templates/item.html with 100% similarity]
docs_src/templates/tutorial001.py [moved from docs/src/templates/tutorial001.py with 100% similarity]
docs_src/using_request_directly/tutorial001.py [moved from docs/src/using_request_directly/tutorial001.py with 100% similarity]
docs_src/websockets/__init__.py [moved from docs/src/websockets/__init__.py with 100% similarity]
docs_src/websockets/tutorial001.py [moved from docs/src/websockets/tutorial001.py with 100% similarity]
docs_src/websockets/tutorial002.py [moved from docs/src/websockets/tutorial002.py with 100% similarity]
docs_src/wsgi/tutorial001.py [moved from docs/src/wsgi/tutorial001.py with 100% similarity]
mkdocs.yml [deleted file]
pyproject.toml
scripts/build-docs.sh
scripts/docs.py [new file with mode: 0644]
scripts/format-imports.sh
scripts/format.sh
scripts/test.sh
tests/test_tutorial/test_additional_responses/test_tutorial002.py
tests/test_tutorial/test_additional_responses/test_tutorial004.py
tests/test_tutorial/test_templates/test_tutorial001.py

index 77f1c274c1adc1bf9cfe810710af334e8b74c1bc..60f8e4b4ae4ef8fa351cdb4685146d0fb060df16 100644 (file)
@@ -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:
index f110dc59725eb559ae32217e51b4fd4577270122..3dbfdd44d16b51db303cb5013c53ac36674f996a 100644 (file)
@@ -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 (file)
index 4ca50db..0000000
+++ /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. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
-
-```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 <a href="https://flit.readthedocs.io/en/latest/index.html" class="external-link" target="_blank">Flit</a> 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 <a href="https://www.mkdocs.org/" class="external-link" target="_blank">MkDocs</a>.
-
-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
-```
similarity index 97%
rename from docs/advanced/additional-responses.md
rename to docs/en/docs/advanced/additional-responses.md
index 71c4cf61d279a45a6d4a4f4b39c183075764da60..4b2abaada310941d7b4076bce7802f89c60e441d 100644 (file)
@@ -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
similarity index 95%
rename from docs/advanced/additional-status-codes.md
rename to docs/en/docs/advanced/additional-status-codes.md
index 14a867c989c88544f72f7b9522a1fef9d1c7d348..b9a32cfa3b661c55b99364bc2eaa47483bfc77c6 100644 (file)
@@ -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
similarity index 91%
rename from docs/advanced/advanced-dependencies.md
rename to docs/en/docs/advanced/advanced-dependencies.md
index ec796362a847d46f273ac56396b97be770cdf328..5e79776cacddd81542f51be739983dce1b8e67d3 100644 (file)
@@ -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
similarity index 90%
rename from docs/advanced/async-sql-databases.md
rename to docs/en/docs/advanced/async-sql-databases.md
index c7d0b86dff3ede2fa52a3adf355961116c61fbd7..523bc91bf472637046f1050bbb55995fc1de8c1e 100644 (file)
@@ -1,3 +1,5 @@
+# Async SQL (Relational) Databases
+
 You can also use <a href="https://github.com/encode/databases" class="external-link" target="_blank">`encode/databases`</a> 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
similarity index 91%
rename from docs/advanced/custom-request-and-route.md
rename to docs/en/docs/advanced/custom-request-and-route.md
index 2e823143a74d9d9b6f356650dff2b26ed9801f09..6c5e97a18b003e2460b931d1cde4d2021e5355b1 100644 (file)
@@ -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!}
 ```
similarity index 92%
rename from docs/advanced/custom-response.md
rename to docs/en/docs/advanced/custom-response.md
index 21e7abee4bcb1b9da3221e1a93980d066aacf516..545a84436015c2274cd0308bdfe34114411fb0eb 100644 (file)
@@ -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 <a href="
 Import the `Response` class (sub-class) you want to use and declare it in the *path operation decorator*.
 
 ```Python hl_lines="2 7"
-{!./src/custom_response/tutorial001b.py!}
+{!../../../docs_src/custom_response/tutorial001b.py!}
 ```
 
 !!! info
@@ -41,7 +43,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
 * Pass `HTMLResponse` as the parameter `content_type` of your *path operation*.
 
 ```Python hl_lines="2 7"
-{!./src/custom_response/tutorial002.py!}
+{!../../../docs_src/custom_response/tutorial002.py!}
 ```
 
 !!! info
@@ -58,7 +60,7 @@ As seen in [Return a Response directly](response-directly.md){.internal-link tar
 The same example from above, returning an `HTMLResponse`, could look like:
 
 ```Python hl_lines="2 7 19"
-{!./src/custom_response/tutorial003.py!}
+{!../../../docs_src/custom_response/tutorial003.py!}
 ```
 
 !!! warning
@@ -78,7 +80,7 @@ The `response_class` will then be used only to document the OpenAPI *path operat
 For example, it could be something like:
 
 ```Python hl_lines="7 23 21"
-{!./src/custom_response/tutorial004.py!}
+{!../../../docs_src/custom_response/tutorial004.py!}
 ```
 
 In this example, the function `generate_html_response()` already generates and returns a `Response` instead of returning the HTML in a `str`.
@@ -116,7 +118,7 @@ It accepts the following parameters:
 FastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the media_type and appending a charset for text types.
 
 ```Python hl_lines="1  18"
-{!./src/response_directly/tutorial002.py!}
+{!../../../docs_src/response_directly/tutorial002.py!}
 ```
 
 ### `HTMLResponse`
@@ -128,7 +130,7 @@ Takes some text or bytes and returns an HTML response, as you read above.
 Takes some text or bytes and returns an plain text response.
 
 ```Python hl_lines="2  7  9"
-{!./src/custom_response/tutorial005.py!}
+{!../../../docs_src/custom_response/tutorial005.py!}
 ```
 
 ### `JSONResponse`
@@ -149,7 +151,7 @@ An alternative JSON response using <a href="https://github.com/ultrajson/ultrajs
     `ujson` is less careful than Python's built-in implementation in how it handles some edge-cases.
 
 ```Python hl_lines="2 7"
-{!./src/custom_response/tutorial001.py!}
+{!../../../docs_src/custom_response/tutorial001.py!}
 ```
 
 !!! tip
@@ -160,7 +162,7 @@ An alternative JSON response using <a href="https://github.com/ultrajson/ultrajs
 Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default.
 
 ```Python hl_lines="2  9"
-{!./src/custom_response/tutorial006.py!}
+{!../../../docs_src/custom_response/tutorial006.py!}
 ```
 
 ### `StreamingResponse`
@@ -168,7 +170,7 @@ Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default
 Takes an async generator or a normal generator/iterator and streams the response body.
 
 ```Python hl_lines="2  14"
-{!./src/custom_response/tutorial007.py!}
+{!../../../docs_src/custom_response/tutorial007.py!}
 ```
 
 #### Using `StreamingResponse` with file-like objects
@@ -178,7 +180,7 @@ If you have a file-like object (e.g. the object returned by `open()`), you can r
 This includes many libraries to interact with cloud storage, video processing, and others.
 
 ```Python hl_lines="2  10 11"
-{!./src/custom_response/tutorial008.py!}
+{!../../../docs_src/custom_response/tutorial008.py!}
 ```
 
 !!! tip
@@ -198,7 +200,7 @@ Takes a different set of arguments to instantiate than the other response types:
 File responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers.
 
 ```Python hl_lines="2  10"
-{!./src/custom_response/tutorial009.py!}
+{!../../../docs_src/custom_response/tutorial009.py!}
 ```
 
 ## Additional documentation
similarity index 93%
rename from docs/advanced/events.md
rename to docs/en/docs/advanced/events.md
index d95a60a4cc3f416668e60fc7b37f3c0071affa74..8b3dc7af1859e43c44e979a1874902f46eabd6ff 100644 (file)
@@ -1,3 +1,4 @@
+# Events: startup - shutdown
 
 You can define event handlers (functions) that need to be executed before the application starts up, or when the application is shutting down.
 
@@ -8,7 +9,7 @@ These functions can be declared with `async def` or normal `def`.
 To add a function that should be run before the application starts, declare it with the event `"startup"`:
 
 ```Python hl_lines="8"
-{!./src/events/tutorial001.py!}
+{!../../../docs_src/events/tutorial001.py!}
 ```
 
 In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values.
@@ -22,7 +23,7 @@ And your application won't start receiving requests until all the `startup` even
 To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`:
 
 ```Python hl_lines="6"
-{!./src/events/tutorial002.py!}
+{!../../../docs_src/events/tutorial002.py!}
 ```
 
 Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`.
similarity index 94%
rename from docs/advanced/extending-openapi.md
rename to docs/en/docs/advanced/extending-openapi.md
index 4841c92134d941c0244c82cdb693ed2a7d8f832e..f98be49a6f3c2de5e432056178157f22121d1cb3 100644 (file)
@@ -1,3 +1,5 @@
+# Extending OpenAPI
+
 !!! warning
     This is a rather advanced feature. You probably can skip it.
 
@@ -43,7 +45,7 @@ For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/doc
 First, write all your **FastAPI** application as normally:
 
 ```Python hl_lines="1 4 7 8 9"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
 ```
 
 ### Generate the OpenAPI schema
@@ -51,7 +53,7 @@ First, write all your **FastAPI** application as normally:
 Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
 
 ```Python hl_lines="2 15 16 17 18 19 20"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
 ```
 
 ### Modify the OpenAPI schema
@@ -59,7 +61,7 @@ Then, use the same utility function to generate the OpenAPI schema, inside a `cu
 Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
 
 ```Python hl_lines="21 22 23"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
 ```
 
 ### Cache the OpenAPI schema
@@ -71,7 +73,7 @@ That way, your application won't have to generate the schema every time a user o
 It will be generated only once, and then the same cached schema will be used for the next requests.
 
 ```Python hl_lines="13 14 24 25"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
 ```
 
 ### Override the method
@@ -79,7 +81,7 @@ It will be generated only once, and then the same cached schema will be used for
 Now you can replace the `.openapi()` method with your new function.
 
 ```Python hl_lines="28"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
 ```
 
 ### Check it
@@ -172,7 +174,7 @@ $ pip install aiofiles
 * "Mount" a `StaticFiles()` instance in a specific path.
 
 ```Python hl_lines="7 11"
-{!./src/extending_openapi/tutorial002.py!}
+{!../../../docs_src/extending_openapi/tutorial002.py!}
 ```
 
 ### Test the static files
@@ -206,7 +208,7 @@ The first step is to disable the automatic docs, as those use the CDN by default
 To disable them, set their URLs to `None` when creating your `FastAPI` app:
 
 ```Python hl_lines="9"
-{!./src/extending_openapi/tutorial002.py!}
+{!../../../docs_src/extending_openapi/tutorial002.py!}
 ```
 
 ### Include the custom docs
@@ -224,7 +226,7 @@ You can re-use FastAPI's internal functions to create the HTML pages for the doc
 And similarly for ReDoc...
 
 ```Python hl_lines="2 3 4 5 6   14 15 16 17 18 19 20 21 22    25 26 27   30 31 32 33 34 35 36"
-{!./src/extending_openapi/tutorial002.py!}
+{!../../../docs_src/extending_openapi/tutorial002.py!}
 ```
 
 !!! tip
@@ -239,7 +241,7 @@ And similarly for ReDoc...
 Now, to be able to test that everything works, create a *path operation*:
 
 ```Python hl_lines="39 40 41"
-{!./src/extending_openapi/tutorial002.py!}
+{!../../../docs_src/extending_openapi/tutorial002.py!}
 ```
 
 ### Test it
similarity index 93%
rename from docs/advanced/graphql.md
rename to docs/en/docs/advanced/graphql.md
index faeabf2d310b0a1f8a1baedb33ad26669c31b308..152754e9a543da6f84321a2489e7971a67494184 100644 (file)
@@ -1,3 +1,4 @@
+# GraphQL
 
 **FastAPI** has optional support for GraphQL (provided by Starlette directly), using the `graphene` library.
 
@@ -10,7 +11,7 @@ GraphQL is implemented with Graphene, you can check <a href="https://docs.graphe
 Import `graphene` and define your GraphQL data:
 
 ```Python hl_lines="1 6 7 8 9 10"
-{!./src/graphql/tutorial001.py!}
+{!../../../docs_src/graphql/tutorial001.py!}
 ```
 
 ## Add Starlette's `GraphQLApp`
@@ -18,7 +19,7 @@ Import `graphene` and define your GraphQL data:
 Then import and add Starlette's `GraphQLApp`:
 
 ```Python hl_lines="3 14"
-{!./src/graphql/tutorial001.py!}
+{!../../../docs_src/graphql/tutorial001.py!}
 ```
 
 !!! info
similarity index 95%
rename from docs/advanced/index.md
rename to docs/en/docs/advanced/index.md
index 4e9b65cedd112d9381d5191b8e1bd308222159dd..628eb71af683a24e65261d5b489e8d886b542fde 100644 (file)
@@ -1,3 +1,5 @@
+# Advanced User Guide - Intro
+
 ## Additional Features
 
 The main [Tutorial - User Guide](../tutorial/){.internal-link target=_blank} should be enough to give you a tour through all the main features of **FastAPI**.
similarity index 95%
rename from docs/advanced/middleware.md
rename to docs/en/docs/advanced/middleware.md
index eff6c30be990f9d09012830eb91f341e7202f91b..4db8af275c4e622689d5eedb34ee92d8ed38bea8 100644 (file)
@@ -1,3 +1,5 @@
+# Advanced Middleware
+
 In the main tutorial you read how to add [Custom Middleware](../tutorial/middleware.md){.internal-link target=_blank} to your application.
 
 And then you also read how to handle [CORS with the `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}.
@@ -53,7 +55,7 @@ Enforces that all incoming requests must either be `https` or `wss`.
 Any incoming requests to `http` or `ws` will be redirected to the secure scheme instead.
 
 ```Python hl_lines="2  6"
-{!./src/advanced_middleware/tutorial001.py!}
+{!../../../docs_src/advanced_middleware/tutorial001.py!}
 ```
 
 ## `TrustedHostMiddleware`
@@ -61,7 +63,7 @@ Any incoming requests to `http` or `ws` will be redirected to the secure scheme
 Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks.
 
 ```Python hl_lines="2  6 7 8"
-{!./src/advanced_middleware/tutorial002.py!}
+{!../../../docs_src/advanced_middleware/tutorial002.py!}
 ```
 
 The following arguments are supported:
@@ -77,7 +79,7 @@ Handles GZip responses for any request that includes `"gzip"` in the `Accept-Enc
 The middleware will handle both standard and streaming responses.
 
 ```Python hl_lines="2  6 7 8"
-{!./src/advanced_middleware/tutorial002.py!}
+{!../../../docs_src/advanced_middleware/tutorial002.py!}
 ```
 
 The following arguments are supported:
similarity index 91%
rename from docs/advanced/nosql-databases.md
rename to docs/en/docs/advanced/nosql-databases.md
index a01921cb7cb27f487339347c8d81daaa4846412a..3cbc2aa2098694d8ae21d371c7f2e93bc8951a77 100644 (file)
@@ -1,3 +1,5 @@
+# NoSQL (Distributed / Big Data) Databases
+
 **FastAPI** can also be integrated with any <abbr title="Distributed database (Big Data), also 'Not Only SQL'">NoSQL</abbr>.
 
 Here we'll see an example using **<a href="https://www.couchbase.com/" class="external-link" target="_blank">Couchbase</a>**, a <abbr title="Document here refers to a JSON object (a dict), with keys and values, and those values can also be other JSON objects, arrays (lists), numbers, strings, booleans, etc.">document</abbr> 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 <abbr title="Automated test, written in code, that checks if another piece of code is working correctly.">unit tests</abbr> 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 <a href="https://docs.
 Also, Couchbase recommends not using a single `Bucket` object in multiple "<abbr title="A sequence of code being executed by the program, while at the same time, or at intervals, there can be others being executed too.">thread</abbr>s", 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
similarity index 97%
rename from docs/advanced/openapi-callbacks.md
rename to docs/en/docs/advanced/openapi-callbacks.md
index 8d3b0ac9e87d8d74dc9da3c914684e924676b709..15c0ba2a1d45d49a4b321146536a10cdfd52fbff 100644 (file)
@@ -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
similarity index 82%
rename from docs/advanced/path-operation-advanced-configuration.md
rename to docs/en/docs/advanced/path-operation-advanced-configuration.md
index eb5cc6a1200752f3bc526d07a15e8d4f58ed7257..7a3247a64ab4da0527809bbc6fe89e97c424d933 100644 (file)
@@ -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!}
 ```
similarity index 93%
rename from docs/advanced/response-change-status-code.md
rename to docs/en/docs/advanced/response-change-status-code.md
index 1f10e12da9133aa3c46cbca41646b4a2a337376f..979cef3f05367a1752339d20fd0dbc112216b4b7 100644 (file)
@@ -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).
similarity index 94%
rename from docs/advanced/response-cookies.md
rename to docs/en/docs/advanced/response-cookies.md
index 8ce07bbf35c921938df057bbb1579cbcc168f971..e46ae755f79d97f3088977106875d2b78831e404 100644 (file)
@@ -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
similarity index 95%
rename from docs/advanced/response-directly.md
rename to docs/en/docs/advanced/response-directly.md
index 1b123280878ef93e9a41eae7608160d1ae2bdc74..f1dca1812b6d56e487130d55cc4aac480a6bd2be 100644 (file)
@@ -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 <a href="https://en.wikipedia.org/wiki/XML"
 You could put your XML content in a string, put it in a `Response`, and return it:
 
 ```Python hl_lines="1  18"
-{!./src/response_directly/tutorial002.py!}
+{!../../../docs_src/response_directly/tutorial002.py!}
 ```
 
 ## Notes
similarity index 94%
rename from docs/advanced/response-headers.md
rename to docs/en/docs/advanced/response-headers.md
index c0f0e6b463fc4c2b7f238d56ef9a9ee7db482591..914bd44017a86dd7dac3d8cb4ca1670bcb739918 100644 (file)
@@ -1,3 +1,5 @@
+# Response Headers
+
 ## Use a `Response` parameter
 
 You can declare a parameter of type `Response` in your *path operation function* (as you can do for cookies).
@@ -5,7 +7,7 @@ You can declare a parameter of type `Response` in your *path operation function*
 And then you can set headers in that *temporal* response object.
 
 ```Python hl_lines="1  7 8"
-{!./src/response_headers/tutorial002.py!}
+{!../../../docs_src/response_headers/tutorial002.py!}
 ```
 
 And then you can return any object you need, as you normally would (a `dict`, a database model, etc).
@@ -23,7 +25,7 @@ You can also add headers when you return a `Response` directly.
 Create a response as described in [Return a Response Directly](response-directly.md){.internal-link target=_blank} and pass the headers as an additional parameter:
 
 ```Python hl_lines="10 11 12"
-{!./src/response_headers/tutorial001.py!}
+{!../../../docs_src/response_headers/tutorial001.py!}
 ```
 
 !!! note "Technical Details"
similarity index 96%
rename from docs/advanced/security/http-basic-auth.md
rename to docs/en/docs/advanced/security/http-basic-auth.md
index 8dc277dae5fe14aa11de8bf451e9e78a86fb88d9..1d2e050f57446e4fcd30fc4e1699959404f653cb 100644 (file)
@@ -1,3 +1,5 @@
+# HTTP Basic Auth
+
 For the simplest cases, you can use HTTP Basic Auth.
 
 In HTTP Basic Auth, the application expects a header that contains a username and a password.
@@ -19,7 +21,7 @@ Then, when you type that username and password, the browser sends them in the he
     * It contains the `username` and `password` sent.
 
 ```Python hl_lines="2 6 10"
-{!./src/security/tutorial006.py!}
+{!../../../docs_src/security/tutorial006.py!}
 ```
 
 When you try to open the URL for the first time (or click the "Execute" button in the docs) the browser will ask you for your username and password:
@@ -35,7 +37,7 @@ Use a dependency to check if the username and password are correct.
 For this, use the Python standard module <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a> 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!}
 ```
similarity index 95%
rename from docs/advanced/security/index.md
rename to docs/en/docs/advanced/security/index.md
index 560af5a7cc58f072bebe0005cb2ca32f168d2ddd..0c94986b5728ebfe8278787df8bde6eef92e218e 100644 (file)
@@ -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}.
similarity index 97%
rename from docs/advanced/security/oauth2-scopes.md
rename to docs/en/docs/advanced/security/oauth2-scopes.md
index 84c806bf888e42ef9552993f11a1e9569e184cb2..a7842322137c9ba3050afce1b8ac49f255ce19fd 100644 (file)
@@ -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
similarity index 95%
rename from docs/advanced/sql-databases-peewee.md
rename to docs/en/docs/advanced/sql-databases-peewee.md
index ae957bec640c3daeec2ecc3da586bac159f519f1..7610290066b019069140ec6ecbf42ca77dd70e8b 100644 (file)
@@ -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
similarity index 94%
rename from docs/advanced/sub-applications-proxy.md
rename to docs/en/docs/advanced/sub-applications-proxy.md
index 333ef9ae2de76cdc12dea88e27ab3fdb9693c2b0..03a7f94460088b6bf0a2daf12678297034693352 100644 (file)
@@ -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
similarity index 91%
rename from docs/advanced/templates.md
rename to docs/en/docs/advanced/templates.md
index da4752e4a598ddb0a58205ef6f1aad1f3ff16179..871f3163f0622f57d608aa60b17ddb10c0954e5d 100644 (file)
@@ -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`.
similarity index 96%
rename from docs/advanced/testing-dependencies.md
rename to docs/en/docs/advanced/testing-dependencies.md
index 50d50618cf1545a1eadadad46c6e7c4ebfc3c578..5ba7e219b9b763f7bf581a51a4626ee31a16a60f 100644 (file)
@@ -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
similarity index 67%
rename from docs/advanced/testing-events.md
rename to docs/en/docs/advanced/testing-events.md
index a52aabe9870f548fa954aebb5f8dd54d6fba1e2d..45d8d868654fbaa8c21cc188eaa30bb75bf1e528 100644 (file)
@@ -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!}
+```
similarity index 72%
rename from docs/advanced/testing-websockets.md
rename to docs/en/docs/advanced/testing-websockets.md
index 8e9ecf34f8e7e9e038634ff0ed9ae5677fc5232f..a9d6821becfd4cd271291abec44bc7bb7a50a01d 100644 (file)
@@ -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!}
 ```
similarity index 96%
rename from docs/advanced/using-request-directly.md
rename to docs/en/docs/advanced/using-request-directly.md
index 4d9e84d2c2a422c88e1ab9951713eeb52d392994..ac452c25ee343d8374b762be4466cb975779a08d 100644 (file)
@@ -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.
similarity index 94%
rename from docs/advanced/websockets.md
rename to docs/en/docs/advanced/websockets.md
index a76eab59c815e07d89ec01beb6f386d377203a1a..d473cef0705c5863a530d27ce69547a27edc81aa 100644 (file)
@@ -1,3 +1,4 @@
+# WebSockets
 
 You can use <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSockets</a> 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
similarity index 92%
rename from docs/advanced/wsgi.md
rename to docs/en/docs/advanced/wsgi.md
index 7d2edfc55a6c5a74836a6e8fc31e1cf172663231..4b81aff2e77faca35f0157109f91a7a5739c7bf0 100644 (file)
@@ -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
similarity index 99%
rename from docs/alternatives.md
rename to docs/en/docs/alternatives.md
index 730c1079450f0af50698af75f011964e11518e5a..3d9e3a55af90fb5154394b8f604e80fcb822400f 100644 (file)
@@ -1,3 +1,5 @@
+# Alternatives, Inspiration and Comparisons
+
 What inspired **FastAPI**, how it compares to other alternatives and what it learned from them.
 
 ## Intro
similarity index 99%
rename from docs/async.md
rename to docs/en/docs/async.md
index 24c2f61d2ef9aa53f60bbb78cda9c07fc656fad6..dc17e5172c1cf5829817f0d2e1ccc180b15a58d7 100644 (file)
@@ -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?
similarity index 99%
rename from docs/benchmarks.md
rename to docs/en/docs/benchmarks.md
index 95efcab531766625adc11df8a8fdd3a12e031d4b..5223df81d6c9779a38b727f5d0d3e88c459407c0 100644 (file)
@@ -1,3 +1,5 @@
+# Benchmarks
+
 Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, 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 (file)
index 0000000..a08991a
--- /dev/null
@@ -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:
+
+<div class="termy">
+
+```console
+$ python -m venv env
+```
+
+</div>
+
+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:
+
+<div class="termy">
+
+```console
+$ source ./env/bin/activate
+```
+
+</div>
+
+Or in Windows' PowerShell:
+
+<div class="termy">
+
+```console
+$ .\env\Scripts\Activate.ps1
+```
+
+</div>
+
+Or if you use Bash for Windows (e.g. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
+
+<div class="termy">
+
+```console
+$ source ./env/Scripts/activate
+```
+
+</div>
+
+To check it worked, use:
+
+<div class="termy">
+
+```console
+$ which pip
+
+some/directory/fastapi/env/bin/pip
+```
+
+</div>
+
+If it shows the `pip` binary at `env/bin/pip` then it worked. 🎉
+
+Or in Windows PowerShell:
+
+<div class="termy">
+
+```console
+$ Get-Command pip
+
+some/directory/fastapi/env/bin/pip
+```
+
+</div>
+
+!!! 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 <a href="https://flit.readthedocs.io/en/latest/index.html" class="external-link" target="_blank">Flit</a> to build, package and publish the project.
+
+After activating the environment as described above, install `flit`:
+
+<div class="termy">
+
+```console
+$ pip install flit
+
+---> 100%
+```
+
+</div>
+
+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:
+
+<div class="termy">
+
+```console
+$ flit install --deps develop --symlink
+
+---> 100%
+```
+
+</div>
+
+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:
+
+<div class="termy">
+
+```console
+$ bash scripts/format.sh
+```
+
+</div>
+
+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:
+
+<div class="termy">
+
+```console
+$ flit install --symlink
+
+---> 100%
+```
+
+</div>
+
+### Format imports
+
+There is another script that formats all the imports and makes sure you don't have unused imports:
+
+<div class="termy">
+
+```console
+$ bash scripts/format-imports.sh
+```
+
+</div>
+
+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 <a href="https://www.mkdocs.org/" class="external-link" target="_blank">MkDocs</a>.
+
+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:
+
+<div class="termy">
+
+```console
+$ python ./scripts/docs.py live
+
+<span style="color: green;">[INFO]</span> Serving on http://0.0.0.0:8008
+<span style="color: green;">[INFO]</span> Start watching changes
+<span style="color: green;">[INFO]</span> Start detecting changes
+```
+
+</div>
+
+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 <a href="https://typer.tiangolo.com/typer-cli/" class="external-link" target="_blank">Typer CLI</a>, and you will get autocompletion in your terminal for the commands after installing completion.
+
+If you install Typer CLI, you can install completion with:
+
+<div class="termy">
+
+```console
+$ typer --install-completion
+
+zsh completion installed in /home/user/.bashrc.
+Completion will take effect once you restart the terminal.
+```
+
+</div>
+
+### Apps and docs at the same time
+
+If you run the examples with, e.g.:
+
+<div class="termy">
+
+```console
+$ uvicorn tutorial001:app --reload
+
+<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+</div>
+
+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 <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">List of ISO 639-1 codes</a>.
+
+#### 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:
+
+<div class="termy">
+
+```console
+// Use the command "live" and pass the language code as a CLI argument
+$ python ./scripts/docs.py live es
+
+<span style="color: green;">[INFO]</span> Serving on http://0.0.0.0:8008
+<span style="color: green;">[INFO]</span> Start watching changes
+<span style="color: green;">[INFO]</span> Start detecting changes
+```
+
+</div>
+
+Now you can go to <a href="http://0.0.0.0:8008" class="external-link" target="_blank">http://0.0.0.0:8008</a> 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:
+
+<div class="termy">
+
+```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
+```
+
+</div>
+
+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:
+
+<div class="termy">
+
+```console
+$ bash scripts/test-cov-html.sh
+```
+
+</div>
+
+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
+```
similarity index 99%
rename from docs/deployment.md
rename to docs/en/docs/deployment.md
index 8d4c6fcdba464fd2ad12ab367154e70cc4391ba6..8ca7c433ff6afca7b3f049ce74a5b5dc62577112 100644 (file)
@@ -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.
similarity index 99%
rename from docs/external-links.md
rename to docs/en/docs/external-links.md
index c222e1247fcbcef60c98b745b0048a72cc99f5c9..4546befd042c5b05101e420940d7779c08aae5c2 100644 (file)
@@ -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**.
similarity index 96%
rename from docs/features.md
rename to docs/en/docs/features.md
index 69c62cbced1f6c389a248dcea448adc68144fbd9..8b5bb51f171ea6d6e5341d468925b0ac0c4e16c5 100644 (file)
@@ -1,3 +1,4 @@
+# Features
 
 ## FastAPI features
 
@@ -16,11 +17,11 @@ Interactive API documentation and exploration web user interfaces. As the framew
 
 * <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>, 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 <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>.
 
-![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 <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>:
 
-![editor support](img/vscode-completion.png)
+![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
 
 * in <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>:
 
-![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.
 
similarity index 99%
rename from docs/help-fastapi.md
rename to docs/en/docs/help-fastapi.md
index 1370a5770eb9f27dafca85b834222058f0339fa8..f6965658302bd5bb796aa3947bbe579fc95734f6 100644 (file)
@@ -1,3 +1,5 @@
+# Help FastAPI - Get Help
+
 Do you like **FastAPI**?
 
 Would you like to help FastAPI, other users, and the author?
similarity index 99%
rename from docs/history-design-future.md
rename to docs/en/docs/history-design-future.md
index 08067e3c201bc9e3f4806007c48d52219010aaf7..9db1027c26c2abb735b7e42d360404b65439c0b7 100644 (file)
@@ -1,3 +1,5 @@
+# History, Design and Future
+
 Some time ago, <a href="https://github.com/tiangolo/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">a **FastAPI** user asked</a>:
 
 > What’s the history of this project? It seems to have come from nowhere to awesome in a few weeks [...]
similarity index 100%
rename from docs/index.md
rename to docs/en/docs/index.md
similarity index 100%
rename from docs/js/custom.js
rename to docs/en/docs/js/custom.js
similarity index 99%
rename from docs/project-generation.md
rename to docs/en/docs/project-generation.md
index 4562d6204a873d0f198744619286bbc6129e52d9..fd7a10fb7d109aaed6acc293c8b070e4c13e0bc5 100644 (file)
@@ -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
similarity index 92%
rename from docs/python-types.md
rename to docs/en/docs/python-types.md
index 5d25e1816597882faa041ed0259c7d4d29dcdc05..ce24281ba3ebf3524b310293e53ee9795154eca8 100644 (file)
@@ -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 <abbr title="for example: str, int, float, bool">type</abbr> 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:
 * <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> 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
similarity index 99%
rename from docs/release-notes.md
rename to docs/en/docs/release-notes.md
index 08d8806505371af4a1238fb3b1020d225b95f87e..d5218e063fb8a2d37827b397a792cbae0122b8d2 100644 (file)
@@ -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).
similarity index 87%
rename from docs/tutorial/application-configuration.md
rename to docs/en/docs/tutorial/application-configuration.md
index 706ecd3483b462977d412038a00b4f3b65fca7cd..978273cc1a2ea028de0c33f426de2bfe8be578b2 100644 (file)
@@ -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!}
 ```
similarity index 95%
rename from docs/tutorial/background-tasks.md
rename to docs/en/docs/tutorial/background-tasks.md
index 15b92e8f5ae0f910dfe7b0290cf4026dc460d134..3771eff7129a2e268bbaeb78b7f29c9d9138580b 100644 (file)
@@ -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.
similarity index 95%
rename from docs/tutorial/bigger-applications.md
rename to docs/en/docs/tutorial/bigger-applications.md
index f6c623b840b3ab8ab4be05fcb4a7da3e8cf8db70..0d3be0f16538c2d18e12050c8ddfbade8d166f49 100644 (file)
@@ -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:
similarity index 93%
rename from docs/tutorial/body-fields.md
rename to docs/en/docs/tutorial/body-fields.md
index f54ed4eb83f38fbf957991f8abb6f5bc79161582..daba2eaffa820c5484154e470596f94d0981af1c 100644 (file)
@@ -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 <a href="http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.5" class="external-link" target="_blank">JSON Schema example</a> 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:
similarity index 93%
rename from docs/tutorial/body-multiple-params.md
rename to docs/en/docs/tutorial/body-multiple-params.md
index 5009c21bfdb22976d1899b61f942b3d5c30167bf..6d5e6e39deed39e8ad68307e5ba6b6a5dcce4ac9 100644 (file)
@@ -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:
similarity index 90%
rename from docs/tutorial/body-nested-models.md
rename to docs/en/docs/tutorial/body-nested-models.md
index d5c5c95756e55f8d37b429b9a0c95771e462e731..993389c903c961d612caad67c94172482bb3d44b 100644 (file)
@@ -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 <a href="https://pydantic
 For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `HttpUrl`:
 
 ```Python hl_lines="4 10"
-{!./src/body_nested_models/tutorial005.py!}
+{!../../../docs_src/body_nested_models/tutorial005.py!}
 ```
 
 The string will be checked to be a valid URL, and documented in JSON Schema / OpenAPI as such.
@@ -131,7 +133,7 @@ The string will be checked to be a valid URL, and documented in JSON Schema / Op
 You can also use Pydantic models as subtypes of `list`, `set`, etc:
 
 ```Python hl_lines="20"
-{!./src/body_nested_models/tutorial006.py!}
+{!../../../docs_src/body_nested_models/tutorial006.py!}
 ```
 
 This will expect (convert, validate, document, etc) a JSON body like:
@@ -168,7 +170,7 @@ This will expect (convert, validate, document, etc) a JSON body like:
 You can define arbitrarily deeply nested models:
 
 ```Python hl_lines="9 14 20 23 27"
-{!./src/body_nested_models/tutorial007.py!}
+{!../../../docs_src/body_nested_models/tutorial007.py!}
 ```
 
 !!! info
@@ -185,7 +187,7 @@ images: List[Image]
 as in:
 
 ```Python hl_lines="15"
-{!./src/body_nested_models/tutorial008.py!}
+{!../../../docs_src/body_nested_models/tutorial008.py!}
 ```
 
 ## Editor support everywhere
@@ -217,7 +219,7 @@ That's what we are going to see here.
 In this case, you would accept any `dict` as long as it has `int` keys with `float` values:
 
 ```Python hl_lines="15"
-{!./src/body_nested_models/tutorial009.py!}
+{!../../../docs_src/body_nested_models/tutorial009.py!}
 ```
 
 !!! tip
similarity index 94%
rename from docs/tutorial/body-updates.md
rename to docs/en/docs/tutorial/body-updates.md
index b951f16fb846886e60a060523797c72fc8e42144..01620d88f7d4f7557753bc914bb9e992fbae3359 100644 (file)
@@ -1,3 +1,5 @@
+# Body - Updates
+
 ## Update replacing with `PUT`
 
 To update an item you can use the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a> operation.
@@ -5,7 +7,7 @@ To update an item you can use the <a href="https://developer.mozilla.org/en-US/d
 You can use the `jsonable_encoder` to convert the input data to data that can be stored as JSON (e.g. with a NoSQL database). For example, converting `datetime` to `str`.
 
 ```Python hl_lines="30 31 32 33 34 35"
-{!./src/body_updates/tutorial001.py!}
+{!../../../docs_src/body_updates/tutorial001.py!}
 ```
 
 `PUT` is used to receive data that should replace the existing data.
@@ -52,7 +54,7 @@ That would generate a `dict` with only the data that was set when creating the `
 Then you can use this to generate a `dict` with only the data that was set (sent in the request), omitting default values:
 
 ```Python hl_lines="34"
-{!./src/body_updates/tutorial002.py!}
+{!../../../docs_src/body_updates/tutorial002.py!}
 ```
 
 ### Using Pydantic's `update` parameter
@@ -62,7 +64,7 @@ Now, you can create a copy of the existing model using `.copy()`, and pass the `
 Like `stored_item_model.copy(update=update_data)`:
 
 ```Python hl_lines="35"
-{!./src/body_updates/tutorial002.py!}
+{!../../../docs_src/body_updates/tutorial002.py!}
 ```
 
 ### Partial updates recap
@@ -81,7 +83,7 @@ In summary, to apply partial updates you would:
 * Return the updated model.
 
 ```Python hl_lines="30 31 32 33 34 35 36 37"
-{!./src/body_updates/tutorial002.py!}
+{!../../../docs_src/body_updates/tutorial002.py!}
 ```
 
 !!! tip
similarity index 95%
rename from docs/tutorial/body.md
rename to docs/en/docs/tutorial/body.md
index 78b791c8a367b3c647e7f518396818340a972a33..25b1fb6ba07411f3a2aa468f6c73e6ff708130be 100644 (file)
@@ -1,3 +1,5 @@
+# Request Body
+
 When you need to send data from a client (let's say, a browser) to your API, you send it as a **request body**.
 
 A **request** body is data sent by the client to your API. A **response** body is the data your API sends to the client.
@@ -16,7 +18,7 @@ To declare a **request** body, you use <a href="https://pydantic-docs.helpmanual
 First, you need to import `BaseModel` from `pydantic`:
 
 ```Python hl_lines="2"
-{!./src/body/tutorial001.py!}
+{!../../../docs_src/body/tutorial001.py!}
 ```
 
 ## Create your data model
@@ -26,7 +28,7 @@ Then you declare your data model as a class that inherits from `BaseModel`.
 Use standard Python types for all the attributes:
 
 ```Python hl_lines="5 6 7 8 9"
-{!./src/body/tutorial001.py!}
+{!../../../docs_src/body/tutorial001.py!}
 ```
 
 The same as when declaring query parameters, when a model attribute has a default value, it is not required. Otherwise, it is required. Use `None` to make it just optional.
@@ -56,7 +58,7 @@ For example, this model above declares a JSON "`object`" (or Python `dict`) like
 To add it to your *path operation*, declare it the same way you declared path and query parameters:
 
 ```Python hl_lines="16"
-{!./src/body/tutorial001.py!}
+{!../../../docs_src/body/tutorial001.py!}
 ```
 
 ...and declare its type as the model you created, `Item`.
@@ -111,7 +113,7 @@ But you would get the same editor support with <a href="https://www.jetbrains.co
 Inside of the function, you can access all the attributes of the model object directly:
 
 ```Python hl_lines="19"
-{!./src/body/tutorial002.py!}
+{!../../../docs_src/body/tutorial002.py!}
 ```
 
 ## Request body + path parameters
@@ -121,7 +123,7 @@ You can declare path parameters and body requests at the same time.
 **FastAPI** will recognize that the function parameters that match path parameters should be **taken from the path**, and that function parameters that are declared to be Pydantic models should be **taken from the request body**.
 
 ```Python hl_lines="15 16"
-{!./src/body/tutorial003.py!}
+{!../../../docs_src/body/tutorial003.py!}
 ```
 
 ## Request body + path + query parameters
@@ -131,7 +133,7 @@ You can also declare **body**, **path** and **query** parameters, all at the sam
 **FastAPI** will recognize each of them and take the data from the correct place.
 
 ```Python hl_lines="16"
-{!./src/body/tutorial004.py!}
+{!../../../docs_src/body/tutorial004.py!}
 ```
 
 The function parameters will be recognized as follows:
similarity index 88%
rename from docs/tutorial/cookie-params.md
rename to docs/en/docs/tutorial/cookie-params.md
index 80999bc070e09caea82d20e11446c73d9fdbc1ab..658c52c4644bca321300ba13e5b8b6fdb489be47 100644 (file)
@@ -1,3 +1,5 @@
+# Cookie Parameters
+
 You can define Cookie parameters the same way you define `Query` and `Path` parameters.
 
 ## Import `Cookie`
@@ -5,7 +7,7 @@ You can define Cookie parameters the same way you define `Query` and `Path` para
 First import `Cookie`:
 
 ```Python hl_lines="1"
-{!./src/cookie_params/tutorial001.py!}
+{!../../../docs_src/cookie_params/tutorial001.py!}
 ```
 
 ## Declare `Cookie` parameters
@@ -15,7 +17,7 @@ Then declare the cookie parameters using the same structure as with `Path` and `
 The first value is the default value, you can pass all the extra validation or annotation parameters:
 
 ```Python hl_lines="7"
-{!./src/cookie_params/tutorial001.py!}
+{!../../../docs_src/cookie_params/tutorial001.py!}
 ```
 
 !!! note "Technical Details"
similarity index 98%
rename from docs/tutorial/cors.md
rename to docs/en/docs/tutorial/cors.md
index 868fc056aacc7ae334a7640483b20a0d84cdf4fd..1ebfec3619446fec565d393494c1aecd5e0b818c 100644 (file)
@@ -1,3 +1,5 @@
+# CORS (Cross-Origin Resource Sharing)
+
 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORS or "Cross-Origin Resource Sharing"</a> 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.
similarity index 97%
rename from docs/tutorial/debugging.md
rename to docs/en/docs/tutorial/debugging.md
index e527bf9712363ec0fc43a9f9a1770505e223930b..733ae32a17eac0a81c354f983862e0e06cf1a9c0 100644 (file)
@@ -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__"`
similarity index 93%
rename from docs/tutorial/dependencies/classes-as-dependencies.md
rename to docs/en/docs/tutorial/dependencies/classes-as-dependencies.md
index 674615410832ae0c6d44c393ea646dba8b765ed8..b4d78af84e4b4ebb4e5f1b49af3ee56124af1e88 100644 (file)
@@ -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.
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 7e774d5209ce180da1cb2fe1c55bf60ec5e0e5f7..64e03139c96adf03aac3721fe8c80c84adaf65ec 100644 (file)
@@ -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*
similarity index 96%
rename from docs/tutorial/dependencies/dependencies-with-yield.md
rename to docs/en/docs/tutorial/dependencies/dependencies-with-yield.md
index 08d600a5aee4de0df5f0cd137062af476a0cfc75..1c8cdba65a2a1e54840fa6e919f35aaac0999581 100644 (file)
@@ -1,4 +1,4 @@
-# Dependencies with `yield`
+# Dependencies with yield
 
 FastAPI supports dependencies that do some <abbr title='sometimes also called "exit", "cleanup", "teardown", "close", "context managers", ...'>extra steps after finishing</abbr>.
 
@@ -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
similarity index 97%
rename from docs/tutorial/dependencies/index.md
rename to docs/en/docs/tutorial/dependencies/index.md
index c92dcebf6d7b27687eca361ea9df76ac80319797..5b8d11ea765ae6c81838583ad38604be587e7dd3 100644 (file)
@@ -1,3 +1,5 @@
+# Dependencies - First Steps
+
 **FastAPI** has a very powerful but intuitive **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** 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.
similarity index 95%
rename from docs/tutorial/dependencies/sub-dependencies.md
rename to docs/en/docs/tutorial/dependencies/sub-dependencies.md
index 3407733808cce1cde7bd6607144d9baefd420d5a..71b1404d6f860d954baa8ea82cac860dcb30c050 100644 (file)
@@ -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
similarity index 95%
rename from docs/tutorial/encoder.md
rename to docs/en/docs/tutorial/encoder.md
index 4ce940eca12278c2940ebe0940473f4382c3cbd9..3879f976af6e17ac27d9edbbcc27a522aa801378 100644 (file)
@@ -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`.
similarity index 94%
rename from docs/tutorial/extra-data-types.md
rename to docs/en/docs/tutorial/extra-data-types.md
index 7534be86da81b4d1394886636fc582d33b2c094a..07c1ed06f792d0b5f068bbcf683a4d26ddd5e871 100644 (file)
@@ -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!}
 ```
similarity index 95%
rename from docs/tutorial/extra-models.md
rename to docs/en/docs/tutorial/extra-models.md
index 731a73f3d18e78f9f6a6b6182482e6e50cc5551b..5b8bf5a2b84ba3f066d5ee0594da41d70c02549d 100644 (file)
@@ -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 <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
 
 ```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
similarity index 95%
rename from docs/tutorial/first-steps.md
rename to docs/en/docs/tutorial/first-steps.md
index 639cfed395658185c5954244d78f524bfc8c0f68..2d212762ed8db3f344f81b3d943f45df14ce1a44 100644 (file)
@@ -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.
similarity index 95%
rename from docs/tutorial/handling-errors.md
rename to docs/en/docs/tutorial/handling-errors.md
index 8ae9ff47ea97b5ea52972d6cf939d4b4f18def34..99ecc2dc82990bb4f83fc46a0b023c3c8ab44da3 100644 (file)
@@ -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.
similarity index 92%
rename from docs/tutorial/header-params.md
rename to docs/en/docs/tutorial/header-params.md
index 46c349bd11ff0aec1203dea9eb65b24a0ed4c251..738d2a559ea90331f39ba5ed2310dc37fb880a59 100644 (file)
@@ -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:
similarity index 98%
rename from docs/tutorial/index.md
rename to docs/en/docs/tutorial/index.md
index ae073518ae4861a4232d1298258d498c2a9b35d0..8fb93ab2b67c81674f96b736891354705def8d6c 100644 (file)
@@ -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.
similarity index 96%
rename from docs/tutorial/middleware.md
rename to docs/en/docs/tutorial/middleware.md
index 5dd779189abc56ee255a091c7e7100f25352df4a..6f7ca000addf99397f043c846753d7a54e359619 100644 (file)
@@ -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
similarity index 88%
rename from docs/tutorial/path-operation-configuration.md
rename to docs/en/docs/tutorial/path-operation-configuration.md
index cfc970b7a90056a336d61b19f2e3d066b1d1532a..c2c30089441572e7034f9962291aa6f56315f120 100644 (file)
@@ -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 <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a> 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 <abbr title="obsolete, recommended not to use it">deprecated</abbr>, 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:
similarity index 89%
rename from docs/tutorial/path-params-numeric-validations.md
rename to docs/en/docs/tutorial/path-params-numeric-validations.md
index 5fe638f5f3351959f724ba0d34e02a4569906c55..9ae4c8b1a480b642bf70000262f6c2cc416241ab 100644 (file)
@@ -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 <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. 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 <abbr title="less than"><code>lt</code></abbr>.
 
 ```Python hl_lines="11"
-{!./src/path_params_numeric_validations/tutorial006.py!}
+{!../../../docs_src/path_params_numeric_validations/tutorial006.py!}
 ```
 
 ## Recap
similarity index 94%
rename from docs/tutorial/path-params.md
rename to docs/en/docs/tutorial/path-params.md
index b4c4054551a3b76cd60d25505b696f1027986033..1c32108bb6a3ef04ed216dd09c683df22bd90ea7 100644 (file)
@@ -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 <a href="http://127.0.0.1:8000/items/foo"
 You can declare the type of a path parameter in the function, using standard Python type annotations:
 
 ```Python hl_lines="7"
-{!./src/path_params/tutorial002.py!}
+{!../../../docs_src/path_params/tutorial002.py!}
 ```
 
 In this case, `item_id` is declared to be an `int`.
@@ -108,7 +110,7 @@ And then you can also have a path `/users/{user_id}` to get data about a specifi
 Because *path operations* are evaluated in order, you need to make sure that the path for `/users/me` is declared before the one for `/users/{user_id}`:
 
 ```Python hl_lines="6 11"
-{!./src/path_params/tutorial003.py!}
+{!../../../docs_src/path_params/tutorial003.py!}
 ```
 
 Otherwise, the path for `/users/{user_id}` would match also for `/users/me`, "thinking" that it's receiving a parameter `user_id` with a value of `"me"`.
@@ -126,7 +128,7 @@ By inheriting from `str` the API docs will be able to know that the values must
 And create class attributes with fixed values, those fixed values will be the available valid values:
 
 ```Python hl_lines="1 6 7 8 9"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
 ```
 
 !!! info
@@ -140,7 +142,7 @@ And create class attributes with fixed values, those fixed values will be the av
 Then create a *path parameter* with a type annotation using the enum class you created (`ModelName`):
 
 ```Python hl_lines="16"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
 ```
 
 ### Check the docs
@@ -158,7 +160,7 @@ The value of the *path parameter* will be an *enumeration member*.
 You can compare it with the *enumeration member* in your created enum `ModelName`:
 
 ```Python hl_lines="17"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
 ```
 
 #### Get the *enumeration value*
@@ -166,7 +168,7 @@ You can compare it with the *enumeration member* in your created enum `ModelName
 You can get the actual value (a `str` in this case) using `model_name.value`, or in general, `your_enum_member.value`:
 
 ```Python hl_lines="19"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
 ```
 
 !!! tip
@@ -179,7 +181,7 @@ You can return *enum members* from your *path operation*, even nested in a JSON
 They will be converted to their corresponding values before returning them to the client:
 
 ```Python hl_lines="18 20 21"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
 ```
 
 ## Path parameters containing paths
@@ -211,7 +213,7 @@ In this case, the name of the parameter is `file_path`, and the last part, `:pat
 So, you can use it with:
 
 ```Python hl_lines="6"
-{!./src/path_params/tutorial004.py!}
+{!../../../docs_src/path_params/tutorial004.py!}
 ```
 
 !!! tip
similarity index 87%
rename from docs/tutorial/query-params-str-validations.md
rename to docs/en/docs/tutorial/query-params-str-validations.md
index a2af2771419ebb6bab4d41245f0a363fdbac9d9b..abde56df4b9862c251ae6022195f9b1fc0d78a61 100644 (file)
@@ -1,9 +1,11 @@
+# Query Parameters and String Validations
+
 **FastAPI** allows you to declare additional information and validation for your parameters.
 
 Let's take this application as example:
 
 ```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial001.py!}
+{!../../../docs_src/query_params_str_validations/tutorial001.py!}
 ```
 
 The query parameter `q` is of type `str`, and by default is `None`, so it is optional.
@@ -17,7 +19,7 @@ We are going to enforce that even though `q` is optional, whenever it is provide
 To achieve that, first import `Query` from `fastapi`:
 
 ```Python hl_lines="1"
-{!./src/query_params_str_validations/tutorial002.py!}
+{!../../../docs_src/query_params_str_validations/tutorial002.py!}
 ```
 
 ## Use `Query` as the default value
@@ -25,7 +27,7 @@ To achieve that, first import `Query` from `fastapi`:
 And now use it as the default value of your parameter, setting the parameter `max_length` to 50:
 
 ```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial002.py!}
+{!../../../docs_src/query_params_str_validations/tutorial002.py!}
 ```
 
 As we have to replace the default value `None` with `Query(None)`, the first parameter to `Query` serves the same purpose of defining that default value.
@@ -57,7 +59,7 @@ This will validate the data, show a clear error when the data is not valid, and
 You can also add a parameter `min_length`:
 
 ```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial003.py!}
+{!../../../docs_src/query_params_str_validations/tutorial003.py!}
 ```
 
 ## Add regular expressions
@@ -65,7 +67,7 @@ You can also add a parameter `min_length`:
 You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> 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:
similarity index 92%
rename from docs/tutorial/query-params.md
rename to docs/en/docs/tutorial/query-params.md
index 5e72301105ad386637d9c128da319c6b8a580530..0efc57e1b87e1b8f7a94b9891fd7825b241f70c8 100644 (file)
@@ -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!}
 ```
similarity index 96%
rename from docs/tutorial/request-files.md
rename to docs/en/docs/tutorial/request-files.md
index b14f45c702f229d167dbe613d4b02e1bc6617fdc..260a5e1905aebf63617857e1a3fdce70a7e674d3 100644 (file)
@@ -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.
similarity index 88%
rename from docs/tutorial/request-forms-and-files.md
rename to docs/en/docs/tutorial/request-forms-and-files.md
index 51ba786386c0cab43ebf7f72d941f5b1477f72ed..6844f8c658f2bd0897e8c2494d5ffbee0e1721eb 100644 (file)
@@ -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.
similarity index 95%
rename from docs/tutorial/request-forms.md
rename to docs/en/docs/tutorial/request-forms.md
index edb9af64174ef44d304b627a5aa4c5f6d55e3f15..b5495a4005610480688181b95e5231f93b6ef4d6 100644 (file)
@@ -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.
similarity index 92%
rename from docs/tutorial/response-model.md
rename to docs/en/docs/tutorial/response-model.md
index 1f1288ca7c4d1451b04863b307af9f71dbf8db1f..3f06cd4d573b58ee98b81b24c0f50e7f08b1be37 100644 (file)
@@ -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
similarity index 94%
rename from docs/tutorial/response-status-code.md
rename to docs/en/docs/tutorial/response-status-code.md
index 3f77272de3f58b9f26d23430a0db77839975970b..29b8521fc737fc2ac9a96427f18f29316cd3e5b5 100644 (file)
@@ -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:
similarity index 97%
rename from docs/tutorial/security/first-steps.md
rename to docs/en/docs/tutorial/security/first-steps.md
index 6fef16235585cbe0341c884b2dd7c9ec9e4d6ac9..c14ec2ad984ff670f274e29fa41997632a615268 100644 (file)
@@ -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*.
similarity index 92%
rename from docs/tutorial/security/get-current-user.md
rename to docs/en/docs/tutorial/security/get-current-user.md
index e2d6b7924cacd495c09b47eb08f7f15a24f3b69e..3fc0164c3263fea5ddbc4639372e5ba9865241d1 100644 (file)
@@ -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
similarity index 99%
rename from docs/tutorial/security/index.md
rename to docs/en/docs/tutorial/security/index.md
index 96c941dd582976294c504df09fb2285231b0e410..9aed2adb5d3a56320b60cdb64c6febaaf66ea0ce 100644 (file)
@@ -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.
similarity index 97%
rename from docs/tutorial/security/oauth2-jwt.md
rename to docs/en/docs/tutorial/security/oauth2-jwt.md
index cd15cb9d293fc05a059856fb5f3f61881a096edb..18b4e0e300c1a3e285fbba1dfa96c269cb48d2fd 100644 (file)
@@ -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 <abbr title="JSON Web Tokens">JWT</abbr> 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`
similarity index 97%
rename from docs/tutorial/security/simple-oauth2.md
rename to docs/en/docs/tutorial/security/simple-oauth2.md
index d7507a1ec8183e48bc508d8267690ee2e579308a..c95c6aa6b62c6ddb5492df84c6392ff3b3dec382 100644 (file)
@@ -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
similarity index 95%
rename from docs/tutorial/sql-databases.md
rename to docs/en/docs/tutorial/sql-databases.md
index ba4b836483140d7997a3221a7a69a7783336241f..179e75f0a9ec6fb5c1449756f1346c37320bc921 100644 (file)
@@ -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 <a href="https://pydantic-docs.helpmanual.io/#config" class="external-link"
 In the `Config` class, set the attribute `orm_mode = True`.
 
 ```Python hl_lines="15 19 20 31 36 37"
-{!./src/sql_databases/sql_app/schemas.py!}
+{!../../../docs_src/sql_databases/sql_app/schemas.py!}
 ```
 
 !!! tip
@@ -365,7 +367,7 @@ Create utility functions to:
 * Read a single item.
 
 ```Python hl_lines="1 3 6 7 10 11 14 15 27 28"
-{!./src/sql_databases/sql_app/crud.py!}
+{!../../../docs_src/sql_databases/sql_app/crud.py!}
 ```
 
 !!! tip
@@ -383,7 +385,7 @@ The steps are:
 * `refresh` your instance (so that it contains any new data from the database, like the generated ID).
 
 ```Python hl_lines="18 19 20 21 22 23 24 31 32 33 34 35 36"
-{!./src/sql_databases/sql_app/crud.py!}
+{!../../../docs_src/sql_databases/sql_app/crud.py!}
 ```
 
 !!! tip
@@ -424,7 +426,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"
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
 ```
 
 #### Alembic Note
@@ -459,7 +461,7 @@ For that, we will create a new dependency with `yield`, as explained before in t
 Our dependency will create a new SQLAlchemy `SessionLocal` that will be used in a single request, and then close it once the request is finished.
 
 ```Python hl_lines="15 16 17 18 19 20"
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
 ```
 
 !!! info
@@ -476,7 +478,7 @@ And then, when using the dependency in a *path operation function*, we declare i
 This will then give us better editor support inside the *path operation function*, because the editor will know that the `db` parameter is of type `Session`:
 
 ```Python hl_lines="24  32  38  47  53"
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
 ```
 
 !!! info "Technical Details"
@@ -489,7 +491,7 @@ This will then give us better editor support inside the *path operation function
 Now, finally, here's the standard **FastAPI** *path operations* code.
 
 ```Python hl_lines="23 24 25 26 27 28  31 32 33 34  37 38 39 40 41 42  45 46 47 48 49  52 53 54 55"
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
 ```
 
 We are creating the database session before each request in the dependency with `yield`, and then closing it afterwards.
@@ -559,31 +561,31 @@ For example, in a background task worker with <a href="http://www.celeryproject.
 * `sql_app/database.py`:
 
 ```Python
-{!./src/sql_databases/sql_app/database.py!}
+{!../../../docs_src/sql_databases/sql_app/database.py!}
 ```
 
 * `sql_app/models.py`:
 
 ```Python
-{!./src/sql_databases/sql_app/models.py!}
+{!../../../docs_src/sql_databases/sql_app/models.py!}
 ```
 
 * `sql_app/schemas.py`:
 
 ```Python
-{!./src/sql_databases/sql_app/schemas.py!}
+{!../../../docs_src/sql_databases/sql_app/schemas.py!}
 ```
 
 * `sql_app/crud.py`:
 
 ```Python
-{!./src/sql_databases/sql_app/crud.py!}
+{!../../../docs_src/sql_databases/sql_app/crud.py!}
 ```
 
 * `sql_app/main.py`:
 
 ```Python
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
 ```
 
 ## Check it
@@ -634,7 +636,7 @@ A "middleware" is basically a function that is always executed for each request,
 The middleware we'll add (just a function) will create a new SQLAlchemy `SessionLocal` for each request, add it to the request and then close it once the request is finished.
 
 ```Python hl_lines="14 15 16 17 18 19 20 21 22"
-{!./src/sql_databases/sql_app/alt_main.py!}
+{!../../../docs_src/sql_databases/sql_app/alt_main.py!}
 ```
 
 !!! info
similarity index 96%
rename from docs/tutorial/static-files.md
rename to docs/en/docs/tutorial/static-files.md
index 0a1d639565344c207ea1db43b60ed14e3b8d0c88..dd239e6f0da5795e24b32406696b1b8fa4f85510 100644 (file)
@@ -1,3 +1,5 @@
+# Static Files
+
 You can serve static files automatically from a directory using `StaticFiles`.
 
 ## Install `aiofiles`
@@ -20,7 +22,7 @@ $ pip install aiofiles
 * "Mount" a `StaticFiles()` instance in a specific path.
 
 ```Python hl_lines="2 6"
-{!./src/static_files/tutorial001.py!}
+{!../../../docs_src/static_files/tutorial001.py!}
 ```
 
 !!! note "Technical Details"
similarity index 94%
rename from docs/tutorial/testing.md
rename to docs/en/docs/tutorial/testing.md
index 6733527728c94e87f71088076a4f49dbbf33075e..9296a20b7b2b0fc63768e5cfaa1064619fa21891 100644 (file)
@@ -1,3 +1,5 @@
+# Testing
+
 Thanks to <a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a>, testing **FastAPI** applications is easy and enjoyable.
 
 It is based on <a href="http://docs.python-requests.org" class="external-link" target="_blank">Requests</a>, 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 (file)
index 0000000..eb3b54e
--- /dev/null
@@ -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 (file)
index 0000000..11c9453
--- /dev/null
@@ -0,0 +1,437 @@
+<p align="center">
+  <a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
+</p>
+<p align="center">
+    <em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
+</p>
+<p align="center">
+<a href="https://travis-ci.com/tiangolo/fastapi" target="_blank">
+    <img src="https://travis-ci.com/tiangolo/fastapi.svg?branch=master" alt="Build Status">
+</a>
+<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
+    <img src="https://codecov.io/gh/tiangolo/fastapi/branch/master/graph/badge.svg" alt="Coverage">
+</a>
+<a href="https://pypi.org/project/fastapi" target="_blank">
+    <img src="https://badge.fury.io/py/fastapi.svg" alt="Package version">
+</a>
+<a href="https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank">
+    <img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Join the chat at https://gitter.im/tiangolo/fastapi">
+</a>
+</p>
+
+---
+
+**Documentation**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
+
+**Source Code**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>
+
+---
+
+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. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> 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: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
+
+<small>* estimation based on tests on an internal development team, building production applications.</small>
+
+## 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.*"
+
+<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+"*I’m over the moon excited about **FastAPI**. It’s so fun!*"
+
+<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+"*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.*"
+
+<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+"*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 [...]*"
+
+<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+"*We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]*"
+
+<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+## **Typer**, the FastAPI of CLIs
+
+<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
+
+If you are building a <abbr title="Command Line Interface">CLI</abbr> app to be used in the terminal instead of a web API, check out <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
+
+**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:
+
+* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> for the web parts.
+* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> for the data parts.
+
+## Installation
+
+<div class="termy">
+
+```console
+$ pip install fastapi
+
+---> 100%
+```
+
+</div>
+
+You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
+
+<div class="termy">
+
+```console
+$ pip install uvicorn
+
+---> 100%
+```
+
+</div>
+
+## 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}
+```
+
+<details markdown="1">
+<summary>Or use <code>async def</code>...</summary>
+
+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 <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
+
+</details>
+
+### Run it
+
+Run the server with:
+
+<div class="termy">
+
+```console
+$ uvicorn main:app --reload
+
+<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+<span style="color: green;">INFO</span>:     Started reloader process [28720]
+<span style="color: green;">INFO</span>:     Started server process [28722]
+<span style="color: green;">INFO</span>:     Waiting for application startup.
+<span style="color: green;">INFO</span>:     Application startup complete.
+```
+
+</div>
+
+<details markdown="1">
+<summary>About the command <code>uvicorn main:app --reload</code>...</summary>
+
+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.
+
+</details>
+
+### Check it
+
+Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
+
+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` <em>operations</em> (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 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
+
+You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
+
+![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
+
+### Alternative API docs
+
+And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
+
+You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
+
+![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 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
+
+* 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 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
+
+* 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.
+* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of input data: coming from the network to Python data and types. Reading from:
+    * JSON.
+    * Path parameters.
+    * Query parameters.
+    * Cookies.
+    * Headers.
+    * Forms.
+    * Files.
+* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> 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 <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - User Guide</a>.
+
+**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 **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** 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 <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
+
+To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
+
+## Optional Dependencies
+
+Used by Pydantic:
+
+* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
+* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
+
+Used by Starlette:
+
+* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
+* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
+* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
+* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
+* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
+* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
+* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - Required for `GraphQLApp` support.
+* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Required if you want to use `UJSONResponse`.
+
+Used by FastAPI / Starlette:
+
+* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
+* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - 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 (file)
index 0000000..8fb7cf4
--- /dev/null
@@ -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 (file)
index 0000000..32b6016
--- /dev/null
@@ -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/mkdocs.yml b/mkdocs.yml
deleted file mode 100644 (file)
index bacae9b..0000000
+++ /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'
index 58e53c3eec2f5c7e40e9122f501d836ca37b3fe8..eadff42bb8dde7041bbe1410aa4eeb2222ecfc6a 100644 (file)
@@ -64,7 +64,10 @@ test = [
 doc = [
     "mkdocs",
     "mkdocs-material",
-    "markdown-include"
+    "markdown-include",
+    "typer",
+    "typer-cli",
+    "pyyaml"
 ]
 dev = [
     "pyjwt",
index 4f4ae2f74e4034638161f7c5da452f25e2601e29..383ad3f4465c7628b7c4327ffbe4330eba1cd237 100755 (executable)
@@ -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 (file)
index 0000000..490f052
--- /dev/null
@@ -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()
index cfa66bbd46069b1c7e4a9f14c471e0425c7c3977..d2c0b7a5874a1ac8c67d3b96254c6af5fa655268 100755 (executable)
@@ -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
index c11eaf749483b5284f30fb24dd69fe71917403dc..bbcb04354b01afdf985ddf457f99ef9f0746b648 100755 (executable)
@@ -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
index d1a4cf630ee39dae6612bef9d873103e26b62a68..468b2c6674c83eb8da08151a12ab731b4c888ebd 100755 (executable)
@@ -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 ${@}
index 09a06d957771e19a6733c18cf20734cbe0ca6975..998070b3d66c4099bdd6a5d3a9265c4e48015cf6 100644 (file)
@@ -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"
index d1285c8ea2009eee2b2a5b82c149129521df0fcd..11f1227e45a68c47b71f6265a9a7b95b1eaec519 100644 (file)
@@ -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"
index 48d6456b49ad109d779904db036880ddf4669ebe..95c5b1ed36eabe03aebf4f9c9adaa9c8efa0c1e5 100644 (file)
@@ -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)