Compare commits

...

183 Commits

Author SHA1 Message Date
Sebastián Ramírez
e2fadcbc90 🔖 Release version 0.27.2 2019-06-03 22:03:24 +04:00
Sebastián Ramírez
b3bb29afa8 📝 Update relase notes 2019-06-03 22:01:09 +04:00
Sebastián Ramírez
c7db2ff858 🐛 Fix path and query parameters receiving dict as valid (#287)
* 🐛 Fix path and query parameters accepting dict

*  Add several tests to ensure invalid types are not accepted

* 📝 Document (to include tested source) using query params with list

* 🐛 Fix OpenAPI schema in query with list tutorial
2019-06-03 21:59:40 +04:00
Sebastián Ramírez
2a7ef5504a 🔖 Release 0.27.1 2019-06-03 18:44:03 +04:00
Sebastián Ramírez
27964c5ffd 📝 Update release notes 2019-06-01 10:00:26 +04:00
Sebastián Ramírez
d262f6e929 🐛 Fix HTTP Bearer security auto-error (#282) 2019-06-01 09:57:45 +04:00
Sebastián Ramírez
d61f5e4b55 📝 Update release notes 2019-05-30 19:43:32 +04:00
Sebastián Ramírez
3ed112e8a9 🐛 Fix type declaration of HTTPException (#279) 2019-05-30 19:43:02 +04:00
Sebastián Ramírez
9da626eb2c 🔖 Release version 0.27.0 2019-05-30 17:48:52 +04:00
Sebastián Ramírez
6f74c7327b 📝 Update release notes 2019-05-30 17:45:38 +04:00
dmontagu
360a2797c1 🐛 Fix docs link in oauth2-scopes.md (#275)
#274
2019-05-30 17:43:18 +04:00
Sebastián Ramírez
0552977cd6 📝 Update release notes 2019-05-30 17:41:40 +04:00
Sebastián Ramírez
bd407cc4ed Refactor param extraction using Pydantic Field (#278)
*  Refactor parameter dependency using Pydantic Field

* ⬆️ Upgrade required Pydantic version with latest Shape values

*  Add tutorials and code for using Enum and Optional

*  Add tests for tutorials with new types and extra cases

* ♻️ Format, clean, and add annotations to dependencies.utils

* 📝 Update tutorial for query parameters with list defaults

*  Add tests for query param with list default
2019-05-30 17:40:43 +04:00
Sebastián Ramírez
83b1a117cc 🔖 Release version 0.26.0 2019-05-29 19:29:44 +04:00
Sebastián Ramírez
2a1ff213a0 📝 Update release notes 2019-05-29 16:33:19 +04:00
Sebastián Ramírez
62af6e0eeb Separate Pydantic's ValidationError handler and improve docs for error handling (#273)
*  Implement separated ValidationError handlers and custom exceptions

*  Add tutorial source examples and tests

* 📝 Add docs for custom exception handlers

* 📝 Update docs section titles
2019-05-29 16:27:55 +04:00
Sebastián Ramírez
15da01af5c 📝 Update release notes 2019-05-29 13:46:27 +04:00
William Hayes
d544bdf092 📝 Update docs for paths in path params (#256) 2019-05-29 13:43:41 +04:00
Sebastián Ramírez
703ade7967 🐛 Fix path in path parameters (#272) 2019-05-29 13:34:46 +04:00
Sebastián Ramírez
58f135ba2f 📝 Update link in release notes 2019-05-29 11:51:43 +04:00
Sebastián Ramírez
713d374484 📝 Update release notes 2019-05-29 11:47:46 +04:00
Sebastián Ramírez
24e9ea28d3 Update testing docs, examples for testing POST, headers (#271) 2019-05-29 11:47:21 +04:00
Sebastián Ramírez
cae53138b2 📝 Update release notes 2019-05-27 21:56:49 +04:00
Sebastián Ramírez
a49d45eaa9 🐛 Fix response_model type to allow List[Model] (#266) 2019-05-27 21:56:20 +04:00
Sebastián Ramírez
3986f79029 🔖 Release version 0.25.0 2019-05-27 20:21:03 +04:00
Sebastián Ramírez
7379fde5ee 📝 Update release notes 2019-05-27 16:28:24 +04:00
Sebastián Ramírez
7b63bc5551 Add include, exclude, and by_alias to path operation methods (#264)
*  Make jsonable_encoder's include and exclude receive sequences

*  Add include, exclude, and by_alias to app and router

*  Add and update tutorial code with new parameters

* 📝 Update docs for new parameters and add docs for updating data

*  Add tests for consistency in path operation methods

*  Add tests for new parameters and update tests
2019-05-27 16:08:13 +04:00
Sebastián Ramírez
747ae8210f 📝 Update release notes 2019-05-25 19:48:27 +04:00
William Hayes
c651416e05 📝 Create CONTRIBUTING.md (#255) 2019-05-25 19:47:49 +04:00
Sebastián Ramírez
814f95e2bf 📝 Update release notes 2019-05-25 19:40:04 +04:00
William Hayes
d8716f94ae Add skip_defaults support for path operations (for #242) (#248) 2019-05-25 19:35:57 +04:00
Sebastián Ramírez
67f8cb3b4f 🔖 Release 0.24.0 2019-05-24 22:48:27 +04:00
Sebastián Ramírez
5c2828bd13 📝 Update release notes 2019-05-24 20:46:36 +04:00
James Kaplan
b087246f26 Add support for WebSockets with dependencies, params, etc #166 (#178) 2019-05-24 20:41:41 +04:00
Sebastián Ramírez
219d299426 📝 Update release notes 2019-05-23 11:04:13 +04:00
euri10
31da760729 ⬆️ Upgrade Pydantic to 0.26 (#247) 2019-05-23 11:03:53 +04:00
Sebastián Ramírez
fc89eb8f81 🔖 Release version 0.23.0 2019-05-21 23:26:28 +04:00
Sebastián Ramírez
6fca1041e9 📝 Update release notes 2019-05-21 23:05:46 +04:00
Sebastián Ramírez
9db1f5641b ⬆️ Upgrade Starlette to 0.12.0 (#243) 2019-05-21 22:59:48 +04:00
Sebastián Ramírez
c3beb56e63 📝 Update release notes 2019-05-21 22:46:22 +04:00
Steinthor Palsson
325edd5f00 Add swagger UI OAuth2 redirect page for implicit/code auth flows in API docs (#198) 2019-05-21 22:39:58 +04:00
Sebastián Ramírez
08322ef359 📝 Update release notes 2019-05-20 18:37:39 +04:00
Trim21
01b43e6e25 Make Swagger UI, ReDoc and OpenAPI handlers be coroutines to improve performance (#241) 2019-05-20 18:34:33 +04:00
Sebastián Ramírez
3cf92a156c 📝 Update release notes 2019-05-20 11:27:33 +04:00
euri10
f54d8d57a4 Make Swagger UI and ReDoc parameterizable to host offline assets for docs (#112) 2019-05-20 11:26:54 +04:00
Sebastián Ramírez
56ab106bbb 🔖 Release version 0.22.0 2019-05-16 18:09:11 +04:00
Sebastián Ramírez
e92b43b5c8 Add parameter dependencies to path operation decorators and include_router (#235)
*  Implement dependencies in decorator and .include_router

* 📝 Add docs for parameter dependencies

*  Add tests for dependencies parameter

* 🔥 Remove debugging prints in tests

* 📝 Update release notes
2019-05-16 18:07:00 +04:00
Sebastián Ramírez
7c50025c47 📝 Update release notes 2019-05-16 17:58:22 +04:00
euri10
adfbd27100 🐛 Fix OpenAPI URL format for Starlette convertors (#234) 2019-05-16 17:55:14 +04:00
Sebastián Ramírez
eada8bf7db 📝 Update release notes 2019-05-15 23:01:19 +04:00
Sebastián Ramírez
440b7a8efa 📝 Update relase notes 2019-05-15 22:14:25 +04:00
Sebastián Ramírez
fcaff64646 🔧 Separate format and lint scripts (#232) 2019-05-15 22:13:06 +04:00
Sebastián Ramírez
d240421378 📝 Add docs about params as functions for mypy (#231) 2019-05-15 22:01:23 +04:00
Sebastián Ramírez
ca27317b65 Add param functions, to override types, to make mypy happy (#226) 2019-05-15 21:25:11 +04:00
Sebastián Ramírez
ce02d3cb83 📝 Update release notes 2019-05-15 18:33:43 +04:00
Sebastián Ramírez
95475aaa9c 🔥 Remove Python version extraction in tests, no longer used 2019-05-15 18:33:13 +04:00
zamiramir
7a8b054a12 🎨 Reenable Black --check for Python 3.7 (#229)
Reenabled Black --check for python 3.7, issue is fixed.
see https://github.com/ambv/black/issues/494
2019-05-15 18:29:36 +04:00
Sebastián Ramírez
7b2993682f 🔖 Release 0.21.0 2019-05-15 14:54:46 +04:00
Sebastián Ramírez
73fad03b46 📝 Update release notes 2019-05-15 14:53:43 +04:00
Ricardo Momm
b0b88f9d5b 🔊 Raise from previous exception (#195) 2019-05-15 14:50:58 +04:00
Sebastián Ramírez
49d33f9f70 📝 Update release notes 2019-05-15 14:45:04 +04:00
Sebastián Ramírez
1f27981045 📝 Update release notes 2019-05-15 14:44:00 +04:00
euri10
f541d2c200 Use a logger instead of the root logging (#222) 2019-05-15 14:43:31 +04:00
euri10
0e99b23ebc ⬆️ Upgrade Pydantic to version 0.25 (#225) 2019-05-15 14:19:51 +04:00
Sebastián Ramírez
de341abe66 📝 Update release notes 2019-05-14 22:06:55 +04:00
Derek J. Lambert
4a1648b04e ✏️ Minor spelling fix in routing (#221) 2019-05-14 22:04:18 +04:00
Sebastián Ramírez
5f13b53ea5 🔧 Enable FastAPI releases bot in main Gitter channel 2019-05-11 19:44:39 +04:00
Sebastián Ramírez
5189c93d85 🔖 Release 0.20.1 2019-05-11 19:38:08 +04:00
Sebastián Ramírez
e612989313 📝 Update release notes 2019-05-11 13:46:17 +04:00
Steve B
d675991a34 add py.typed to ship typing information (#209)
As described in https://www.python.org/dev/peps/pep-0561/
2019-05-11 13:43:47 +04:00
Sebastián Ramírez
d03678dfbb 📝 Update release notes 2019-04-27 20:03:23 +04:00
Sebastián Ramírez
6ff89284c5 Add FastAPI releases bot for Gitter (#189)
* 🔥 Remove development util script

* 🎨 Reformat release notes with markdown-only code (no HTML)

*  Add FastAPI releases bot for Gitter
2019-04-27 20:02:32 +04:00
Sebastián Ramírez
7f673cf4e9 🔖 Release 0.20.0 2019-04-27 17:51:31 +04:00
Sebastián Ramírez
bac7230027 📝 Update release notes 2019-04-27 17:07:17 +04:00
Christopher Dignam
866af5bca6 ✏️ Fix typos in docs, from forms (#176) 2019-04-27 17:05:06 +04:00
Sebastián Ramírez
f4be79be51 📝 Update release notes 2019-04-27 17:04:00 +04:00
Sebastián Ramírez
3797c04946 Use 401 with WWW-Authenticate for OAuth2 and add scope_str (#188) 2019-04-27 17:00:56 +04:00
Sebastián Ramírez
9a9bfd7f93 📝 Update release notes 2019-04-26 19:28:54 +04:00
Sebastián Ramírez
ada1ecdb00 📝 Add Hypercorn as an alternative ASGI server (#187) 2019-04-26 19:26:38 +04:00
Sebastián Ramírez
3bbd38313b 📝 Update release notes 2019-04-26 19:08:04 +04:00
Sebastián Ramírez
c1df0f6b84 Add docs and tests for Jinja2 templates (#186)
*  Add docs and tests for Jinja2 templates

* 🎨 Fix format in test, remove unused import
2019-04-26 18:49:15 +04:00
Sebastián Ramírez
0cd5485597 📝 Update release notes 2019-04-26 15:17:32 +04:00
Sebastián Ramírez
528ef7e079 Docs and tests, responses with headers and cookies (#185) 2019-04-26 15:13:59 +04:00
Sebastián Ramírez
8e3a7699a3 🔖 Release 0.19.0 2019-04-26 13:48:30 +04:00
Sebastián Ramírez
8998ccaffb 📝 Update release notes 2019-04-26 13:45:38 +04:00
Sebastián Ramírez
2b7f201a44 📝 Add docs about returning a response directly and encoder (#184) 2019-04-26 13:40:23 +04:00
Sebastián Ramírez
192ebba2a2 ♻️ Rename parameter content_type to response_class (#183) 2019-04-26 13:11:16 +04:00
Sebastián Ramírez
8880c4cb03 🔖 Release 0.18.0 2019-04-22 21:08:43 +04:00
Sebastián Ramírez
6324be684f 📝 Update release notes 2019-04-21 22:31:43 +04:00
Sebastián Ramírez
c705685394 Add docs for HTTP Basic Auth and tests (#177) 2019-04-21 22:30:58 +04:00
Sebastián Ramírez
945f401d8e 📝 Update release notes 2019-04-21 21:46:00 +04:00
Sebastián Ramírez
f216d340ec Add automatic header handling for HTTP Basic Auth (#175)
*  Add automatic header handling for HTTP Basic Auth

* 🎨 Remove obsolete comment
2019-04-21 21:44:25 +04:00
Sebastián Ramírez
a4558e7053 📝 Update release notes 2019-04-21 20:21:53 +04:00
Sebastián Ramírez
298f8478e2 🔒 Fix development dependencies security (#174) 2019-04-21 20:20:25 +04:00
Sebastián Ramírez
b86d163470 📝 Rename additional response OpenAPI declarations 2019-04-21 20:13:26 +04:00
Sebastián Ramírez
9e2d37b89c 📝 Update release notes 2019-04-21 19:57:07 +04:00
Sebastián Ramírez
97adadd9e1 📝 Add docs for middleware (#173) 2019-04-21 19:56:20 +04:00
Sebastián Ramírez
26e3dffb37 🚀 Deploy when tagged using Python 3.6 2019-04-20 22:16:07 +04:00
Sebastián Ramírez
aa7b4bd101 🔖 0.17.0 2019-04-20 22:12:55 +04:00
Sebastián Ramírez
ffc4c716c0 🚀 Make Flit publish from CI (#170) 2019-04-20 22:09:35 +04:00
Sebastián Ramírez
ef7b6e8eaf 📝 Update Release Notes 2019-04-20 21:15:03 +04:00
Sebastián Ramírez
596243f4a5 Add docs about CORS (#169) 2019-04-20 21:13:01 +04:00
Sebastián Ramírez
766bf1c5aa 📝 Update release notes 2019-04-20 20:31:44 +04:00
Sebastián Ramírez
9e748dbca4 By default, encode by alias (#168) 2019-04-20 20:29:54 +04:00
Sebastián Ramírez
cefe6cf92c 🔖 Release version 0.16.0 2019-04-16 23:28:13 +04:00
Sebastián Ramírez
be3953499f 📝 Update release notes 2019-04-16 23:27:25 +04:00
Sebastián Ramírez
546d233dec ♻️ Update Pydantic usage, types, values, minor structure changes (#164) 2019-04-16 23:26:09 +04:00
Sebastián Ramírez
61dd36a945 Upgrade docstring Markdown parsing (#163)
*  Upgrade docstring Markdown parsing

* 📝 Update release notes
2019-04-16 22:49:18 +04:00
Sebastián Ramírez
27f9d55c3e 📝 Update release notes 2019-04-16 22:43:59 +04:00
euri10
906cc60f65 ⬆️ Upgrade Pydantic to 0.23 (#160)
* Add websocket to APIRouter

* Upgrade pydantic to v0.23.0

* Forgot pyproject.toml

* ⬆️ Upgrade some Pipfile.lock dependencies
2019-04-16 22:42:00 +04:00
Sebastián Ramírez
69afaf256f 📝 Update release notes 2019-04-16 22:21:32 +04:00
Daniel Michaels
4ab349a2a8 ✏️ fixed small typo /tutorial/extra-models.md (#159) 2019-04-16 22:20:03 +04:00
Sebastián Ramírez
9c258107b4 📝 Update release notes 2019-04-16 22:18:42 +04:00
hayata-yamamoto
29a4f90bcd 📝 fix URL examples in Tutorial: Query Parameters (#157)
* modify tutorial

* modify item_id
2019-04-16 22:16:16 +04:00
Sebastián Ramírez
361fd00777 📝 Add note about Swagger UI and multi-part uploads 2019-04-14 22:24:31 +04:00
Sebastián Ramírez
4c3cf31730 🔖 Release 0.15.0, multi-file uploads 2019-04-14 22:14:20 +04:00
Sebastián Ramírez
aad6b123f7 Add support for multi-file uploads (#158) 2019-04-14 22:12:14 +04:00
Sebastián Ramírez
e40e87c662 📝 Use same link in benchmarks as in index 2019-04-12 22:56:09 +04:00
Sebastián Ramírez
84de980977 Add docs about responses with additional status codes (#156)
*  Add docs about responses with additional status codes

* 📝 Update docs, link to documenting additional responses
2019-04-12 22:43:21 +04:00
Sebastián Ramírez
08484603ee 🔖 Release 0.14.0 2019-04-12 21:56:22 +04:00
Sebastián Ramírez
ab6dd60997 📝 Add note on installing and running pytest 2019-04-12 21:45:19 +04:00
Sebastián Ramírez
c9ef7bd6dc 📝 Update release notes 2019-04-12 21:27:24 +04:00
Sebastián Ramírez
88ece95a30 🎨 Improve automatic naming of path operations in API docs (#155)
* 🎨 Improve operation summary naming

* 📝 Update names in README

* 🚚 Improve names of security tutorial
2019-04-12 21:25:26 +04:00
Sebastián Ramírez
366c5db0bb 📝 Update release notes 2019-04-12 20:18:48 +04:00
Sebastián Ramírez
46e3811f8d Add testing docs and tests (#151)
* ✏️ Fix typo in security intro

*  Add testing docs and tests

* 🐛 Debug Travis coverage

* 🐛 Debug Travis coverage, report XML

* 💚 Make Travis/Flit use same code install

*  Revert Travis/Codecov debugging changes
2019-04-12 20:15:05 +04:00
Sebastián Ramírez
613e211d20 📝 Update release notes 2019-04-12 11:51:26 +04:00
William Hayes
500f2b2ad4 Add deeplinking to Swagger UI (#148)
Update the Swagger UI docs to deep link to path operations to share them more easily.
2019-04-12 11:49:32 +04:00
Sebastián Ramírez
5cf7718657 📝 Update release notes 2019-04-12 11:40:56 +04:00
Sebastián Ramírez
727b656c8d ⬆️ Update development dependencies, Pipfile.lock (#150) 2019-04-12 11:39:06 +04:00
Sebastián Ramírez
cc7102e9b8 📝 Add opinions in main page 2019-04-10 22:27:28 +04:00
Sebastián Ramírez
5123915fe4 📝 Include Hug and Falcon in Alternatives/Inspiration 2019-04-10 22:09:50 +04:00
Sebastián Ramírez
1b8bbd51d8 🔖 Release 0.13.0 2019-04-09 23:38:11 +04:00
Sebastián Ramírez
1e4f86db6d 📝 Update release notes and OAuth2 scopes docs 2019-04-09 23:36:18 +04:00
Sebastián Ramírez
7391056daf Add OAuth2 scopes with SecurityScopes, upgrade Security (#141)
*  Upgrade OAuth2 Security with scopes handling

* 📝 Update Security tutorial with OAuth2 and JWT

*  Add tutorial code for OAuth2 with scopes (and JWT)

*  Add tests for tutorial/OAuth2 with scopes

* 🐛 Fix security_scopes type declaration

*  Add docs and tests for SecurityScopes
2019-04-09 23:29:04 +04:00
Sebastián Ramírez
6a274d18b4 🔖 Release 0.12.1, fix responses in include_router 2019-04-05 20:08:36 +04:00
Sebastián Ramírez
62626b0175 📝 Update release notes 2019-04-05 20:08:00 +04:00
Sebastián Ramírez
c8df3ae57c 🐛 Fix handling additional responses in include_router (#140) 2019-04-05 20:06:40 +04:00
Sebastián Ramírez
6f7f9268f6 📝 Update release notes 2019-04-05 16:24:04 +04:00
Matthew McLeod
50653e205f 📝 Fix typo in SQL tutorial (#138) 2019-04-05 16:22:33 +04:00
Sebastián Ramírez
50a280b17b 📝 Update release notes 2019-04-05 16:21:17 +04:00
Mostapha Sadeghipour Roudsari
c1da3b38a3 📝 fix typos in nested models and OAuth2 with JWT (#127) 2019-04-05 16:08:59 +04:00
Sebastián Ramírez
e68a68c97c 🔖 Release 0.12.0, add additional responses 2019-04-05 14:35:01 +04:00
Sebastián Ramírez
907e613ff2 🔧 Update test-conv-html.sh to allow extra params 2019-04-05 14:29:36 +04:00
Sebastián Ramírez
f0fc2fad2c 📝 Update release notes 2019-04-05 14:28:30 +04:00
Sebastián Ramírez
ad471307e2 Additional Responses (#97)
Add additional responses to OpenAPI, including Pydantic models or schemas directly, custom status codes, media types, extending `response_model`, etc.
2019-04-05 14:18:28 +04:00
Sebastián Ramírez
2bd775988f Add/refactor addditional responses, tests, docs 2019-04-05 13:54:00 +04:00
Sebastián Ramírez
c59ddc8a24 🔖 Release 0.11.0 2019-04-03 15:51:44 +04:00
Sebastián Ramírez
378b39bbbc 📝 Update release notes 2019-04-03 15:49:58 +04:00
Sebastián Ramírez
37e0306517 📝 Update default error response in SQL tutorial 2019-04-03 15:49:40 +04:00
Sebastián Ramírez
fad3a9e1dc Add auto_error to security utils (#134)
to allow them to be optional, also allowing the declaration of multiple security schemes
2019-04-03 15:44:52 +04:00
Sebastián Ramírez
b35b0a9a90 📝 Update release notes 2019-03-31 22:05:03 +04:00
Alex Iribarren
1426b6200a 🗃️ Close the DB even if exceptions are raised (#89)
* Close the DB even if exceptions are raised

* 📝 Add note about closing DB in finally
2019-03-31 22:01:32 +04:00
Sebastián Ramírez
40e5f3764e 📝 Update release notes 2019-03-31 20:56:52 +04:00
Alif Jahan
e5c75807ce 🔥 removed duplicate dependency in pyproject.toml (#128) 2019-03-31 20:55:12 +04:00
Sebastián Ramírez
deff2b6678 🔖 Release 0.10.3 2019-03-30 21:54:00 +04:00
Sebastián Ramírez
7c572fdb3a 📝 Update release notes 2019-03-30 21:32:24 +04:00
Daniel Hahler
ae970638cf 👷 Set Travis to use dist=xenial and Python 3.7 instead of 3.7-dev (#92) 2019-03-30 21:30:31 +04:00
Sebastián Ramírez
deae92bba1 📝 Update release notes 2019-03-30 21:09:47 +04:00
yihuang
f806ba642a 🔥 Remove repeated param declaration (#123) 2019-03-30 21:07:41 +04:00
Sebastián Ramírez
5a3cf863da 📝 Update release notes 2019-03-30 19:55:01 +04:00
Sebastián Ramírez
dd6ab23b62 Add docs/tests extending OpenAPI (#126) 2019-03-30 19:53:44 +04:00
Sebastián Ramírez
0449499188 📝 Update release notes 2019-03-30 18:32:23 +04:00
The Gitter Badger
4dc7b32861 📝 Add a Gitter chat badge and links (#117)
* Add Gitter badge

* 📝 Add links and badges to Gitter chat
2019-03-30 18:30:02 +04:00
Sebastián Ramírez
08d849d5c5 📝 Update release notes 2019-03-29 19:06:02 +04:00
James Saunders
714e68b5f0 📝 Add note in response model docs: why not return type annotations (#109)
* Update response model documentation to explain design choice

Closes #101

* 📝 Update note about return function type annotation
2019-03-29 19:02:53 +04:00
Sebastián Ramírez
3d4f59f35a 📝 Udpate release notes 2019-03-29 18:43:40 +04:00
Stratos Gerakakis
3ce2920fef 🐛 fix name of shutdown_event in docs (#105)
Fix name copy/paste name error in docs source for startup/shutdown events.
2019-03-29 18:39:57 +04:00
Sebastián Ramírez
825f397918 🔖 Release 0.10.2 2019-03-29 15:17:34 +04:00
Sebastián Ramírez
b390e32372 📝 Update release notes 2019-03-29 15:16:56 +04:00
Sebastián Ramírez
b7d184363f 🐛 Fix JSON Schema of additional properties (#121)
#87
2019-03-29 15:15:49 +04:00
Sebastián Ramírez
2ddb804940 📝 Update release notes 2019-03-25 23:48:27 +04:00
Sebastián Ramírez
a2c9f666b5 📝 Add note about Celery in background tasks 2019-03-25 23:47:25 +04:00
Sebastián Ramírez
1594222e39 📝 Update Release Notes 2019-03-25 23:28:36 +04:00
Sebastián Ramírez
dc1e94d05f Document and test union and list response models (#108) 2019-03-25 23:28:09 +04:00
Mohammed
eda9b28338 files formatting 2019-03-23 13:10:45 +03:00
Mohammed
7514ac6fb0 100% test coverage 2019-03-23 13:01:53 +03:00
Mohammed
25fb4239cc increase test coverage 2019-03-23 01:13:09 +03:00
Mohammed
65568065e0 Remove extra code. 2019-03-23 00:47:32 +03:00
Mohammed
95679ca5e6 Fix: adding additional_responses on .include_router() 2019-03-23 00:37:10 +03:00
Mohammed
84a300ef84 Formatting according to guide 2019-03-22 22:54:48 +03:00
Mohammed
c6d28c8209 Accept Multiple Additional Responses 2019-03-22 22:50:47 +03:00
Mohammed
3984e9b8ac Additional Responses test 2019-03-22 22:40:46 +03:00
Mohammed
aa0bca7bb2 Additional Responses implementation 2019-03-22 22:40:07 +03:00
273 changed files with 10439 additions and 1133 deletions

View File

@@ -1,14 +1,16 @@
dist: xenial
language: python
cache: pip
python:
- "3.6"
- "3.7-dev"
- "3.7"
install:
- pip install flit
- flit install
- flit install --symlink
script:
- bash scripts/test.sh
@@ -18,6 +20,7 @@ after_script:
deploy:
provider: script
script: bash scripts/trigger-docker.sh
script: bash scripts/deploy.sh
on:
branch: master
tags: true
python: "3.6"

1
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1 @@
Please read the [Development - Contributing](https://fastapi.tiangolo.com/contributing/) guidelines in the documentation site.

View File

@@ -25,9 +25,10 @@ sqlalchemy = "*"
uvicorn = "*"
[packages]
starlette = "==0.11.1"
pydantic = "==0.21.0"
starlette = "==0.12.0"
pydantic = "==0.26.0"
databases = {extras = ["sqlite"],version = "*"}
hypercorn = "*"
[requires]
python_version = "3.6"

380
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "24b3b7b88d3cbe671ddbe296e64c15f8558f0e5d5df977200119872a363aac13"
"sha256": "4a33b47e814fa75533548874ffadbc6163b3058db4d1615ff633512366d72ccb"
},
"pipfile-spec": 6,
"requires": {
@@ -18,34 +18,33 @@
"default": {
"aiocontextvars": {
"hashes": [
"sha256:1e0ff5837c8b01c36a1107acdd0baf7853ebdf6c9fc43e8e311f4be37ac2038a",
"sha256:6ff7aee14f549d52f0446cbb84d0deddcd3fc677bcf8fbc2ce13f5756d2064dc"
"sha256:885daf8261818767d8f7cbd79f9d4482d118f024b6586ef6e67980236a27bfa3",
"sha256:f027372dc48641f683c559f247bd84962becaacdc9ba711d583c3871fb5652aa"
],
"markers": "python_version < '3.7'",
"version": "==0.2.1"
"version": "==0.2.2"
},
"aiosqlite": {
"hashes": [
"sha256:af4fed9e778756fa0ffffc7a8b14c4d7b1a57155dc5669f18e45107313f6019e"
"sha256:ad84fbd7516ca7065d799504fc41d6845c938e5306d1b7dd960caaeda12e22a9"
],
"version": "==0.9.0"
"version": "==0.10.0"
},
"contextvars": {
"hashes": [
"sha256:2341042e1c03a271813e07dba29b6b60fa85c1005ea5ed1638a076cf50b4d625"
"sha256:f38c908aaa59c14335eeea12abea5f443646216c4e29380d7bf34d2018e2c39e"
],
"markers": "python_version < '3.7'",
"version": "==2.3"
"version": "==2.4"
},
"databases": {
"extras": [
"sqlite"
],
"hashes": [
"sha256:4a0f15669c390a04b439972426350c0ae921ddc08c42bd54f125eb2fb86ee728"
"sha256:d365cff2035c5177ef5fd8c5abf6671da01189521da64848a01251c870daf48f"
],
"index": "pypi",
"version": "==0.2.0"
"version": "==0.2.2"
},
"dataclasses": {
"hashes": [
@@ -55,42 +54,104 @@
"markers": "python_version < '3.7'",
"version": "==0.6"
},
"h11": {
"hashes": [
"sha256:acca6a44cb52a32ab442b1779adf0875c443c689e9e028f8d831a3769f9c5208",
"sha256:f2b1ca39bfed357d1f19ac732913d5f9faa54a5062eca7d2ec3a916cfb7ae4c7"
],
"version": "==0.8.1"
},
"h2": {
"hashes": [
"sha256:c8f387e0e4878904d4978cd688a3195f6b169d49b1ffa572a3d347d7adc5e09f",
"sha256:fd07e865a3272ac6ef195d8904de92dc7b38dc28297ec39cfa22716b6d62e6eb"
],
"version": "==3.1.0"
},
"hpack": {
"hashes": [
"sha256:0edd79eda27a53ba5be2dfabf3b15780928a0dff6eb0c60a3d6767720e970c89",
"sha256:8eec9c1f4bfae3408a3f30500261f7e6a65912dc138526ea054f9ad98892e9d2"
],
"version": "==3.0.0"
},
"hypercorn": {
"hashes": [
"sha256:cfe7811a93ab7bc22c8a0d5514a2a7a512e812c1e4ee13b9731b705b79d4d453",
"sha256:f2577806223fa44d57d6f136b6c37a046794f961252699aec8afb15f35d226d5"
],
"index": "pypi",
"version": "==0.5.4"
},
"hyperframe": {
"hashes": [
"sha256:5187962cb16dcc078f23cb5a4b110098d546c3f41ff2d4038a9896893bbd0b40",
"sha256:a9f5c17f2cc3c719b917c4f33ed1c61bd1f8dfac4b1bd23b7c80b3400971b41f"
],
"version": "==5.2.0"
},
"immutables": {
"hashes": [
"sha256:1e4f4513254ef11e0230a558ee0dcb4551b914993c330005d15338da595d3750",
"sha256:228e38dc7a810ba4ff88909908ac47f840e5dc6c4c0da6b25009c626a9ae771c",
"sha256:2ae88fbfe1d04f4e5859c924e97313edf70e72b4f19871bf329b96a67ede9ba0",
"sha256:2d32b61c222cba1dd11f0faff67c7fb6204ef1982454e1b5b001d4b79966ef17",
"sha256:35af186bfac5b62522fdf2cab11120d7b0547f405aa399b6a1e443cf5f5e318c",
"sha256:63023fa0cceedc62e0d1535cd4ca7a1f6df3120a6d8e5c34e89037402a6fd809",
"sha256:6bf5857f42a96331fd0929c357dc0b36a72f339f3b6acaf870b149c96b141f69",
"sha256:7bb1590024a032c7a57f79faf8c8ff5e91340662550d2980e0177f67e66e9c9c",
"sha256:7c090687d7e623d4eca22962635b5e1a1ee2d6f9a9aca2f3fb5a184a1ffef1f2",
"sha256:bc36a0a8749881eebd753f696b081bd51145e4d77291d671d2e2f622e5b65d2f",
"sha256:d9fc6a236018d99af6453ead945a6bb55f98d14b1801a2c229dd993edc753a00"
"sha256:10861f2a2b86139f0c91d5073392d76117f37e84f912dc47c943c23a64008cc7",
"sha256:3e23eeb4bc55d57b2a97bef4c1a2891bbb731050b4167c855545797d45e84e45",
"sha256:4373876879f147986808f71e6ca02380192a279e8b8d45832f6fed4e7f717562",
"sha256:46f9122da033fecf84d7f4c6257aec780f370b20f3ce6bc521702b63ee3d99f7",
"sha256:5104db6102e53702af45c6b0af36e45a80970123b11a80c14e0fce48444cdbe3",
"sha256:59274bcb631f4fdc9731e9a4a96d16d96b3a17e29fd5e46516518f38406f678f",
"sha256:65a9c624e50ca5c50464dbf432996b5c4f056a411bcff5690ef4cab59f913f99",
"sha256:b64e0672497b884d21170ca61c693da8488d77f043650efa7911378cbbad0f2c",
"sha256:b70655dba00742b033310933066a2202e1cfbbb0f63841b4597cd8787974b242",
"sha256:c3d8c238a6f9b60355578579563773348674b6da63c1a0d7394384ed341f3d41",
"sha256:cd66bcd11b6a1c1a80fb8d90e25870ff2d5c705ab5eb9666355a33d3fef6ac70",
"sha256:d59310fc4f97c1ff8c3660cb98032db266ac0c285a86ca7a512e8e84a95f44c9",
"sha256:d71d1c822498646143270580dd6f743bb31ab89ae0ded8b2307c356d3a00f1c0",
"sha256:f53da698b42db83cfb1f5073560838051430798c8d8e34a57a27031edbc3041d",
"sha256:f958ba15745e30d3a38e3c9fcead8496037135bb21c78c0f925c104abba3a6fa",
"sha256:ff95e2aa618eed1a0ef4479938f18f3522c89562b9bbb59d677597c0337569dd"
],
"version": "==0.6"
"version": "==0.9"
},
"pydantic": {
"hashes": [
"sha256:93fa585402e7c8c01623ea8af6ca23363e8b4c6a020b7a2de9e99fa29d642d50",
"sha256:eb441dd50779347a450494c437db3ecbb13c1f3854497df879662782af516c5c"
"sha256:b72e0df2463cee746cf42639845d4106c19f30136375e779352d710e69617731",
"sha256:dab99d3070e040b8b2e987dfbe237350ab92d5d57a22d4e0e268ede2d85c7964"
],
"index": "pypi",
"version": "==0.21.0"
"version": "==0.26.0"
},
"pytoml": {
"hashes": [
"sha256:ca2d0cb127c938b8b76a9a0d0f855cf930c1d50cc3a0af6d3595b566519a1013"
],
"version": "==0.1.20"
},
"sqlalchemy": {
"hashes": [
"sha256:781fb7b9d194ed3fc596b8f0dd4623ff160e3e825dd8c15472376a438c19598b"
"sha256:91c54ca8345008fceaec987e10924bf07dcab36c442925357e5a467b36a38319"
],
"version": "==1.3.1"
"version": "==1.3.3"
},
"starlette": {
"hashes": [
"sha256:9d48b35d1fc7521d59ae53c421297ab3878d3c7cd4b75266d77f6c73cccb78bb"
"sha256:d313433ef5cc38e0a276b59688ca2b11b8f031c78808c1afdf9d55cb86f34590"
],
"index": "pypi",
"version": "==0.11.1"
"version": "==0.12.0"
},
"typing-extensions": {
"hashes": [
"sha256:07b2c978670896022a43c4b915df8958bec4a6b84add7f2c87b2b728bda3ba64",
"sha256:f3f0e67e1d42de47b5c67c32c9b26641642e9170fe7e292991793705cd5fef7c",
"sha256:fb2cd053238d33a8ec939190f30cfd736c00653a85a2919415cecf7dc3d9da71"
],
"version": "==3.7.2"
},
"wsproto": {
"hashes": [
"sha256:55c3da870460e8838b2fbe4d10f3accc0cea3a13d5e8dbbdc6da5d537d6d44dc",
"sha256:c7f35e0af250b9f25583b090039eb2159a079fbe71b7daf86cc3ddcd2f3a70b3"
],
"version": "==0.14.0"
}
},
"develop": {
@@ -117,10 +178,10 @@
},
"autoflake": {
"hashes": [
"sha256:c103e63466f11db3617167a2c68ff6a0cda35b940222920631c6eeec6b67e807"
"sha256:6b59e5b9b82e30077499578856282debb81186d10b4f899e8c2e1d616cdef973"
],
"index": "pypi",
"version": "==1.2"
"version": "==1.3"
},
"backcall": {
"hashes": [
@@ -175,37 +236,35 @@
},
"coverage": {
"hashes": [
"sha256:029c69deaeeeae1b15bc6c59f0ffa28aa8473721c614a23f2c2976dec245cd12",
"sha256:02abbbebc6e9d5abe13cd28b5e963dedb6ffb51c146c916d17b18f141acd9947",
"sha256:1bbfe5b82a3921d285e999c6d256c1e16b31c554c29da62d326f86c173d30337",
"sha256:210c02f923df33a8d0e461c86fdcbbb17228ff4f6d92609fc06370a98d283c2d",
"sha256:2d0807ba935f540d20b49d5bf1c0237b90ce81e133402feda906e540003f2f7a",
"sha256:35d7a013874a7c927ce997350d314144ffc5465faf787bb4e46e6c4f381ef562",
"sha256:3636f9d0dcb01aed4180ef2e57a4e34bb4cac3ecd203c2a23db8526d86ab2fb4",
"sha256:42f4be770af2455a75e4640f033a82c62f3fb0d7a074123266e143269d7010ef",
"sha256:48440b25ba6cda72d4c638f3a9efa827b5b87b489c96ab5f4ff597d976413156",
"sha256:4dac8dfd1acf6a3ac657475dfdc66c621f291b1b7422a939cc33c13ac5356473",
"sha256:4e8474771c69c2991d5eab65764289a7dd450bbea050bc0ebb42b678d8222b42",
"sha256:551f10ddfeff56a1325e5a34eff304c5892aa981fd810babb98bfee77ee2fb17",
"sha256:5b104982f1809c1577912519eb249f17d9d7e66304ad026666cb60a5ef73309c",
"sha256:5c62aef73dfc87bfcca32cee149a1a7a602bc74bac72223236b0023543511c88",
"sha256:633151f8d1ad9467b9f7e90854a7f46ed8f2919e8bc7d98d737833e8938fc081",
"sha256:772207b9e2d5bf3f9d283b88915723e4e92d9a62c83f44ec92b9bd0cd685541b",
"sha256:7d5e02f647cd727afc2659ec14d4d1cc0508c47e6cfb07aea33d7aa9ca94d288",
"sha256:a9798a4111abb0f94584000ba2a2c74841f2cfe5f9254709756367aabbae0541",
"sha256:b38ea741ab9e35bfa7015c93c93bbd6a1623428f97a67083fc8ebd366238b91f",
"sha256:b6a5478c904236543c0347db8a05fac6fc0bd574c870e7970faa88e1d9890044",
"sha256:c6248bfc1de36a3844685a2e10ba17c18119ba6252547f921062a323fb31bff1",
"sha256:c705ab445936457359b1424ef25ccc0098b0491b26064677c39f1d14a539f056",
"sha256:d95a363d663ceee647291131dbd213af258df24f41350246842481ec3709bd33",
"sha256:e27265eb80cdc5dab55a40ef6f890e04ecc618649ad3da5265f128b141f93f78",
"sha256:ebc276c9cb5d917bd2ae959f84ffc279acafa9c9b50b0fa436ebb70bbe2166ea",
"sha256:f4d229866d030863d0fe3bf297d6d11e6133ca15bbb41ed2534a8b9a3d6bd061",
"sha256:f95675bd88b51474d4fe5165f3266f419ce754ffadfb97f10323931fa9ac95e5",
"sha256:f95bc54fb6d61b9f9ff09c4ae8ff6a3f5edc937cda3ca36fc937302a7c152bf1",
"sha256:fd0f6be53de40683584e5331c341e65a679dbe5ec489a0697cec7c2ef1a48cda"
"sha256:0402b1822d513d0231589494bceddb067d20581f5083598c451b56c684b0e5d6",
"sha256:0644e28e8aea9d9d563607ee8b7071b07dd57a4a3de11f8684cd33c51c0d1b93",
"sha256:0874a283686803884ec0665018881130604956dbaa344f2539c46d82cbe29eda",
"sha256:0988c3837df4bc371189bb3425d5232cf150055452034c232dda9cbe04f9c38e",
"sha256:20bc3205b3100956bb72293fabb97f0ed972c81fed10b3251c90c70dcb0599ab",
"sha256:2cc9142a3367e74eb6b19d58c53ebb1dfd7336b91cdcc91a6a2888bf8c7af984",
"sha256:3ae9a0a59b058ce0761c3bd2c2d66ecb2ee2b8ac592620184370577f7a546fb3",
"sha256:3b2e30b835df58cb973f478d09f3d82e90c98c8e5059acc245a8e4607e023801",
"sha256:401e9b04894eb1498c639c6623ee78a646990ce5f095248e2440968aafd6e90e",
"sha256:41ec5812d5decdaa72708be3018e7443e90def4b5a71294236a4df192cf9eab9",
"sha256:475769b638a055e75b3d3219e054fe2a023c0b077ff15bff6c95aba7e93e6cac",
"sha256:61424f4e2e82c4129a4ba71e10ebacb32a9ecd6f80de2cd05bdead6ba75ed736",
"sha256:811969904d4dd0bee7d958898be8d9d75cef672d9b7e7db819dfeac3d20d2d0c",
"sha256:86224bb99abfd672bf2f9fcecad5e8d7a3fa94f7f71513f2210460a0350307cd",
"sha256:9a238a20a3af00665f8381f7e53e9c606f9bb652d2423f6b822f6cb790d887e8",
"sha256:a23b3fbc14d4e6182ecebfd22f3729beef0636d151d94764a1c28330d185e4e5",
"sha256:ac162b4ebe51b7a2b7f5e462c4402802633eb81e77c94f8a7c1ed8a556e72c75",
"sha256:b6187378726c84365bf297b5dcdae8789b6a5823b200bea23797777e5a63be09",
"sha256:bcd5723d905ed4a825f17410a53535f880b6d7548ae3d89078db7b1ceefcd853",
"sha256:c48a4f9c5fb385269bb7fbaf9c1326a94863b65ec7f5c96b2ea56b252f01ad08",
"sha256:cd40199d6f1c29c85b170d25589be9a97edff8ee7e62be180a2a137823896030",
"sha256:d1bc331a7d069485ac1d8c25a0ea1f6aab6cb2a87146fb652222481c1bddc9ff",
"sha256:d7e0cdc249aa0f94aa2e531b03999ddaf03a10b4fa090a894712d4c8066abd89",
"sha256:e9ee8fcd8e067fcc5d7276d46e07e863102b70a52545ef4254df1ff0893ce75f",
"sha256:eb313c23d983b7810504f42104e8dcd1c7ccdda8fbaab82aab92ab79fea19345",
"sha256:f9cfd478654b509941b85ed70f870f5e3c74678f566bec12fd26545e5340ba47",
"sha256:fae1fa144034d021a52cb9ea200eb8dedf91869c6df8202ad5d149b41ed91cc8"
],
"version": "==5.0a4"
"version": "==5.0a5"
},
"decorator": {
"hashes": [
@@ -216,10 +275,10 @@
},
"defusedxml": {
"hashes": [
"sha256:24d7f2f94f7f3cb6061acb215685e5125fbcdc40a857eff9de22518820b0a4f4",
"sha256:702a91ade2968a82beb0db1e0766a6a273f33d4616a6ce8cde475d8e09853b20"
"sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93",
"sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"
],
"version": "==0.5.0"
"version": "==0.6.0"
},
"dnspython": {
"hashes": [
@@ -238,10 +297,10 @@
},
"email-validator": {
"hashes": [
"sha256:ddc4b5b59fa699bb10127adcf7ad4de78fde4ec539a072b104b8bb16da666ae5"
"sha256:79966e318d6d68fed359c90f8f19d242bcc178b724011f1c07145bd093da6cc7"
],
"index": "pypi",
"version": "==1.0.3"
"version": "==1.0.4"
},
"entrypoints": {
"hashes": [
@@ -288,18 +347,18 @@
},
"ipykernel": {
"hashes": [
"sha256:0aeb7ec277ac42cc2b59ae3d08b10909b2ec161dc6908096210527162b53675d",
"sha256:0fc0bf97920d454102168ec2008620066878848fcfca06c22b669696212e292f"
"sha256:346189536b88859937b5f4848a6fd85d1ad0729f01724a411de5cae9b618819c",
"sha256:f0e962052718068ad3b1d8bcc703794660858f58803c3798628817f492a8769c"
],
"version": "==5.1.0"
"version": "==5.1.1"
},
"ipython": {
"hashes": [
"sha256:b038baa489c38f6d853a3cfc4c635b0cda66f2864d136fe8f40c1a6e334e2a6b",
"sha256:f5102c1cd67e399ec8ea66bcebe6e3968ea25a8977e53f012963e5affeb1fe38"
"sha256:54c5a8aa1eadd269ac210b96923688ccf01ebb2d0f21c18c3c717909583579a8",
"sha256:e840810029224b56cd0d9e7719dc3b39cf84d577f8ac686547c8ba7a06eeab26"
],
"markers": "python_version >= '3.3'",
"version": "==7.4.0"
"version": "==7.5.0"
},
"ipython-genutils": {
"hashes": [
@@ -317,11 +376,11 @@
},
"isort": {
"hashes": [
"sha256:08f8e3f0f0b7249e9fad7e5c41e2113aba44969798a26452ee790c06f155d4ec",
"sha256:4e9e9c4bd1acd66cf6c36973f29b031ec752cbfd991c69695e4e259f9a756927"
"sha256:c40744b6bc5162bbb39c1257fe298b7a393861d50978b565f3ccd9cb9de0182a",
"sha256:f57abacd059dc3bd666258d1efb0377510a89777fda3e3274e3c01f7c03ae22d"
],
"index": "pypi",
"version": "==4.3.16"
"version": "==4.3.20"
},
"jedi": {
"hashes": [
@@ -332,10 +391,10 @@
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
"sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013",
"sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"
],
"version": "==2.10"
"version": "==2.10.1"
},
"jsonschema": {
"hashes": [
@@ -376,17 +435,17 @@
},
"livereload": {
"hashes": [
"sha256:29cadfabcedd12eed792e0131991235b9d4764d4474bed75cf525f57109ec0a2",
"sha256:e632a6cd1d349155c1d7f13a65be873b38f43ef02961804a1bba8d817fa649a7"
"sha256:78d55f2c268a8823ba499305dcac64e28ddeb9a92571e12d543cd304faf5817b",
"sha256:89254f78d7529d7ea0a3417d224c34287ebfe266b05e67e51facaf82c27f0f66"
],
"version": "==2.6.0"
"version": "==2.6.1"
},
"markdown": {
"hashes": [
"sha256:c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa",
"sha256:d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c"
"sha256:2e50876bcdd74517e7b71f3e7a76102050edec255b3983403f1a63e7c8a41e7a",
"sha256:56a46ac655704b91e5b7e6326ce43d5ef72411376588afa1dd90e881b83c7e8c"
],
"version": "==3.0.1"
"version": "==3.1.1"
},
"markdown-include": {
"hashes": [
@@ -452,27 +511,36 @@
},
"mkdocs-material": {
"hashes": [
"sha256:0b394aa034b25a09a5874ae2a6ccc426fd81f5764e0991217b169e31cb0c1c0e",
"sha256:f5bb80a2c16d045d380edb2c5b05636af1bb709cb859bfaa9d01063a11df803f"
"sha256:1c39b6af13a900d9f47ab2b8ac67b3258799f4570b552573e9d6868ad6a438e9",
"sha256:22073941cff7176e810b719aced6a90381e64a96d346b8a6803a06b7192b7ad5"
],
"index": "pypi",
"version": "==4.1.0"
"version": "==4.3.0"
},
"more-itertools": {
"hashes": [
"sha256:0125e8f60e9e031347105eb1682cef932f5e97d7b9a1a28d9bf00c22a5daef40",
"sha256:590044e3942351a1bdb1de960b739ff4ce277960f2425ad4509446dbace8d9d1"
"sha256:2112d2ca570bb7c3e53ea1a35cd5df42bb0fd10c45f0fb97178679c3c03d64c7",
"sha256:c3e4748ba1aad8dba30a4886b0b1a2004f9a863837b8654e7059eebf727afa5a"
],
"markers": "python_version > '2.7'",
"version": "==6.0.0"
"version": "==7.0.0"
},
"mypy": {
"hashes": [
"sha256:308c274eb8482fbf16006f549137ddc0d69e5a589465e37b99c4564414363ca7",
"sha256:e80fd6af34614a0e898a57f14296d0dacb584648f0339c2e000ddbf0f4cc2f8d"
"sha256:2afe51527b1f6cdc4a5f34fc90473109b22bf7f21086ba3e9451857cf11489e6",
"sha256:56a16df3e0abb145d8accd5dbb70eba6c4bd26e2f89042b491faa78c9635d1e2",
"sha256:5764f10d27b2e93c84f70af5778941b8f4aa1379b2430f85c827e0f5464e8714",
"sha256:5bbc86374f04a3aa817622f98e40375ccb28c4836f36b66706cf3c6ccce86eda",
"sha256:6a9343089f6377e71e20ca734cd8e7ac25d36478a9df580efabfe9059819bf82",
"sha256:6c9851bc4a23dc1d854d3f5dfd5f20a016f8da86bcdbb42687879bb5f86434b0",
"sha256:b8e85956af3fcf043d6f87c91cbe8705073fc67029ba6e22d3468bfee42c4823",
"sha256:b9a0af8fae490306bc112229000aa0c2ccc837b49d29a5c42e088c132a2334dd",
"sha256:bbf643528e2a55df2c1587008d6e3bda5c0445f1240dfa85129af22ae16d7a9a",
"sha256:c46ab3438bd21511db0f2c612d89d8344154c0c9494afc7fbc932de514cf8d15",
"sha256:f7a83d6bd805855ef83ec605eb01ab4fa42bcef254b13631e451cbb44914a9b0"
],
"index": "pypi",
"version": "==0.670"
"version": "==0.701"
},
"mypy-extensions": {
"hashes": [
@@ -483,10 +551,10 @@
},
"nbconvert": {
"hashes": [
"sha256:302554a2e219bc0fc84f3edd3e79953f3767b46ab67626fdec16e38ba3f7efe4",
"sha256:5de8fb2284422272a1d45abc77c07b888127550a6d602ce619592a2b08a474ff"
"sha256:138381baa41d83584459b5cfecfc38c800ccf1f37d9ddd0bd440783346a4c39c",
"sha256:4a978548d8383f6b2cfca4a3b0543afb77bc7cb5a96e8b424337ab58c12da9bc"
],
"version": "==5.4.1"
"version": "==5.5.0"
},
"nbformat": {
"hashes": [
@@ -497,10 +565,10 @@
},
"notebook": {
"hashes": [
"sha256:18a98858c0331fb65a60f2ebb6439f8c0c4defd14ca363731b6cabc7f61624b4",
"sha256:cc027a62be0f7756e0ef3d2d98458c4d7f4b3566449fb1a05891207f5bd9a1bf"
"sha256:573e0ae650c5d76b18b6e564ba6d21bf321d00847de1d215b418acb64f056eb8",
"sha256:f64fa6624d2323fbef6210a621817d6505a45d0d4a9367f1843b20a38a4666ee"
],
"version": "==5.7.6"
"version": "==5.7.8"
},
"pandocfilters": {
"hashes": [
@@ -510,18 +578,18 @@
},
"parso": {
"hashes": [
"sha256:4580328ae3f548b358f4901e38c0578229186835f0fa0846e47369796dd5bcc9",
"sha256:68406ebd7eafe17f8e40e15a84b56848eccbf27d7c1feb89e93d8fca395706db"
"sha256:17cc2d7a945eb42c3569d4564cdf49bde221bc2b552af3eca9c1aad517dcdd33",
"sha256:2e9574cb12e7112a87253e14e2c380ce312060269d04bd018478a3c92ea9a376"
],
"version": "==0.3.4"
"version": "==0.4.0"
},
"pexpect": {
"hashes": [
"sha256:2a8e88259839571d1251d278476f3eec5db26deb73a70be5ed5dc5435e418aba",
"sha256:3fbd41d4caf27fa4a377bfd16fef87271099463e6fa73e92a52f92dfee5d425b"
"sha256:2094eefdfcf37a1fdbfb9aa090862c1a4878e5c7e0e7e7088bdb511c558e5cd1",
"sha256:9e2c1fd0e6ee3a49b28f95d4b33bc389c89b20af6a1255906e90ff1262ce62eb"
],
"markers": "sys_platform != 'win32'",
"version": "==4.6.0"
"version": "==4.7.0"
},
"pickleshare": {
"hashes": [
@@ -532,10 +600,10 @@
},
"pluggy": {
"hashes": [
"sha256:19ecf9ce9db2fce065a7a0586e07cfb4ac8614fe96edf628a264b1c70116cf8f",
"sha256:84d306a647cc805219916e62aab89caa97a33a1dd8c342e87a37f91073cd4746"
"sha256:25a1bc1d148c9a640211872b4ff859878d422bccb59c9965e04eed468a0aa180",
"sha256:964cedd2b27c492fbf0b7f58b3284a09cf7f99b0f715941fb24a439b3af1bd1a"
],
"version": "==0.9.0"
"version": "==0.11.0"
},
"prometheus-client": {
"hashes": [
@@ -582,10 +650,10 @@
},
"pygments": {
"hashes": [
"sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a",
"sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"
"sha256:31cba6ffb739f099a85e243eff8cb717089fdd3c7300767d9fc34cb8e1b065f5",
"sha256:5ad302949b3c98dd73f8d9fcdc7e9cb592f120e32a18e23efd7f3dc51194472b"
],
"version": "==2.3.1"
"version": "==2.4.0"
},
"pymdown-extensions": {
"hashes": [
@@ -596,25 +664,25 @@
},
"pyrsistent": {
"hashes": [
"sha256:3ca82748918eb65e2d89f222b702277099aca77e34843c5eb9d52451173970e2"
"sha256:16692ee739d42cf5e39cef8d27649a8c1fdb7aa99887098f1460057c5eb75c3a"
],
"version": "==0.14.11"
"version": "==0.15.2"
},
"pytest": {
"hashes": [
"sha256:592eaa2c33fae68c7d75aacf042efc9f77b27c08a6224a4f59beab8d9a420523",
"sha256:ad3ad5c450284819ecde191a654c09b0ec72257a2c711b9633d677c71c9850c4"
"sha256:1a8aa4fa958f8f451ac5441f3ac130d9fc86ea38780dd2715e6d5c5882700b24",
"sha256:b8bf138592384bd4e87338cb0f256bf5f615398a649d4bd83915f0e4047a5ca6"
],
"index": "pypi",
"version": "==4.3.1"
"version": "==4.5.0"
},
"pytest-cov": {
"hashes": [
"sha256:0ab664b25c6aa9716cbf203b17ddb301932383046082c081b9848a0edf5add33",
"sha256:230ef817450ab0699c6cc3c9c8f7a829c34674456f2ed8df1fe1d39780f7c87f"
"sha256:2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6",
"sha256:e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a"
],
"index": "pypi",
"version": "==2.6.1"
"version": "==2.7.1"
},
"python-dateutil": {
"hashes": [
@@ -684,18 +752,18 @@
},
"qtconsole": {
"hashes": [
"sha256:1ac4a65e81a27b0838330a6d351c2f8435d4013d98a95373e8a41119b2968390",
"sha256:bc1ba15f50c29ed50f1268ad823bb6543be263c18dd093b80495e9df63b003ac"
"sha256:a667558c7b1e1442a2e5bcef1686c55e096efd0b58d8b2a0a8415f4579991ee3",
"sha256:fdfc6002d9d2834c88f9c92e0f6f590284ff3740fa53016f188a62d58bcca6d8"
],
"version": "==4.4.3"
"version": "==4.4.4"
},
"requests": {
"hashes": [
"sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
"sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
],
"index": "pypi",
"version": "==2.21.0"
"version": "==2.22.0"
},
"send2trash": {
"hashes": [
@@ -713,16 +781,16 @@
},
"sqlalchemy": {
"hashes": [
"sha256:781fb7b9d194ed3fc596b8f0dd4623ff160e3e825dd8c15472376a438c19598b"
"sha256:91c54ca8345008fceaec987e10924bf07dcab36c442925357e5a467b36a38319"
],
"version": "==1.3.1"
"version": "==1.3.3"
},
"terminado": {
"hashes": [
"sha256:55abf9ade563b8f9be1f34e4233c7b7bde726059947a593322e8a553cc4c067a",
"sha256:65011551baff97f5414c67018e908110693143cfbaeb16831b743fe7cad8b927"
"sha256:d9d012de63acb8223ac969c17c3043337c2fcfd28f3aea1ee429b345d01ef460",
"sha256:de08e141f83c3a0798b050ecb097ab6259c3f0331b2f7b7750c9075ced2c20c2"
],
"version": "==0.8.1"
"version": "==0.8.2"
},
"testpath": {
"hashes": [
@@ -759,27 +827,27 @@
},
"typed-ast": {
"hashes": [
"sha256:035a54ede6ce1380599b2ce57844c6554666522e376bd111eb940fbc7c3dad23",
"sha256:037c35f2741ce3a9ac0d55abfcd119133cbd821fffa4461397718287092d9d15",
"sha256:049feae7e9f180b64efacbdc36b3af64a00393a47be22fa9cb6794e68d4e73d3",
"sha256:19228f7940beafc1ba21a6e8e070e0b0bfd1457902a3a81709762b8b9039b88d",
"sha256:2ea681e91e3550a30c2265d2916f40a5f5d89b59469a20f3bad7d07adee0f7a6",
"sha256:3a6b0a78af298d82323660df5497bcea0f0a4a25a0b003afd0ce5af049bd1f60",
"sha256:5385da8f3b801014504df0852bf83524599df890387a3c2b17b7caa3d78b1773",
"sha256:606d8afa07eef77280c2bf84335e24390055b478392e1975f96286d99d0cb424",
"sha256:69245b5b23bbf7fb242c9f8f08493e9ecd7711f063259aefffaeb90595d62287",
"sha256:6f6d839ab09830d59b7fa8fb6917023d8cb5498ee1f1dbd82d37db78eb76bc99",
"sha256:730888475f5ac0e37c1de4bd05eeb799fdb742697867f524dc8a4cd74bcecc23",
"sha256:9819b5162ffc121b9e334923c685b0d0826154e41dfe70b2ede2ce29034c71d8",
"sha256:9e60ef9426efab601dd9aa120e4ff560f4461cf8442e9c0a2b92548d52800699",
"sha256:af5fbdde0690c7da68e841d7fc2632345d570768ea7406a9434446d7b33b0ee1",
"sha256:b64efdbdf3bbb1377562c179f167f3bf301251411eb5ac77dec6b7d32bcda463",
"sha256:bac5f444c118aeb456fac1b0b5d14c6a71ea2a42069b09c176f75e9bd4c186f6",
"sha256:bda9068aafb73859491e13b99b682bd299c1b5fd50644d697533775828a28ee0",
"sha256:d659517ca116e6750101a1326107d3479028c5191f0ecee3c7203c50f5b915b0",
"sha256:eddd3fb1f3e0f82e5915a899285a39ee34ce18fd25d89582bc89fc9fb16cd2c6"
"sha256:132eae51d6ef3ff4a8c47c393a4ef5ebf0d1aecc96880eb5d6c8ceab7017cc9b",
"sha256:18141c1484ab8784006c839be8b985cfc82a2e9725837b0ecfa0203f71c4e39d",
"sha256:2baf617f5bbbfe73fd8846463f5aeafc912b5ee247f410700245d68525ec584a",
"sha256:3d90063f2cbbe39177e9b4d888e45777012652d6110156845b828908c51ae462",
"sha256:4304b2218b842d610aa1a1d87e1dc9559597969acc62ce717ee4dfeaa44d7eee",
"sha256:4983ede548ffc3541bae49a82675996497348e55bafd1554dc4e4a5d6eda541a",
"sha256:5315f4509c1476718a4825f45a203b82d7fdf2a6f5f0c8f166435975b1c9f7d4",
"sha256:6cdfb1b49d5345f7c2b90d638822d16ba62dc82f7616e9b4caa10b72f3f16649",
"sha256:7b325f12635598c604690efd7a0197d0b94b7d7778498e76e0710cd582fd1c7a",
"sha256:8d3b0e3b8626615826f9a626548057c5275a9733512b137984a68ba1598d3d2f",
"sha256:8f8631160c79f53081bd23446525db0bc4c5616f78d04021e6e434b286493fd7",
"sha256:912de10965f3dc89da23936f1cc4ed60764f712e5fa603a09dd904f88c996760",
"sha256:b010c07b975fe853c65d7bbe9d4ac62f1c69086750a574f6292597763781ba18",
"sha256:c908c10505904c48081a5415a1e295d8403e353e0c14c42b6d67f8f97fae6616",
"sha256:c94dd3807c0c0610f7c76f078119f4ea48235a953512752b9175f9f98f5ae2bd",
"sha256:ce65dee7594a84c466e79d7fb7d3303e7295d16a83c22c7c4037071b059e2c21",
"sha256:eaa9cfcb221a8a4c2889be6f93da141ac777eb8819f077e1d09fb12d00a09a93",
"sha256:f3376bc31bad66d46d44b4e6522c5c21976bf9bca4ef5987bb2bf727f4506cbb",
"sha256:f9202fa138544e13a4ec1a6792c35834250a85958fde1251b6a22e07d1260ae7"
],
"version": "==1.3.1"
"version": "==1.3.5"
},
"ujson": {
"hashes": [
@@ -790,17 +858,17 @@
},
"urllib3": {
"hashes": [
"sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
"sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"
"sha256:a53063d8b9210a7bdec15e7b272776b9d42b2fd6816401a0d43006ad2f9902db",
"sha256:d363e3607d8de0c220d31950a8f38b18d5ba7c0830facd71a1c6b1036b7ce06c"
],
"version": "==1.24.1"
"version": "==1.25.2"
},
"uvicorn": {
"hashes": [
"sha256:d700b65169820fc260f39402b7f966c178691daaa40cb376cad99d7cd737f772"
"sha256:c10da7a54a6552279870900c881a2f1726314e2dd6270d4d3f9251683c643783"
],
"index": "pypi",
"version": "==0.7.0b1"
"version": "==0.7.1"
},
"uvloop": {
"hashes": [

View File

@@ -14,6 +14,9 @@
<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>
---
@@ -40,6 +43,28 @@ The key features are:
<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>
---
"*Im over the moon excited about **FastAPI**. Its 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>
---
## Requirements
@@ -57,7 +82,7 @@ FastAPI stands on the shoulders of giants:
$ pip install fastapi
```
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" target="_blank">uvicorn</a>.
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" target="_blank">Hypercorn</a>.
```bash
$ pip install uvicorn
@@ -195,7 +220,7 @@ def read_item(item_id: int, q: str = None):
@app.put("/items/{item_id}")
def create_item(item_id: int, item: Item):
def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```

View File

@@ -236,6 +236,19 @@ It was one of the first extremely fast Python frameworks based on `asyncio`. It
That's why **FastAPI** is based on Starlette, as it is the fastest framework available (tested by third-party benchmarks).
### <a href="https://falconframework.org/" target="_blank">Falcon</a>
Falcon is another high performance Python framework, it is designed to be minimal, and work as the foundation of other frameworks like Hug.
It uses the previous standard for Python web frameworks (WSGI) which is synchronous, so it can't handle Websockets and other use cases. Nevertheless, it also has a very good performance.
It is designed to have functions that receive two parameters, one "request" and one "response". Then you "read" parts from the request, and "write" parts to the response. Because of this design, it is not possible to declare request parameters and bodies with standard Python type hints as function parameters.
So, data validation, serialization, and documentation, have to be done in code, not automatically. Or they have to be implemented as a framework on top of Falcon, like Hug. This same distinction happens in other frameworks that are inspired by Falcon's design, of having one request object and one response object as parameters.
!!! check "Inspired **FastAPI** to"
Find ways to get great performance.
### <a href="https://moltenframework.com/" target="_blank">Molten</a>
I discovered Molten in the first stages of building **FastAPI**. And it has quite similar ideas:
@@ -257,11 +270,34 @@ Routes are declared in a single place, using functions declared in other places
This actually inspired updating parts of Pydantic, to support the same validation declaration style (all this functionality is now already available in Pydantic).
### <a href="http://www.hug.rest/" target="_blank">Hug</a>
Hug was one of the first frameworks to implement the declaration of API parameter types using Python type hints. This was a great idea that inspired other tools to do the same.
It used custom types in its declarations instead of standard Python types, but it was still a huge step forward.
It also was one of the first frameworks to generate a custom schema declaring the whole API in JSON.
It was not based on a standard like OpenAPI and JSON Schema. So it wouldn't be straightforward to integrate it with other tools, like Swagger UI. But again, it was a very innovative idea.
It has an interesting, uncommon feature: using the same framework, it's possible to create APIs and also CLIs.
As it is based on the previous standard for synchronous Python web frameworks (WSGI), it can't handle Websockets and other things, although it still has high performance too.
!!! info
Hug was created by Timothy Crosley, the same creator of <a href="https://github.com/timothycrosley/isort" target="_blank">`isort`</a>, a great tool to automatically sort imports in Python files.
!!! check "Ideas inspired in **FastAPI**"
Hug inspired parts of APIStar, and was one of the tools I found most promising, alongside APIStar.
Hug helped inspiring **FastAPI** to use Python type hints to declare parameters, and to generate a schema defining the API automatically.
### <a href="https://github.com/encode/apistar" target="_blank">APIStar</a> (<= 0.5)
Right before deciding to build **FastAPI** I found **APIStar** server. It had almost everything I was looking for and had a great design.
It was actually the first implementation of a framework using Python type hints to declare parameters and requests that I ever saw (before NestJS and Molten).
It was one of the first implementations of a framework using Python type hints to declare parameters and requests that I ever saw (before NestJS and Molten). I found it more or less at the same time as Hug. But APIStar used the OpenAPI standard.
It had automatic data validation, data serialization and OpenAPI schema generation based on the same type hints in several places.

View File

@@ -1,4 +1,4 @@
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=a979de55-980d-4721-a46f-77298b3f3923&hw=ph&test=fortune&l=zijzen-7" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
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" 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.

View File

@@ -1,4 +1,4 @@
It is recommended to use <a href="https://www.docker.com/" target="_blank">**Docker**</a> for security, replicability, development simplicity, etc.
You can use <a href="https://www.docker.com/" target="_blank">**Docker**</a> for deployment. It has several advantages like security, replicability, development simplicity, etc.
In this section you'll see instructions and links to guides to know how to:
@@ -237,7 +237,21 @@ The generated project has instructions to deploy it, doing it takes other 2 min.
You can deploy **FastAPI** directly without Docker too.
You just need to install <a href="https://www.uvicorn.org/" target="_blank">Uvicorn</a> (or any other ASGI server).
You just need to install an ASGI compatible server like:
* <a href="https://www.uvicorn.org/" target="_blank">Uvicorn</a>, a lightning-fast ASGI server, built on uvloop and httptools.
```bash
pip install uvicorn
```
* <a href="https://gitlab.com/pgjones/hypercorn" target="_blank">Hypercorn</a>, an ASGI server also compatible with HTTP/2.
```bash
pip install hypercorn
```
...or any other ASGI server.
And run your application the same way you have done in the tutorials, but without the `--reload` option, e.g.:
@@ -245,9 +259,15 @@ And run your application the same way you have done in the tutorials, but withou
uvicorn main:app --host 0.0.0.0 --port 80
```
or with Hypercorn:
```bash
hypercorn main:app --bind 0.0.0.0:80
```
You might want to set up some tooling to make sure it is restarted automatically if it stops.
You might also want to install <a href="https://gunicorn.org/" target="_blank">Gunicorn</a> and <a href="https://www.uvicorn.org/#running-with-gunicorn" target="_blank">use it as a manager for Uvicorn</a>.
You might also want to install <a href="https://gunicorn.org/" target="_blank">Gunicorn</a> and <a href="https://www.uvicorn.org/#running-with-gunicorn" target="_blank">use it as a manager for Uvicorn</a>, or use Hypercorn with multiple workers.
Making sure to fine-tune the number of workers, etc.

View File

@@ -24,6 +24,15 @@ There you can select "Releases only".
Doing it, you will receive notifications (in your email) whenever there's a new release (a new version) of **FastAPI** with bug fixes and new features.
## Join the chat
<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>
Join the chat on Gitter: <a href="https://gitter.im/tiangolo/fastapi" target="_blank">https://gitter.im/tiangolo/fastapi</a>.
There you can ask quick questions, help others, share ideas, etc.
## Connect with the author

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 90 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -14,6 +14,9 @@
<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>
---
@@ -40,6 +43,28 @@ The key features are:
<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>
---
"*Im over the moon excited about **FastAPI**. Its 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>
---
## Requirements
@@ -57,7 +82,7 @@ FastAPI stands on the shoulders of giants:
$ pip install fastapi
```
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" target="_blank">uvicorn</a>.
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" target="_blank">Hypercorn</a>.
```bash
$ pip install uvicorn
@@ -195,7 +220,7 @@ def read_item(item_id: int, q: str = None):
@app.put("/items/{item_id}")
def create_item(item_id: int, item: Item):
def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```

View File

@@ -1,133 +1,397 @@
## Next release
## Latest changes
## 0.27.2
* Fix path and query parameters receiving `dict` as a valid type. It should be mapped to a body payload. PR [#287](https://github.com/tiangolo/fastapi/pull/287). Updated docs at: [Query parameter list / multiple values with defaults: Using `list`](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#using-list).
## 0.27.1
* Fix `auto_error=False` handling in `HTTPBearer` security scheme. Do not `raise` when there's an incorrect `Authorization` header if `auto_error=False`. PR [#282](https://github.com/tiangolo/fastapi/pull/282).
* Fix type declaration of `HTTPException`. PR [#279](https://github.com/tiangolo/fastapi/pull/279).
## 0.27.0
* Fix broken link in docs about OAuth 2.0 with scopes. PR [#275](https://github.com/tiangolo/fastapi/pull/275) by [@dmontagu](https://github.com/dmontagu).
* Refactor param extraction using Pydantic `Field`:
* Large refactor, improvement, and simplification of param extraction from *path operations*.
* Fix/add support for list *query parameters* with list defaults. New documentation: [Query parameter list / multiple values with defaults](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#query-parameter-list-multiple-values-with-defaults).
* Add support for enumerations in *path operation* parameters. New documentation: [Path Parameters: Predefined values](https://fastapi.tiangolo.com/tutorial/path-params/#predefined-values).
* Add support for type annotations using `Optional` as in `param: Optional[str] = None`. New documentation: [Optional type declarations](https://fastapi.tiangolo.com/tutorial/query-params/#optional-type-declarations).
* PR [#278](https://github.com/tiangolo/fastapi/pull/278).
## 0.26.0
* Separate error handling for validation errors.
* This will allow developers to customize the exception handlers.
* Document better how to handle exceptions and use error handlers.
* Include `RequestValidationError` and `WebSocketRequestValidationError` (this last one will be useful once [encode/starlette#527](https://github.com/encode/starlette/pull/527) or equivalent is merged).
* New documentation about exceptions handlers:
* [Install custom exception handlers](https://fastapi.tiangolo.com/tutorial/handling-errors/#install-custom-exception-handlers).
* [Override the default exception handlers](https://fastapi.tiangolo.com/tutorial/handling-errors/#override-the-default-exception-handlers).
* [Re-use **FastAPI's** exception handlers](https://fastapi.tiangolo.com/tutorial/handling-errors/#re-use-fastapis-exception-handlers).
* PR [#273](https://github.com/tiangolo/fastapi/pull/273).
* Fix support for *paths* in *path parameters* without needing explicit `Path(...)`.
* PR [#256](https://github.com/tiangolo/fastapi/pull/256).
* Documented in PR [#272](https://github.com/tiangolo/fastapi/pull/272) by [@wshayes](https://github.com/wshayes).
* New documentation at: [Path Parameters containing paths](https://fastapi.tiangolo.com/tutorial/path-params/#path-parameters-containing-paths).
* Update docs for testing FastAPI. Include using `POST`, sending JSON, testing headers, etc. New documentation: [Testing](https://fastapi.tiangolo.com/tutorial/testing/#testing-extended-example). PR [#271](https://github.com/tiangolo/fastapi/pull/271).
* Fix type declaration of `response_model` to allow generic Python types as `List[Model]`. Mainly to fix `mypy` for users. PR [#266](https://github.com/tiangolo/fastapi/pull/266).
## 0.25.0
* Add support for Pydantic's `include`, `exclude`, `by_alias`.
* Update documentation: [Response Model](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
* Add docs for: [Body - updates](https://fastapi.tiangolo.com/tutorial/body-updates/), using Pydantic's `skip_defaults`.
* Add method consistency tests.
* PR [#264](https://github.com/tiangolo/fastapi/pull/264).
* Add `CONTRIBUTING.md` file to GitHub, to help new contributors. PR [#255](https://github.com/tiangolo/fastapi/pull/255) by [@wshayes](https://github.com/wshayes).
* Add support for Pydantic's `skip_defaults`:
* There's a new *path operation decorator* parameter `response_model_skip_defaults`.
* The name of the parameter will most probably change in a future version to `response_skip_defaults`, `model_skip_defaults` or something similar.
* New [documentation section about using `response_model_skip_defaults`](https://fastapi.tiangolo.com/tutorial/response-model/#response-model-encoding-parameters).
* PR [#248](https://github.com/tiangolo/fastapi/pull/248) by [@wshayes](https://github.com/wshayes).
## 0.24.0
* Add support for WebSockets with dependencies and parameters.
* Support included for:
* `Depends`
* `Security`
* `Cookie`
* `Header`
* `Path`
* `Query`
* ...as these are compatible with the WebSockets protocol (e.g. `Body` is not).
* [Updated documentation for WebSockets](https://fastapi.tiangolo.com/tutorial/websockets/).
* PR [#178](https://github.com/tiangolo/fastapi/pull/178) by [@jekirl](https://github.com/jekirl).
* Upgrade the compatible version of Pydantic to `0.26.0`.
* This includes JSON Schema support for IP address and network objects, bug fixes, and other features.
* PR [#247](https://github.com/tiangolo/fastapi/pull/247) by [@euri10](https://github.com/euri10).
## 0.23.0
* Upgrade the compatible version of Starlette to `0.12.0`.
* This includes support for ASGI 3 (the latest version of the standard).
* It's now possible to use [Starlette's `StreamingResponse`](https://www.starlette.io/responses/#streamingresponse) with iterators, like [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) objects (as those returned by `open()`).
* It's now possible to use the low level utility `iterate_in_threadpool` from `starlette.concurrency` (for advanced scenarios).
* PR [#243](https://github.com/tiangolo/fastapi/pull/243).
* Add OAuth2 redirect page for Swagger UI. This allows having delegated authentication in the Swagger UI docs. For this to work, you need to add `{your_origin}/docs/oauth2-redirect` to the allowed callbacks in your OAuth2 provider (in Auth0, Facebook, Google, etc).
* For example, during development, it could be `http://localhost:8000/docs/oauth2-redirect`.
* Have in mind that this callback URL is independent of whichever one is used by your frontend. You might also have another callback at `https://yourdomain.com/login/callback`.
* This is only to allow delegated authentication in the API docs with Swagger UI.
* PR [#198](https://github.com/tiangolo/fastapi/pull/198) by [@steinitzu](https://github.com/steinitzu).
* Make Swagger UI and ReDoc route handlers (*path operations*) be `async` functions instead of lambdas to improve performance. PR [#241](https://github.com/tiangolo/fastapi/pull/241) by [@Trim21](https://github.com/Trim21).
* Make Swagger UI and ReDoc URLs parameterizable, allowing to host and serve local versions of them and have offline docs. PR [#112](https://github.com/tiangolo/fastapi/pull/112) by [@euri10](https://github.com/euri10).
## 0.22.0
* Add support for `dependencies` parameter:
* A parameter in *path operation decorators*, for dependencies that should be executed but the return value is not important or not used in the *path operation function*.
* A parameter in the `.include_router()` method of FastAPI applications and routers, to include dependencies that should be executed in each *path operation* in a router.
* This is useful, for example, to require authentication or permissions in specific group of *path operations*.
* Different `dependencies` can be applied to different routers.
* These `dependencies` are run before the normal parameter dependencies. And normal dependencies are run too. They can be combined.
* Dependencies declared in a router are executed first, then the ones defined in *path operation decorators*, and then the ones declared in normal parameters. They are all combined and executed.
* All this also supports using `Security` with `scopes` in those `dependencies` parameters, for more advanced OAuth 2.0 security scenarios with scopes.
* New documentation about [dependencies in *path operation decorators*](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
* New documentation about [dependencies in the `include_router()` method](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-prefix-tags-responses-and-dependencies).
* PR [#235](https://github.com/tiangolo/fastapi/pull/235).
* Fix OpenAPI documentation of Starlette URL convertors. Specially useful when using `path` convertors, to take a whole path as a parameter, like `/some/url/{p:path}`. PR [#234](https://github.com/tiangolo/fastapi/pull/234) by [@euri10](https://github.com/euri10).
* Make default parameter utilities exported from `fastapi` be functions instead of classes (the new functions return instances of those classes). To be able to override the return types and fix `mypy` errors in FastAPI's users' code. Applies to `Path`, `Query`, `Header`, `Cookie`, `Body`, `Form`, `File`, `Depends`, and `Security`. PR [#226](https://github.com/tiangolo/fastapi/pull/226) and PR [#231](https://github.com/tiangolo/fastapi/pull/231).
* Separate development scripts `test.sh`, `lint.sh`, and `format.sh`. PR [#232](https://github.com/tiangolo/fastapi/pull/232).
* Re-enable `black` formatting checks for Python 3.7. PR [#229](https://github.com/tiangolo/fastapi/pull/229) by [@zamiramir](https://github.com/zamiramir).
## 0.21.0
* On body parsing errors, raise `from` previous exception, to allow better introspection in logging code. PR [#192](https://github.com/tiangolo/fastapi/pull/195) by [@ricardomomm](https://github.com/ricardomomm).
* Use Python logger named "`fastapi`" instead of root logger. PR [#222](https://github.com/tiangolo/fastapi/pull/222) by [@euri10](https://github.com/euri10).
* Upgrade Pydantic to version 0.25. PR [#225](https://github.com/tiangolo/fastapi/pull/225) by [@euri10](https://github.com/euri10).
* Fix typo in routing. PR [#221](https://github.com/tiangolo/fastapi/pull/221) by [@djlambert](https://github.com/djlambert).
## 0.20.1
* Add typing information to package including file `py.typed`. PR [#209](https://github.com/tiangolo/fastapi/pull/209) by [@meadsteve](https://github.com/meadsteve).
* Add FastAPI bot for Gitter. To automatically announce new releases. PR [#189](https://github.com/tiangolo/fastapi/pull/189).
## 0.20.0
* Upgrade OAuth2:
* Upgrade Password flow using Bearer tokens to use the correct HTTP status code 401 `UNAUTHORIZED`, with `WWW-Authenticate` headers.
* Update, simplify, and improve all the [security docs](https://fastapi.tiangolo.com/tutorial/security/intro/).
* Add new `scope_str` to `SecurityScopes` and update docs: [OAuth2 scopes](https://fastapi.tiangolo.com/tutorial/security/oauth2-scopes/).
* Update docs, images, tests.
* PR [#188](https://github.com/tiangolo/fastapi/pull/188).
* Include [Hypercorn](https://gitlab.com/pgjones/hypercorn) as an alternative ASGI server in the docs. PR [#187](https://github.com/tiangolo/fastapi/pull/187).
* Add docs for [Static Files](https://fastapi.tiangolo.com/tutorial/static-files/) and [Templates](https://fastapi.tiangolo.com/tutorial/templates/). PR [#186](https://github.com/tiangolo/fastapi/pull/186).
* Add docs for handling [Response Cookies](https://fastapi.tiangolo.com/tutorial/response-cookies/) and [Response Headers](https://fastapi.tiangolo.com/tutorial/response-headers/). PR [#185](https://github.com/tiangolo/fastapi/pull/185).
* Fix typos in docs. PR [#176](https://github.com/tiangolo/fastapi/pull/176) by [@chdsbd](https://github.com/chdsbd).
## 0.19.0
* Rename _path operation decorator_ parameter `content_type` to `response_class`. PR [#183](https://github.com/tiangolo/fastapi/pull/183).
* Add docs:
* How to use the `jsonable_encoder` in [JSON compatible encoder](https://fastapi.tiangolo.com/tutorial/encoder/).
* How to [Return a Response directly](https://fastapi.tiangolo.com/tutorial/response-directly/).
* Update how to use a [Custom Response Class](https://fastapi.tiangolo.com/tutorial/custom-response/).
* PR [#184](https://github.com/tiangolo/fastapi/pull/184).
## 0.18.0
* Add docs for [HTTP Basic Auth](https://fastapi.tiangolo.com/tutorial/custom-response/). PR [#177](https://github.com/tiangolo/fastapi/pull/177).
* Upgrade HTTP Basic Auth handling with automatic headers (automatic browser login prompt). PR [#175](https://github.com/tiangolo/fastapi/pull/175).
* Update dependencies for security. PR [#174](https://github.com/tiangolo/fastapi/pull/174).
* Add docs for [Middleware](https://fastapi.tiangolo.com/tutorial/middleware/). PR [#173](https://github.com/tiangolo/fastapi/pull/173).
## 0.17.0
* Make Flit publish from CI. PR [#170](https://github.com/tiangolo/fastapi/pull/170).
* Add documentation about handling [CORS (Cross-Origin Resource Sharing)](https://fastapi.tiangolo.com/tutorial/cors/). PR [#169](https://github.com/tiangolo/fastapi/pull/169).
* By default, encode by alias. This allows using Pydantic `alias` parameters working by default. PR [#168](https://github.com/tiangolo/fastapi/pull/168).
## 0.16.0
* Upgrade _path operation_ `doctsring` parsing to support proper Markdown descriptions. New documentation at [Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#description-from-docstring). PR [#163](https://github.com/tiangolo/fastapi/pull/163).
* Refactor internal usage of Pydantic to use correct data types. PR [#164](https://github.com/tiangolo/fastapi/pull/164).
* Upgrade Pydantic to version `0.23`. PR [#160](https://github.com/tiangolo/fastapi/pull/160) by [@euri10](https://github.com/euri10).
* Fix typo in Tutorial about Extra Models. PR [#159](https://github.com/tiangolo/fastapi/pull/159) by [@danielmichaels](https://github.com/danielmichaels).
* Fix [Query Parameters](https://fastapi.tiangolo.com/tutorial/query-params/) URL examples in docs. PR [#157](https://github.com/tiangolo/fastapi/pull/157) by [@hayata-yamamoto](https://github.com/hayata-yamamoto).
## 0.15.0
* Add support for multiple file uploads (as a single form field). New docs at: [Multiple file uploads](https://fastapi.tiangolo.com/tutorial/request-files/#multiple-file-uploads). PR [#158](https://github.com/tiangolo/fastapi/pull/158).
* Add docs for: [Additional Status Codes](https://fastapi.tiangolo.com/tutorial/additional-status-codes/). PR [#156](https://github.com/tiangolo/fastapi/pull/156).
## 0.14.0
* Improve automatically generated names of path operations in OpenAPI (in API docs). A function `read_items` instead of having a generated name "Read Items Get" will have "Read Items". PR [#155](https://github.com/tiangolo/fastapi/pull/155).
* Add docs for: [Testing **FastAPI**](https://fastapi.tiangolo.com/tutorial/testing/). PR [#151](https://github.com/tiangolo/fastapi/pull/151).
* Update `/docs` Swagger UI to enable deep linking. This allows sharing the URL pointing directly to the path operation documentation in the docs. PR [#148](https://github.com/tiangolo/fastapi/pull/148) by [@wshayes](https://github.com/wshayes).
* Update development dependencies, `Pipfile.lock`. PR [#150](https://github.com/tiangolo/fastapi/pull/150).
* Include Falcon and Hug in: [Alternatives, Inspiration and Comparisons](https://fastapi.tiangolo.com/alternatives/).
## 0.13.0
* Improve/upgrade OAuth2 scopes support with `SecurityScopes`:
* `SecurityScopes` can be declared as a parameter like `Request`, to get the scopes of all super-dependencies/dependants.
* Improve `Security` handling, merging scopes when declaring `SecurityScopes`.
* Allow using `SecurityBase` (like `OAuth2`) classes with `Depends` and still document them. `Security` now is needed only to declare `scopes`.
* Updated docs about: [OAuth2 with Password (and hashing), Bearer with JWT tokens](https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/).
* New docs about: [OAuth2 scopes](https://fastapi.tiangolo.com/tutorial/security/oauth2-scopes/).
* PR [#141](https://github.com/tiangolo/fastapi/pull/141).
## 0.12.1
* Fix bug: handling additional `responses` in `APIRouter.include_router()`. PR [#140](https://github.com/tiangolo/fastapi/pull/140).
* Fix typo in SQL tutorial. PR [#138](https://github.com/tiangolo/fastapi/pull/138) by [@mostaphaRoudsari](https://github.com/mostaphaRoudsari).
* Fix typos in section about nested models and OAuth2 with JWT. PR [#127](https://github.com/tiangolo/fastapi/pull/127) by [@mmcloud](https://github.com/mmcloud).
## 0.12.0
* Add additional `responses` parameter to _path operation decorators_ to extend responses in OpenAPI (and API docs).
* It also allows extending existing responses generated from `response_model`, declare other media types (like images), etc.
* The new documentation is here: [Additional Responses](https://fastapi.tiangolo.com/tutorial/additional-responses/).
* `responses` can also be added to `.include_router()`, the updated docs are here: [Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#add-some-custom-tags-and-responses).
* PR [#97](https://github.com/tiangolo/fastapi/pull/97) originally initiated by [@barsi](https://github.com/barsi).
* Update `scripts/test-cov-html.sh` to allow passing extra parameters like `-vv`, for development.
## 0.11.0
* Add `auto_error` parameter to security utility functions. Allowing them to be optional. Also allowing to have multiple alternative security schemes that are then checked in a single dependency instead of each one verifying and returning the error to the client automatically when not satisfied. PR [#134](https://github.com/tiangolo/fastapi/pull/134).
* Update [SQL Tutorial](https://fastapi.tiangolo.com/tutorial/sql-databases/#create-a-middleware-to-handle-sessions) to close database sessions even when there are exceptions. PR [#89](https://github.com/tiangolo/fastapi/pull/89) by [@alexiri](https://github.com/alexiri).
* Fix duplicate dependency in `pyproject.toml`. PR [#128](https://github.com/tiangolo/fastapi/pull/128) by [@zxalif](https://github.com/zxalif).
## 0.10.3
* Add Gitter chat, badge, links, etc. [https://gitter.im/tiangolo/fastapi](https://gitter.im/tiangolo/fastapi) . PR [#117](https://github.com/tiangolo/fastapi/pull/117).
* Add docs about [Extending OpenAPI](https://fastapi.tiangolo.com/tutorial/extending-openapi/). PR [#126](https://github.com/tiangolo/fastapi/pull/126).
* Make Travis run Ubuntu Xenial (newer version) and Python 3.7 instead of Python 3.7-dev. PR [#92](https://github.com/tiangolo/fastapi/pull/92) by [@blueyed](https://github.com/blueyed).
* Fix duplicated param variable creation. PR [#123](https://github.com/tiangolo/fastapi/pull/123) by [@yihuang](https://github.com/yihuang).
* Add note in [Response Model docs](https://fastapi.tiangolo.com/tutorial/response-model/) about why using a function parameter instead of a function return type annotation. PR [#109](https://github.com/tiangolo/fastapi/pull/109) by [@JHSaunders](https://github.com/JHSaunders).
* Fix event docs (startup/shutdown) function name. PR [#105](https://github.com/tiangolo/fastapi/pull/105) by [@stratosgear](https://github.com/stratosgear).
## 0.10.2
* Fix OpenAPI (JSON Schema) for declarations of Python `Union` (JSON Schema `additionalProperties`). PR [#121](https://github.com/tiangolo/fastapi/pull/121).
* Update [Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/) with a note on Celery.
* Document response models using unions and lists, updated at: [Extra Models](https://fastapi.tiangolo.com/tutorial/extra-models/). PR [#108](https://github.com/tiangolo/fastapi/pull/108).
## 0.10.1
* Add docs and tests for <a href="https://github.com/encode/databases" target="_blank">encode/databases</a>. New docs at: <a href="https://fastapi.tiangolo.com/tutorial/async-sql-databases/" target="_blank">Async SQL (Relational) Databases</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/107" target="_blank">#107</a>.
* Add docs and tests for [encode/databases](https://github.com/encode/databases). New docs at: [Async SQL (Relational) Databases](https://fastapi.tiangolo.com/tutorial/async-sql-databases/). PR [#107](https://github.com/tiangolo/fastapi/pull/107).
## 0.10.0
* Add support for Background Tasks in *path operation functions* and dependencies. New documentation about <a href="https://fastapi.tiangolo.com/tutorial/background-tasks/" target="_blank">Background Tasks is here</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/103" target="_blank">#103</a>.
* Add support for Background Tasks in _path operation functions_ and dependencies. New documentation about [Background Tasks is here](https://fastapi.tiangolo.com/tutorial/background-tasks/). PR [#103](https://github.com/tiangolo/fastapi/pull/103).
* Add support for `.websocket_route()` in `APIRouter`. PR <a href="https://github.com/tiangolo/fastapi/pull/100" target="_blank">#100</a> by <a href="https://github.com/euri10" target="_blank">@euri10</a>.
* Add support for `.websocket_route()` in `APIRouter`. PR [#100](https://github.com/tiangolo/fastapi/pull/100) by [@euri10](https://github.com/euri10).
* New docs section about <a href="https://fastapi.tiangolo.com/tutorial/events/" target="_blank">Events: startup - shutdown</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/99" target="_blank">#99</a>.
* New docs section about [Events: startup - shutdown](https://fastapi.tiangolo.com/tutorial/events/). PR [#99](https://github.com/tiangolo/fastapi/pull/99).
## 0.9.1
* Document receiving <a href="https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#query-parameter-list-multiple-values" target="_blank">Multiple values with the same query parameter</a> and <a href="https://fastapi.tiangolo.com/tutorial/header-params/#duplicate-headers" target="_blank">Duplicate headers</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/95" target="_blank">#95</a>.
* Document receiving [Multiple values with the same query parameter](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#query-parameter-list-multiple-values) and [Duplicate headers](https://fastapi.tiangolo.com/tutorial/header-params/#duplicate-headers). PR [#95](https://github.com/tiangolo/fastapi/pull/95).
## 0.9.0
* Upgrade compatible Pydantic version to `0.21.0`. PR <a href="https://github.com/tiangolo/fastapi/pull/90" target="_blank">#90</a>.
* Upgrade compatible Pydantic version to `0.21.0`. PR [#90](https://github.com/tiangolo/fastapi/pull/90).
* Add documentation for: <a href="https://fastapi.tiangolo.com/tutorial/application-configuration/" target="_blank">Application Configuration</a>.
* Add documentation for: [Application Configuration](https://fastapi.tiangolo.com/tutorial/application-configuration/).
* Fix typo in docs. PR <a href="https://github.com/tiangolo/fastapi/pull/76" target="_blank">#76</a> by <a href="https://github.com/matthewhegarty" target="_blank">@matthewhegarty</a>.
* Fix typo in docs. PR [#76](https://github.com/tiangolo/fastapi/pull/76) by [@matthewhegarty](https://github.com/matthewhegarty).
* Fix link in "Deployment" to "Bigger Applications".
## 0.8.0
* Make development scripts executable. PR <a href="https://github.com/tiangolo/fastapi/pull/76" target="_blank">#76</a> by <a href="https://github.com/euri10" target="_blank">@euri10</a>.
* Make development scripts executable. PR [#76](https://github.com/tiangolo/fastapi/pull/76) by [@euri10](https://github.com/euri10).
* Add support for adding `tags` in `app.include_router()`. PR <a href="https://github.com/tiangolo/fastapi/pull/55" target="_blank">#55</a> by <a href="https://github.com/euri10" target="_blank">@euri10</a>. Documentation updated in the section: <a href="https://fastapi.tiangolo.com/tutorial/bigger-applications/" target="_blank">Bigger Applications</a>.
* Add support for adding `tags` in `app.include_router()`. PR [#55](https://github.com/tiangolo/fastapi/pull/55) by [@euri10](https://github.com/euri10). Documentation updated in the section: [Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/).
* Update docs related to Uvicorn to use new `--reload` option from version `0.5.x`. PR <a href="https://github.com/tiangolo/fastapi/pull/74" target="_blank">#74</a>.
* Update docs related to Uvicorn to use new `--reload` option from version `0.5.x`. PR [#74](https://github.com/tiangolo/fastapi/pull/74).
* Update `isort` imports and scripts to be compatible with newer versions. PR <a href="https://github.com/tiangolo/fastapi/pull/75" target="_blank">#75</a>.
* Update `isort` imports and scripts to be compatible with newer versions. PR [#75](https://github.com/tiangolo/fastapi/pull/75).
## 0.7.1
* Update <a href="https://fastapi.tiangolo.com/async/#path-operation-functions" target="_blank">technical details about `async def` handling</a> with respect to previous frameworks. PR <a href="https://github.com/tiangolo/fastapi/pull/64" target="_blank">#64</a> by <a href="https://github.com/haizaar" target="_blank">@haizaar</a>.
* Update [technical details about `async def` handling](https://fastapi.tiangolo.com/async/#path-operation-functions) with respect to previous frameworks. PR [#64](https://github.com/tiangolo/fastapi/pull/64) by [@haizaar](https://github.com/haizaar).
* Add <a href="https://fastapi.tiangolo.com/deployment/#raspberry-pi-and-other-architectures" target="_blank">deployment documentation for Docker in Raspberry Pi</a> and other architectures.
* Add [deployment documentation for Docker in Raspberry Pi](https://fastapi.tiangolo.com/deployment/#raspberry-pi-and-other-architectures) and other architectures.
* Trigger Docker images build on Travis CI automatically. PR <a href="https://github.com/tiangolo/fastapi/pull/65" target="_blank">#65</a>.
* Trigger Docker images build on Travis CI automatically. PR [#65](https://github.com/tiangolo/fastapi/pull/65).
## 0.7.0
* Add support for `UploadFile` in `File` parameter annotations.
* This includes a file-like interface.
* Here's the updated documentation for declaring <a href="https://fastapi.tiangolo.com/tutorial/request-files/#file-parameters-with-uploadfile" target="_blank"> `File` parameters with `UploadFile`</a>.
* And here's the updated documentation for using <a href="https://fastapi.tiangolo.com/tutorial/request-forms-and-files/" target="_blank">`Form` parameters mixed with `File` parameters, supporting `bytes` and `UploadFile`</a> at the same time.
* PR <a href="https://github.com/tiangolo/fastapi/pull/63" target="_blank">#63</a>.
* Here's the updated documentation for declaring [`File` parameters with `UploadFile`](https://fastapi.tiangolo.com/tutorial/request-files/#file-parameters-with-uploadfile).
* And here's the updated documentation for using [`Form` parameters mixed with `File` parameters, supporting `bytes` and `UploadFile`](https://fastapi.tiangolo.com/tutorial/request-forms-and-files/) at the same time.
* PR [#63](https://github.com/tiangolo/fastapi/pull/63).
## 0.6.4
* Add <a href="https://fastapi.tiangolo.com/async/#very-technical-details" target="_blank">technical details about `async def` handling to docs</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/61" target="_blank">#61</a>.
* Add [technical details about `async def` handling to docs](https://fastapi.tiangolo.com/async/#very-technical-details). PR [#61](https://github.com/tiangolo/fastapi/pull/61).
* Add docs for <a href="https://fastapi.tiangolo.com/tutorial/debugging/" target="_blank">Debugging FastAPI applications in editors</a>.
* Add docs for [Debugging FastAPI applications in editors](https://fastapi.tiangolo.com/tutorial/debugging/).
* Clarify <a href="https://fastapi.tiangolo.com/deployment/#bigger-applications" target="_blank">Bigger Applications deployed with Docker</a>.
* Clarify [Bigger Applications deployed with Docker](https://fastapi.tiangolo.com/deployment/#bigger-applications).
* Fix typos in docs.
* Add section about <a href="https://fastapi.tiangolo.com/history-design-future/" target="_blank">History, Design and Future</a>.
* Add section about [History, Design and Future](https://fastapi.tiangolo.com/history-design-future/).
* Add docs for using <a href="https://fastapi.tiangolo.com/tutorial/websockets/" target="_blank">WebSockets with **FastAPI**</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/62" target="_blank">#62</a>.
* Add docs for using [WebSockets with **FastAPI**](https://fastapi.tiangolo.com/tutorial/websockets/). PR [#62](https://github.com/tiangolo/fastapi/pull/62).
## 0.6.3
* Add Favicons to docs. PR <a href="https://github.com/tiangolo/fastapi/pull/53" target="_blank">#53</a>.
* Add Favicons to docs. PR [#53](https://github.com/tiangolo/fastapi/pull/53).
## 0.6.2
* Introduce new project generator based on FastAPI and PostgreSQL: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/52" target="_blank">#52</a>.
* Introduce new project generator based on FastAPI and PostgreSQL: [https://github.com/tiangolo/full-stack-fastapi-postgresql](https://github.com/tiangolo/full-stack-fastapi-postgresql). PR [#52](https://github.com/tiangolo/fastapi/pull/52).
* Update <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" target="_blank">SQL tutorial with SQLAlchemy, using `Depends` to improve editor support and reduce code repetition</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/52" target="_blank">#52</a>.
* Update [SQL tutorial with SQLAlchemy, using `Depends` to improve editor support and reduce code repetition](https://fastapi.tiangolo.com/tutorial/sql-databases/). PR [#52](https://github.com/tiangolo/fastapi/pull/52).
* Improve middleware naming in tutorial for SQL with SQLAlchemy <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" target="_blank">https://fastapi.tiangolo.com/tutorial/sql-databases/</a>.
* Improve middleware naming in tutorial for SQL with SQLAlchemy [https://fastapi.tiangolo.com/tutorial/sql-databases/](https://fastapi.tiangolo.com/tutorial/sql-databases/).
## 0.6.1
* Add docs for GraphQL: <a href="https://fastapi.tiangolo.com/tutorial/graphql/" target="_blank">https://fastapi.tiangolo.com/tutorial/graphql/</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/48" target="_blank">#48</a>.
* Add docs for GraphQL: [https://fastapi.tiangolo.com/tutorial/graphql/](https://fastapi.tiangolo.com/tutorial/graphql/). PR [#48](https://github.com/tiangolo/fastapi/pull/48).
## 0.6.0
* Update SQL with SQLAlchemy tutorial at <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" target="_blank">https://fastapi.tiangolo.com/tutorial/sql-databases/</a> using the new official `request.state`. PR <a href="https://github.com/tiangolo/fastapi/pull/45" target="_blank">#45</a>.
* Update SQL with SQLAlchemy tutorial at [https://fastapi.tiangolo.com/tutorial/sql-databases/](https://fastapi.tiangolo.com/tutorial/sql-databases/) using the new official `request.state`. PR [#45](https://github.com/tiangolo/fastapi/pull/45).
* Upgrade Starlette to version `0.11.1` and add required compatibility changes. PR <a href="https://github.com/tiangolo/fastapi/pull/44" target="_blank">#44</a>.
* Upgrade Starlette to version `0.11.1` and add required compatibility changes. PR [#44](https://github.com/tiangolo/fastapi/pull/44).
## 0.5.1
* Add section about <a href="https://fastapi.tiangolo.com/help-fastapi/" target="_blank">helping and getting help with **FastAPI**</a>.
* Add section about [helping and getting help with **FastAPI**](https://fastapi.tiangolo.com/help-fastapi/).
* Add note about <a href="https://fastapi.tiangolo.com/tutorial/path-params/#order-matters" target="_blank">path operations order in docs</a>.
* Add note about [path operations order in docs](https://fastapi.tiangolo.com/tutorial/path-params/#order-matters).
* Update <a href="https://fastapi.tiangolo.com/tutorial/handling-errors/" target="_blank">section about error handling</a> with more information and make relation with Starlette error handling utilities more explicit. PR <a href="https://github.com/tiangolo/fastapi/pull/41" target="_blank">#41</a>.
* Update [section about error handling](https://fastapi.tiangolo.com/tutorial/handling-errors/) with more information and make relation with Starlette error handling utilities more explicit. PR [#41](https://github.com/tiangolo/fastapi/pull/41).
* Add <a href="" target="_blank">Development - Contributing section to the docs</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/42" target="_blank">#42</a>.
* Add <a href="" target="_blank">Development - Contributing section to the docs</a>. PR [#42](https://github.com/tiangolo/fastapi/pull/42).
## 0.5.0
* Add new `HTTPException` with support for custom headers. With new documentation for handling errors at: <a href="https://fastapi.tiangolo.com/tutorial/handling-errors/" target="_blank">https://fastapi.tiangolo.com/tutorial/handling-errors/</a>. PR <a href="https://github.com/tiangolo/fastapi/pull/35" target="_blank">#35</a>.
* Add new `HTTPException` with support for custom headers. With new documentation for handling errors at: [https://fastapi.tiangolo.com/tutorial/handling-errors/](https://fastapi.tiangolo.com/tutorial/handling-errors/). PR [#35](https://github.com/tiangolo/fastapi/pull/35).
* Add <a href="https://fastapi.tiangolo.com/tutorial/using-request-directly/" target="_blank">documentation to use Starlette `Request` object</a> directly. Check <a href="https://github.com/tiangolo/fastapi/pull/25" target="_blank">#25</a> by <a href="https://github.com/euri10" target="_blank">@euri10</a>.
* Add [documentation to use Starlette `Request` object](https://fastapi.tiangolo.com/tutorial/using-request-directly/) directly. Check [#25](https://github.com/tiangolo/fastapi/pull/25) by [@euri10](https://github.com/euri10).
* Add issue templates to simplify reporting bugs, getting help, etc: <a href="https://github.com/tiangolo/fastapi/pull/34" target="_blank">#34</a>.
* Add issue templates to simplify reporting bugs, getting help, etc: [#34](https://github.com/tiangolo/fastapi/pull/34).
* Update example for the SQLAlchemy tutorial at <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" target="_blank">https://fastapi.tiangolo.com/tutorial/sql-databases/</a> using middleware and database session attached to request.
* Update example for the SQLAlchemy tutorial at [https://fastapi.tiangolo.com/tutorial/sql-databases/](https://fastapi.tiangolo.com/tutorial/sql-databases/) using middleware and database session attached to request.
## 0.4.0
* Add `openapi_prefix`, support for reverse proxy and mounting sub-applications. See the docs at <a href="https://fastapi.tiangolo.com/tutorial/sub-applications-proxy/" target="_blank">https://fastapi.tiangolo.com/tutorial/sub-applications-proxy/</a>: <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank">#26</a> by <a href="https://github.com/kabirkhan" target="_blank">@kabirkhan</a>.
* Add `openapi_prefix`, support for reverse proxy and mounting sub-applications. See the docs at [https://fastapi.tiangolo.com/tutorial/sub-applications-proxy/](https://fastapi.tiangolo.com/tutorial/sub-applications-proxy/): [#26](https://github.com/tiangolo/fastapi/pull/26) by [@kabirkhan](https://github.com/kabirkhan).
* Update <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" target="_blank">docs/tutorial for SQLAlchemy</a> including note about *DB Browser for SQLite*.
* Update [docs/tutorial for SQLAlchemy](https://fastapi.tiangolo.com/tutorial/sql-databases/) including note about _DB Browser for SQLite_.
## 0.3.0
* Fix/add SQLAlchemy support, including ORM, and update <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" target="_blank">docs for SQLAlchemy</a>: <a href="https://github.com/tiangolo/fastapi/pull/30" target="_blank">#30</a>.
* Fix/add SQLAlchemy support, including ORM, and update [docs for SQLAlchemy](https://fastapi.tiangolo.com/tutorial/sql-databases/): [#30](https://github.com/tiangolo/fastapi/pull/30).
## 0.2.1
* Fix `jsonable_encoder` for Pydantic models with `Config` but without `json_encoders`: <a href="https://github.com/tiangolo/fastapi/pull/29" target="_blank">#29</a>.
* Fix `jsonable_encoder` for Pydantic models with `Config` but without `json_encoders`: [#29](https://github.com/tiangolo/fastapi/pull/29).
## 0.2.0
* Fix typos in Security section: <a href="https://github.com/tiangolo/fastapi/pull/24" target="_blank">#24</a> by <a href="https://github.com/kkinder" target="_blank">@kkinder</a>.
* Fix typos in Security section: [#24](https://github.com/tiangolo/fastapi/pull/24) by [@kkinder](https://github.com/kkinder).
* Add support for Pydantic custom JSON encoders: <a href="https://github.com/tiangolo/fastapi/pull/21" target="_blank">#21</a> by <a href="https://github.com/euri10" target="_blank">@euri10</a>.
* Add support for Pydantic custom JSON encoders: [#21](https://github.com/tiangolo/fastapi/pull/21) by [@euri10](https://github.com/euri10).
## 0.1.19
* Upgrade Starlette version to the current latest `0.10.1`: <a href="https://github.com/tiangolo/fastapi/pull/17" target="_blank">#17</a> by <a href="https://github.com/euri10" target="_blank">@euri10</a>.
* Upgrade Starlette version to the current latest `0.10.1`: [#17](https://github.com/tiangolo/fastapi/pull/17) by [@euri10](https://github.com/euri10).

View File

@@ -0,0 +1,23 @@
from fastapi import FastAPI
from pydantic import BaseModel
from starlette.responses import JSONResponse
class Item(BaseModel):
id: str
value: str
class Message(BaseModel):
message: str
app = FastAPI()
@app.get("/items/{item_id}", response_model=Item, responses={404: {"model": Message}})
async def read_item(item_id: str):
if item_id == "foo":
return {"id": "foo", "value": "there goes my hero"}
else:
return JSONResponse(status_code=404, content={"message": "Item not found"})

View File

@@ -0,0 +1,28 @@
from fastapi import FastAPI
from pydantic import BaseModel
from starlette.responses import FileResponse
class Item(BaseModel):
id: str
value: str
app = FastAPI()
@app.get(
"/items/{item_id}",
response_model=Item,
responses={
200: {
"content": {"image/png": {}},
"description": "Return the JSON item or an image.",
}
},
)
async def read_item(item_id: str, img: bool = None):
if img:
return FileResponse("image.png", media_type="image/png")
else:
return {"id": "foo", "value": "there goes my hero"}

View File

@@ -0,0 +1,37 @@
from fastapi import FastAPI
from pydantic import BaseModel
from starlette.responses import JSONResponse
class Item(BaseModel):
id: str
value: str
class Message(BaseModel):
message: str
app = FastAPI()
@app.get(
"/items/{item_id}",
response_model=Item,
responses={
404: {"model": Message, "description": "The item was not found"},
200: {
"description": "Item requested by ID",
"content": {
"application/json": {
"example": {"id": "bar", "value": "The bar tenders"}
}
},
},
},
)
async def read_item(item_id: str):
if item_id == "foo":
return {"id": "foo", "value": "there goes my hero"}
else:
return JSONResponse(status_code=404, content={"message": "Item not found"})

View File

@@ -0,0 +1,30 @@
from fastapi import FastAPI
from pydantic import BaseModel
from starlette.responses import FileResponse
class Item(BaseModel):
id: str
value: str
responses = {
404: {"description": "Item not found"},
302: {"description": "The item was moved"},
403: {"description": "Not enough privileges"},
}
app = FastAPI()
@app.get(
"/items/{item_id}",
response_model=Item,
responses={**responses, 200: {"content": {"image/png": {}}}},
)
async def read_item(item_id: str, img: bool = None):
if img:
return FileResponse("image.png", media_type="image/png")
else:
return {"id": "foo", "value": "there goes my hero"}

View File

@@ -0,0 +1,20 @@
from fastapi import Body, FastAPI
from starlette.responses import JSONResponse
from starlette.status import HTTP_201_CREATED
app = FastAPI()
items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
@app.put("/items/{item_id}")
async def upsert_item(item_id: str, name: str = Body(None), size: int = Body(None)):
if item_id in items:
item = items[item_id]
item["name"] = name
item["size"] = size
return item
else:
item = {"name": name, "size": size}
items[item_id] = item
return JSONResponse(status_code=HTTP_201_CREATED, content=item)

View File

View File

@@ -0,0 +1,8 @@
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def read_main():
return {"msg": "Hello World"}

View File

@@ -0,0 +1,36 @@
from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel
fake_secret_token = "coneofsilence"
fake_db = {
"foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
"bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
}
app = FastAPI()
class Item(BaseModel):
id: str
title: str
description: str = None
@app.get("/items/{item_id}", response_model=Item)
async def read_main(item_id: str, x_token: str = Header(...)):
if x_token != fake_secret_token:
raise HTTPException(status_code=400, detail="Invalid X-Token header")
if item_id not in fake_db:
raise HTTPException(status_code=404, detail="Item not found")
return fake_db[item_id]
@app.post("/items/", response_model=Item)
async def create_item(item: Item, x_token: str = Header(...)):
if x_token != fake_secret_token:
raise HTTPException(status_code=400, detail="Invalid X-Token header")
if item.id in fake_db:
raise HTTPException(status_code=400, detail="Item already exists")
fake_db[item.id] = item
return item

View File

@@ -0,0 +1,11 @@
from starlette.testclient import TestClient
from .main import app
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"}

View File

@@ -0,0 +1,65 @@
from starlette.testclient import TestClient
from .main_b import app
client = TestClient(app)
def test_read_item():
response = client.get("/items/foo", headers={"X-Token": "coneofsilence"})
assert response.status_code == 200
assert response.json() == {
"id": "foo",
"title": "Foo",
"description": "There goes my hero",
}
def test_read_item_bad_token():
response = client.get("/items/foo", headers={"X-Token": "hailhydra"})
assert response.status_code == 400
assert response.json() == {"detail": "Invalid X-Token header"}
def test_read_inexistent_item():
response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
def test_create_item():
response = client.post(
"/items/",
headers={"X-Token": "coneofsilence"},
json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
)
assert response.status_code == 200
assert response.json() == {
"id": "foobar",
"title": "Foo Bar",
"description": "The Foo Barters",
}
def test_create_item_bad_token():
response = client.post(
"/items/",
headers={"X-Token": "hailhydra"},
json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"},
)
assert response.status_code == 400
assert response.json() == {"detail": "Invalid X-Token header"}
def test_create_existing_token():
response = client.post(
"/items/",
headers={"X-Token": "coneofsilence"},
json={
"id": "foo",
"title": "The Foo ID Stealers",
"description": "There goes my stealer",
},
)
assert response.status_code == 400
assert response.json() == {"detail": "Item already exists"}

View File

@@ -0,0 +1,18 @@
from fastapi import FastAPI
from starlette.testclient import TestClient
app = FastAPI()
@app.get("/")
async def read_main():
return {"msg": "Hello World"}
client = TestClient(app)
def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"}

View File

@@ -0,0 +1,31 @@
from fastapi import FastAPI
from starlette.testclient import TestClient
from starlette.websockets import WebSocket
app = FastAPI()
@app.get("/")
async def read_main():
return {"msg": "Hello World"}
@app.websocket_route("/ws")
async def websocket(websocket: WebSocket):
await websocket.accept()
await websocket.send_json({"msg": "Hello WebSocket"})
await websocket.close()
def test_read_main():
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"msg": "Hello World"}
def test_websocket():
client = TestClient(app)
with client.websocket_connect("/ws") as websocket:
data = websocket.receive_json()
assert data == {"msg": "Hello WebSocket"}

View File

@@ -0,0 +1,24 @@
from fastapi import FastAPI
from starlette.testclient import TestClient
app = FastAPI()
items = {}
@app.on_event("startup")
async def startup_event():
items["foo"] = {"name": "Fighters"}
items["bar"] = {"name": "Tenders"}
@app.get("/items/{item_id}")
async def read_items(item_id: str):
return items[item_id]
def test_read_items():
with TestClient(app) as client:
response = client.get("/items/foo")
assert response.status_code == 200
assert response.json() == {"name": "Fighters"}

View File

@@ -1,8 +1,20 @@
from fastapi import FastAPI
from fastapi import Depends, FastAPI, Header, HTTPException
from .routers import items, users
app = FastAPI()
async def get_token_header(x_token: str = Header(...)):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
app.include_router(users.router)
app.include_router(items.router, prefix="/items", tags=["items"])
app.include_router(
items.router,
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)

View File

@@ -1,4 +1,4 @@
from fastapi import APIRouter
from fastapi import APIRouter, HTTPException
router = APIRouter()
@@ -11,3 +11,14 @@ async def read_items():
@router.get("/{item_id}")
async def read_item(item_id: str):
return {"name": "Fake Specific Item", "item_id": item_id}
@router.put(
"/{item_id}",
tags=["custom"],
responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
if item_id != "foo":
raise HTTPException(status_code=403, detail="You can only update the item: foo")
return {"item_id": item_id, "name": "The Fighters"}

View File

@@ -1,8 +1,7 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import UrlStr
from pydantic import BaseModel, UrlStr
app = FastAPI()

View File

@@ -1,8 +1,7 @@
from typing import List, Set
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import UrlStr
from pydantic import BaseModel, UrlStr
app = FastAPI()
@@ -18,7 +17,7 @@ class Item(BaseModel):
price: float
tax: float = None
tags: Set[str] = []
image: List[Image] = None
images: List[Image] = None
@app.put("/items/{item_id}")

View File

@@ -1,8 +1,7 @@
from typing import List, Set
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import UrlStr
from pydantic import BaseModel, UrlStr
app = FastAPI()
@@ -18,7 +17,7 @@ class Item(BaseModel):
price: float
tax: float = None
tags: Set[str] = []
image: List[Image] = None
images: List[Image] = None
class Offer(BaseModel):

View File

@@ -1,8 +1,7 @@
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import UrlStr
from pydantic import BaseModel, UrlStr
app = FastAPI()

View File

@@ -0,0 +1,34 @@
from typing import List
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str = None
description: str = None
price: float = None
tax: float = 10.5
tags: List[str] = []
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: str):
return items[item_id]
@app.put("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item: Item):
update_item_encoded = jsonable_encoder(item)
items[item_id] = update_item_encoded
return update_item_encoded

View File

@@ -0,0 +1,37 @@
from typing import List
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str = None
description: str = None
price: float = None
tax: float = 10.5
tags: List[str] = []
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: str):
return items[item_id]
@app.patch("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item: Item):
stored_item_data = items[item_id]
stored_item_model = Item(**stored_item_data)
update_data = item.dict(skip_defaults=True)
updated_item = stored_item_model.copy(update=update_data)
items[item_id] = jsonable_encoder(updated_item)
return updated_item

View File

@@ -0,0 +1,19 @@
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"http://localhost.tiangolo.com",
"https://localhost.tiangolo.com",
"http:localhost",
"http:localhost:8080",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

View File

@@ -4,6 +4,6 @@ from starlette.responses import UJSONResponse
app = FastAPI()
@app.get("/items/", content_type=UJSONResponse)
@app.get("/items/", response_class=UJSONResponse)
async def read_items():
return [{"item_id": "Foo"}]

View File

@@ -4,7 +4,7 @@ from starlette.responses import HTMLResponse
app = FastAPI()
@app.get("/items/", content_type=HTMLResponse)
@app.get("/items/", response_class=HTMLResponse)
async def read_items():
return """
<html>

View File

@@ -18,6 +18,6 @@ def generate_html_response():
return HTMLResponse(content=html_content, status_code=200)
@app.get("/items/", content_type=HTMLResponse)
@app.get("/items/", response_class=HTMLResponse)
async def read_items():
return generate_html_response()

View File

@@ -1,21 +1,19 @@
from fastapi import Depends, FastAPI
from fastapi import Depends, FastAPI, Header, HTTPException
app = FastAPI()
class FixedContentQueryChecker:
def __init__(self, fixed_content: str):
self.fixed_content = fixed_content
def __call__(self, q: str = ""):
if q:
return self.fixed_content in q
return False
async def verify_token(x_token: str = Header(...)):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
checker = FixedContentQueryChecker("bar")
async def verify_key(x_key: str = Header(...)):
if x_key != "fake-super-secret-key":
raise HTTPException(status_code=400, detail="X-Key header invalid")
return x_key
@app.get("/query-checker/")
async def read_query_check(fixed_content_included: bool = Depends(checker)):
return {"fixed_content_in_query": fixed_content_included}
@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)])
async def read_items():
return [{"item": "Foo"}, {"item": "Bar"}]

View File

@@ -0,0 +1,21 @@
from fastapi import Depends, FastAPI
app = FastAPI()
class FixedContentQueryChecker:
def __init__(self, fixed_content: str):
self.fixed_content = fixed_content
def __call__(self, q: str = ""):
if q:
return self.fixed_content in q
return False
checker = FixedContentQueryChecker("bar")
@app.get("/query-checker/")
async def read_query_check(fixed_content_included: bool = Depends(checker)):
return {"fixed_content_in_query": fixed_content_included}

View File

@@ -0,0 +1,22 @@
from datetime import datetime
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
fake_db = {}
class Item(BaseModel):
title: str
timestamp: datetime
description: str = None
app = FastAPI()
@app.put("/items/{id}")
def update_item(id: str, item: Item):
json_compatible_item_data = jsonable_encoder(item)
fake_db[id] = json_compatible_item_data

View File

@@ -12,5 +12,5 @@ async def startup_event():
@app.get("/items/{item_id}")
async def read_item(item_id: str):
async def read_items(item_id: str):
return items[item_id]

View File

@@ -4,7 +4,7 @@ app = FastAPI()
@app.on_event("shutdown")
def startup_event():
def shutdown_event():
with open("log.txt", mode="a") as log:
log.write("Application shutdown")

View File

@@ -0,0 +1,28 @@
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"name": "Foo"}]
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title="Custom title",
version="2.5.0",
description="This is a very custom OpenAPI schema",
routes=app.routes,
)
openapi_schema["info"]["x-logo"] = {
"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
}
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi

View File

@@ -0,0 +1,35 @@
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class BaseItem(BaseModel):
description: str
type: str
class CarItem(BaseItem):
type = "car"
class PlaneItem(BaseItem):
type = "plane"
size: int
items = {
"item1": {"description": "All my friends drive a low rider", "type": "car"},
"item2": {
"description": "Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5,
},
}
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
async def read_item(item_id: str):
return items[item_id]

View File

@@ -0,0 +1,22 @@
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str
items = [
{"name": "Foo", "description": "There comes my hero"},
{"name": "Red", "description": "It's my aeroplane"},
]
@app.get("/items/", response_model=List[Item])
async def read_items():
return items

View File

@@ -6,7 +6,7 @@ items = {"foo": "The Foo Wrestlers"}
@app.get("/items/{item_id}")
async def create_item(item_id: str):
async def read_item(item_id: str):
if item_id not in items:
raise HTTPException(status_code=404, detail="Item not found")
return {"item": items[item_id]}

View File

@@ -6,7 +6,7 @@ items = {"foo": "The Foo Wrestlers"}
@app.get("/items-header/{item_id}")
async def create_item_header(item_id: str):
async def read_item_header(item_id: str):
if item_id not in items:
raise HTTPException(
status_code=404,

View File

@@ -1,15 +1,26 @@
from fastapi import FastAPI
from starlette.exceptions import HTTPException
from starlette.responses import PlainTextResponse
from starlette.requests import Request
from starlette.responses import JSONResponse
class UnicornException(Exception):
def __init__(self, name: str):
self.name = name
app = FastAPI()
@app.exception_handler(HTTPException)
async def http_exception(request, exc):
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
return JSONResponse(
status_code=418,
content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
)
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/unicorns/{name}")
async def read_unicorn(name: str):
if name == "yolo":
raise UnicornException(name=name)
return {"unicorn_name": name}

View File

@@ -0,0 +1,23 @@
from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.responses import PlainTextResponse
app = FastAPI()
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return PlainTextResponse(str(exc), status_code=400)
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id == 3:
raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
return {"item_id": item_id}

View File

@@ -0,0 +1,28 @@
from fastapi import FastAPI, HTTPException
from fastapi.exception_handlers import (
http_exception_handler,
request_validation_exception_handler,
)
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
app = FastAPI()
@app.exception_handler(StarletteHTTPException)
async def custom_http_exception_handler(request, exc):
print(f"OMG! An HTTP error!: {exc}")
return await http_exception_handler(request, exc)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
print(f"OMG! The client sent invalid data!: {exc}")
return await request_validation_exception_handler(request, exc)
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id == 3:
raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
return {"item_id": item_id}

View File

@@ -0,0 +1,15 @@
import time
from fastapi import FastAPI
from starlette.requests import Request
app = FastAPI()
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response

View File

@@ -18,11 +18,11 @@ class Item(BaseModel):
async def create_item(*, item: Item):
"""
Create an item with all the information:
* name: each item must have a name
* description: a long description
* price: required
* tax: if the item doesn't have tax, you can omit this
* tags: a set of unique tag strings for this item
- **name**: each item must have a name
- **description**: a long description
- **price**: required
- **tax**: if the item doesn't have tax, you can omit this
- **tags**: a set of unique tag strings for this item
"""
return item

View File

@@ -23,11 +23,11 @@ class Item(BaseModel):
async def create_item(*, item: Item):
"""
Create an item with all the information:
* name: each item must have a name
* description: a long description
* price: required
* tax: if the item doesn't have tax, you can omit this
* tags: a set of unique tag strings for this item
- **name**: each item must have a name
- **description**: a long description
- **price**: required
- **tax**: if the item doesn't have tax, you can omit this
- **tags**: a set of unique tag strings for this item
"""
return item

View File

@@ -0,0 +1,8 @@
from fastapi import FastAPI
app = FastAPI()
@app.get("/files/{file_path:path}")
async def read_user_me(file_path: str):
return {"file_path": file_path}

View File

@@ -0,0 +1,21 @@
from enum import Enum
from fastapi import FastAPI
class ModelName(Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/model/{model_name}")
async def get_model(model_name: ModelName):
if model_name == ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}

View File

@@ -0,0 +1,11 @@
from typing import Optional
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_user_item(item_id: str, limit: Optional[int] = None):
item = {"item_id": item_id, "limit": limit}
return item

View File

@@ -0,0 +1,11 @@
from typing import List
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: List[str] = Query(["foo", "bar"])):
query_items = {"q": q}
return query_items

View File

@@ -0,0 +1,9 @@
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: list = Query(None)):
query_items = {"q": q}
return query_items

View File

@@ -0,0 +1,33 @@
from typing import List
from fastapi import FastAPI, File, UploadFile
from starlette.responses import HTMLResponse
app = FastAPI()
@app.post("/files/")
async def create_files(files: List[bytes] = File(...)):
return {"file_sizes": [len(file) for file in files]}
@app.post("/uploadfiles/")
async def create_upload_files(files: List[UploadFile] = File(...)):
return {"filenames": [file.filename for file in files]}
@app.get("/")
async def main():
content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
"""
return HTMLResponse(content=content)

View File

@@ -0,0 +1,12 @@
from fastapi import FastAPI
from starlette.responses import JSONResponse
app = FastAPI()
@app.post("/cookie/")
def create_cookie():
content = {"message": "Come to the dark side, we have cookies"}
response = JSONResponse(content=content)
response.set_cookie(key="fakesession", value="fake-cookie-session-value")
return response

View File

@@ -0,0 +1,21 @@
from datetime import datetime
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
from starlette.responses import JSONResponse
class Item(BaseModel):
title: str
timestamp: datetime
description: str = None
app = FastAPI()
@app.put("/items/{id}")
def update_item(id: str, item: Item):
json_compatible_item_data = jsonable_encoder(item)
return JSONResponse(content=json_compatible_item_data)

View File

@@ -0,0 +1,20 @@
from fastapi import FastAPI
from starlette.responses import Response
app = FastAPI()
@app.get("/legacy/")
def get_legacy_data():
data = """
<?xml version="1.0"?>
<shampoo>
<Header>
Apply shampoo here.
<Header>
<Body>
You'll have to use soap here.
</Body>
</shampoo>
"""
return Response(content=data, media_type="application/xml")

View File

@@ -0,0 +1,11 @@
from fastapi import FastAPI
from starlette.responses import JSONResponse
app = FastAPI()
@app.get("/headers/")
def get_headers():
content = {"message": "Hello World"}
headers = {"X-Cat-Dog": "alone in the world", "Content-Language": "en-US"}
return JSONResponse(content=content, headers=headers)

View File

@@ -1,4 +1,4 @@
from typing import Set
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
@@ -11,9 +11,9 @@ class Item(BaseModel):
description: str = None
price: float
tax: float = None
tags: Set[str] = []
tags: List[str] = []
@app.post("/items/", response_model=Item)
async def create_item(*, item: Item):
async def create_item(item: Item):
return item

View File

@@ -0,0 +1,26 @@
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = 10.5
tags: List[str] = []
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}", response_model=Item, response_model_skip_defaults=True)
async def read_item(item_id: str):
return items[item_id]

View File

@@ -0,0 +1,37 @@
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = 10.5
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
"baz": {
"name": "Baz",
"description": "There goes my baz",
"price": 50.2,
"tax": 10.5,
},
}
@app.get(
"/items/{item_id}/name",
response_model=Item,
response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
return items[item_id]
@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
return items[item_id]

View File

@@ -0,0 +1,37 @@
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = 10.5
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
"baz": {
"name": "Baz",
"description": "There goes my baz",
"price": 50.2,
"tax": 10.5,
},
}
@app.get(
"/items/{item_id}/name",
response_model=Item,
response_model_include=["name", "description"],
)
async def read_item_name(item_id: str):
return items[item_id]
@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
async def read_item_public_data(item_id: str):
return items[item_id]

View File

@@ -1,4 +1,4 @@
from fastapi import FastAPI, Security
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
@@ -7,5 +7,5 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
@app.get("/items/")
async def read_items(token: str = Security(oauth2_scheme)):
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}

View File

@@ -1,6 +1,6 @@
from typing import Optional
from fastapi import Depends, FastAPI, Security
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
@@ -22,7 +22,7 @@ def fake_decode_token(token):
)
async def get_current_user(token: str = Security(oauth2_scheme)):
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
return user

View File

@@ -1,6 +1,7 @@
from fastapi import Depends, FastAPI, HTTPException, Security
from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
from starlette.status import HTTP_401_UNAUTHORIZED
fake_users_db = {
"johndoe": {
@@ -53,11 +54,13 @@ def fake_decode_token(token):
return user
async def get_current_user(token: str = Security(oauth2_scheme)):
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
if not user:
raise HTTPException(
status_code=400, detail="Invalid authentication credentials"
status_code=HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return user

View File

@@ -1,18 +1,17 @@
from datetime import datetime, timedelta
import jwt
from fastapi import Depends, FastAPI, HTTPException, Security
from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jwt import PyJWTError
from passlib.context import CryptContext
from pydantic import BaseModel
from starlette.status import HTTP_403_FORBIDDEN
from starlette.status import HTTP_401_UNAUTHORIZED
# to get a string like this run:
# openssl rand -hex 32
SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
ALGORITHM = "HS256"
TOKEN_SUBJECT = "access"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
@@ -32,7 +31,7 @@ class Token(BaseModel):
token_type: str
class TokenPayload(BaseModel):
class TokenData(BaseModel):
username: str = None
@@ -83,20 +82,28 @@ def create_access_token(*, data: dict, expires_delta: timedelta = None):
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire, "sub": TOKEN_SUBJECT})
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
async def get_current_user(token: str = Security(oauth2_scheme)):
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
token_data = TokenPayload(**payload)
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except PyJWTError:
raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="Could not validate credentials"
)
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
return user
@@ -107,18 +114,22 @@ async def get_current_active_user(current_user: User = Depends(get_current_user)
@app.post("/token", response_model=Token)
async def route_login_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=400, detail="Incorrect email or password")
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"username": form_data.username}, expires_delta=access_token_expires
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/users/me", response_model=User)
@app.get("/users/me/", response_model=User)
async def read_users_me(current_user: User = Depends(get_current_active_user)):
return current_user

View File

@@ -0,0 +1,175 @@
from datetime import datetime, timedelta
from typing import List
import jwt
from fastapi import Depends, FastAPI, HTTPException, Security
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm,
SecurityScopes,
)
from jwt import PyJWTError
from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
from starlette.status import HTTP_401_UNAUTHORIZED
# to get a string like this run:
# openssl rand -hex 32
SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
fake_users_db = {
"johndoe": {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe@example.com",
"hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
"disabled": False,
},
"alice": {
"username": "alice",
"full_name": "Alice Chains",
"email": "alicechains@example.com",
"hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm",
"disabled": True,
},
}
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: str = None
scopes: List[str] = []
class User(BaseModel):
username: str
email: str = None
full_name: str = None
disabled: bool = None
class UserInDB(User):
hashed_password: str
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="/token",
scopes={"me": "Read information about the current user.", "items": "Read items."},
)
app = FastAPI()
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password):
return pwd_context.hash(password)
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
return False
if not verify_password(password, user.hashed_password):
return False
return user
def create_access_token(*, data: dict, expires_delta: timedelta = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
async def get_current_user(
security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme)
):
if security_scopes.scopes:
authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
else:
authenticate_value = f"Bearer"
credentials_exception = HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": authenticate_value},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, username=username)
except (PyJWTError, ValidationError):
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
for scope in security_scopes.scopes:
if scope not in token_data.scopes:
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Not enough permissions",
headers={"WWW-Authenticate": authenticate_value},
)
return user
async def get_current_active_user(
current_user: User = Security(get_current_user, scopes=["me"])
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
@app.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=400, detail="Incorrect username or password")
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.username, "scopes": form_data.scopes},
expires_delta=access_token_expires,
)
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/users/me/", response_model=User)
async def read_users_me(current_user: User = Depends(get_current_active_user)):
return current_user
@app.get("/users/me/items/")
async def read_own_items(
current_user: User = Security(get_current_active_user, scopes=["items"])
):
return [{"item_id": "Foo", "owner": current_user.username}]
@app.get("/status/")
async def read_system_status(current_user: User = Depends(get_current_user)):
return {"status": "ok"}

View File

@@ -0,0 +1,11 @@
from fastapi import Depends, FastAPI
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
@app.get("/users/me")
def read_current_user(credentials: HTTPBasicCredentials = Depends(security)):
return {"username": credentials.username, "password": credentials.password}

View File

@@ -0,0 +1,22 @@
from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from starlette.status import HTTP_401_UNAUTHORIZED
app = FastAPI()
security = HTTPBasic()
def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
if credentials.username != "foo" or credentials.password != "password":
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
@app.get("/users/me")
def read_current_user(username: str = Depends(get_current_username)):
return {"username": username}

View File

@@ -3,6 +3,7 @@ from sqlalchemy import Boolean, Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import Session, sessionmaker
from starlette.requests import Request
from starlette.responses import Response
# SQLAlchemy specific code, as with any other app
SQLALCHEMY_DATABASE_URI = "sqlite:///./test.db"
@@ -66,7 +67,10 @@ def read_user(user_id: int, db: Session = Depends(get_db)):
@app.middleware("http")
async def db_session_middleware(request: Request, call_next):
request.state.db = SessionLocal()
response = await call_next(request)
request.state.db.close()
response = Response("Internal server error", status_code=500)
try:
request.state.db = SessionLocal()
response = await call_next(request)
finally:
request.state.db.close()
return response

View File

@@ -0,0 +1,6 @@
from fastapi import FastAPI
from starlette.staticfiles import StaticFiles
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")

View File

@@ -0,0 +1,3 @@
h1 {
color: green;
}

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>Item Details</title>
<link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">
</head>
<body>
<h1>Item ID: {{ id }}</h1>
</body>
</html>

View File

@@ -0,0 +1,16 @@
from fastapi import FastAPI
from starlette.requests import Request
from starlette.staticfiles import StaticFiles
from starlette.templating import Jinja2Templates
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
@app.get("/items/{id}")
async def read_item(request: Request, id: str):
return templates.TemplateResponse("item.html", {"request": request, "id": id})

View File

View File

@@ -44,10 +44,9 @@ async def get():
return HTMLResponse(html)
@app.websocket_route("/ws")
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message text was: {data}")
await websocket.close()

View File

@@ -0,0 +1,78 @@
from fastapi import Cookie, Depends, FastAPI, Header
from starlette.responses import HTMLResponse
from starlette.status import WS_1008_POLICY_VIOLATION
from starlette.websockets import WebSocket
app = FastAPI()
html = """
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<form action="" onsubmit="sendMessage(event)">
<label>Item ID: <input type="text" id="itemId" autocomplete="off" value="foo"/></label>
<button onclick="connect(event)">Connect</button>
<br>
<label>Message: <input type="text" id="messageText" autocomplete="off"/></label>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<script>
var ws = null;
function connect(event) {
var input = document.getElementById("itemId")
ws = new WebSocket("ws://localhost:8000/items/" + input.value + "/ws");
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
}
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
</body>
</html>
"""
@app.get("/")
async def get():
return HTMLResponse(html)
async def get_cookie_or_client(
websocket: WebSocket, session: str = Cookie(None), x_client: str = Header(None)
):
if session is None and x_client is None:
await websocket.close(code=WS_1008_POLICY_VIOLATION)
return session or x_client
@app.websocket("/items/{item_id}/ws")
async def websocket_endpoint(
websocket: WebSocket,
item_id: int,
q: str = None,
cookie_or_client: str = Depends(get_cookie_or_client),
):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(
f"Session Cookie or X-Client Header value is: {cookie_or_client}"
)
if q is not None:
await websocket.send_text(f"Query parameter q is: {q}")
await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")

View File

@@ -0,0 +1,235 @@
!!! warning
This is a rather advanced topic.
If you are starting with **FastAPI**, you might not need this.
You can declare additional responses, with additional status codes, media types, descriptions, etc.
Those additional responses will be included in the OpenAPI schema, so they will also appear in the API docs.
But for those additional responses you have to make sure you return a `Response` like `JSONResponse` directly, with your status code and content.
## Additional Response with `model`
You can pass to your *path operation decorators* a parameter `responses`.
It receives a `dict`, the keys are status codes for each response, like `200`, and the values are other `dict`s with the information for each of them.
Each of those response `dict`s can have a key `model`, containing a Pydantic model, just like `response_model`.
**FastAPI** will take that model, generate its JSON Schema and include it in the correct place in OpenAPI.
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!}
```
!!! note
Have in mind that you have to return the `JSONResponse` directly.
!!! info
The `model` key is not part of OpenAPI.
**FastAPI** will take the Pydantic model from there, generate the `JSON Schema`, and put it in the correct place.
The correct place is:
* In the key `content`, that has as value another JSON object (`dict`) that contains:
* A key with the media type, e.g. `application/json`, that contains as value another JSON object, that contains:
* A key `schema`, that has as the value the JSON Schema from the model, here's the correct place.
* **FastAPI** adds a reference here to the global JSON Schemas in another place in your OpenAPI instead of including it directly. This way, other applications and clients can use those JSON Schemas directly, provide better code generation tools, etc.
The generated responses in the OpenAPI for this *path operation* will be:
```JSON hl_lines="3 4 5 6 7 8 9 10 11 12"
{
"responses": {
"404": {
"description": "Additional Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
```
The schemas are referenced to another place inside the OpenAPI schema:
```JSON hl_lines="4 5 6 7 8 9 10 11 12 13 14 15 16"
{
"components": {
"schemas": {
"Message": {
"title": "Message",
"required": [
"message"
],
"type": "object",
"properties": {
"message": {
"title": "Message",
"type": "string"
}
}
},
"Item": {
"title": "Item",
"required": [
"id",
"value"
],
"type": "object",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"value": {
"title": "Value",
"type": "string"
}
}
},
"ValidationError": {
"title": "ValidationError",
"required": [
"loc",
"msg",
"type"
],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"type": "string"
}
},
"msg": {
"title": "Message",
"type": "string"
},
"type": {
"title": "Error Type",
"type": "string"
}
}
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
}
}
}
}
```
## Additional media types for the main response
You can use this same `responses` parameter to add different media types for the same main response.
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!}
```
!!! note
Notice that you have to return the image using a `FileResponse` directly.
## Combining information
You can also combine response information from multiple places, including the `response_model`, `status_code`, and `responses` parameters.
You can declare a `response_model`, using the default status code `200` (or a custom one if you need), and then declare additional information for that same response in `responses`, directly in the OpenAPI schema.
**FastAPI** will keep the additional information from `responses`, and combine it with the JSON Schema from your model.
For example, you can declare a response with a status code `404` that uses a Pydantic model and has a custom `description`.
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!}
```
It will all be combined and included in your OpenAPI, and shown in the API docs:
<img src="/img/tutorial/additional-responses/image01.png">
## Combine predefined responses and custom ones
You might want to have some predefined responses that apply to many *path operations*, but you want to combine them with custom responses needed by each *path operation*.
For those cases, you can use the Python technique of "unpacking" a `dict` with `**dict_to_unpack`:
```Python
old_dict = {
"old key": "old value",
"second old key": "second old value",
}
new_dict = {**old_dict, "new key": "new value"}
```
Here, `new_dict` will contain all the key-value pairs from `old_dict` plus the new key-value pair:
```Python
{
"old key": "old value",
"second old key": "second old value",
"new key": "new value",
}
```
You can use that technique to re-use some predefined responses in your *path operations* and combine them with additional custom ones.
For example:
```Python hl_lines="11 12 13 14 15 24"
{!./src/additional_responses/tutorial004.py!}
```
## More information about OpenAPI responses
To see what exactly you can include in the responses, you can check these sections in the OpenAPI specification:
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" target="_blank">OpenAPI Responses Object</a>, it includes the `Response Object`.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" target="_blank">OpenAPI Response Object</a>, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`.

View File

@@ -0,0 +1,30 @@
By default, **FastAPI** will return the responses using Starlette's `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*.
## Additional status codes
If you want to return additional status codes apart from the main one, you can do that by returning a `Response` directly, like a `JSONResponse`, and set the additional status code directly.
For example, let's say that you want to have a *path operation* that allows to update items, and returns HTTP status codes of 200 "OK" when successful.
But you also want it to accept new items. And when the items didn't exist before, it creates them, and returns an HTTP status code of 201 "Created".
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
```Python hl_lines="2 20"
{!./src/additional_status_codes/tutorial001.py!}
```
!!! warning
When you return a `Response` directly, like in the example above, it will be returned directly.
It won't be serialized with a model, etc.
Make sure it has the data you want it to have, and that the values are valid JSON (if you are using `JSONResponse`).
## OpenAPI and API docs
If you return additional status codes and responses directly, they won't be included in the OpenAPI schema (the API docs), because FastAPI doesn't have a way to know before hand what you are going to return.
But you can document that in your code, using: <a href="https://fastapi.tiangolo.com/tutorial/additional-responses/" target="_blank">Additional Responses</a>.

View File

@@ -81,6 +81,16 @@ It's still possible to use `BackgroundTask` alone in FastAPI, but you have to cr
You can see more details in <a href="https://www.starlette.io/background/" target="_blank">Starlette's official docs for Background Tasks</a>.
## Caveat
If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like <a href="http://www.celeryproject.org/" target="_blank">Celery</a>.
They tend to require more complex configurations, a message/job queue manager, like RabbitMQ or Redis, but they allow you to run background tasks in multiple processes, and especially, in multiple servers.
To see an example, check the <a href="https://fastapi.tiangolo.com/project-generation/" target="_blank">Project Generators</a>, they all include Celery already configured.
But if you need to access variables and objects from the same **FastAPI** app, or you need to perform small background tasks (like sending an email notification), you can simply just use `BackgroundTasks`.
## Recap
Import and use `BackgroundTasks` with parameters in *path operation functions* and dependencies to add background tasks.

View File

@@ -22,16 +22,15 @@ Let's say you have a file structure like this:
!!! tip
There are two `__init__.py` files: one in each directory or subdirectory.
This is what allows importing code from one file into another.
For example, in `app/main.py` you could have a line like:
```
from app.routers import items
```
* The `app` directory contains everything.
* This `app` directory has an empty file `app/__init__.py`.
* So, the `app` directory is a "Python package" (a collection of "Python modules").
@@ -103,7 +102,17 @@ 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 16"
```Python hl_lines="6 11"
{!./src/bigger_applications/app/routers/items.py!}
```
### Add some custom `tags`, `responses`, and `dependencies`
We are not adding the prefix `/items/` nor the `tags=["items"]` to add them later.
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!}
```
@@ -187,12 +196,11 @@ So, to be able to use both of them in the same file, we import the submodules di
{!./src/bigger_applications/app/main.py!}
```
### Include an `APIRouter`
Now, let's include the `router` from the submodule `users`:
```Python hl_lines="8"
```Python hl_lines="13"
{!./src/bigger_applications/app/main.py!}
```
@@ -211,15 +219,14 @@ It will include all the routes from that router as part of it.
!!! check
You don't have to worry about performance when including routers.
This will take microseconds and will only happen at startup.
So it won't affect performance.
### Include an `APIRouter` with a `prefix`, `tags`, `responses`, and `dependencies`
### Include an `APIRouter` with a prefix
Now, let's include the router form the `items` submodule.
Now, let's include the router from the `items` submodule.
But, remember that we were lazy and didn't add `/items/` nor `tags` to all the *path operations*?
@@ -237,9 +244,13 @@ async def read_item(item_id: str):
So, the prefix in this case would be `/items`.
And we can also add a list of `tags` that will be applied to all the *path operations* included in this router:
We can also add a list of `tags` that will be applied to all the *path operations* included in this router.
```Python hl_lines="9"
And we can add predefined `responses` that will be included in all the *path operations* too.
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.
```Python hl_lines="8 9 10 14 15 16 17 18 19 20"
{!./src/bigger_applications/app/main.py!}
```
@@ -250,21 +261,28 @@ The end result is that the item paths are now:
...as we intended.
And they are marked with a list of tags that contain a single string `"items"`.
* They will be marked with a list of tags that contain a single string `"items"`.
* The *path operation* that declared a `"custom"` tag will have both tags, `items` and `custom`.
* These "tags" are especially useful for the automatic interactive documentation systems (using OpenAPI).
* All of them will include the predefined `responses`.
* The *path operation* that declared a custom `403` response will have both the predefined responses (`404`) and the `403` declared in it directly.
* All these *path operations* will have the list of `dependencies` evaluated/executed before them.
* If you also declare dependencies in a specific *path operation*, **they will be executed too**.
* The router dependencies are executed first, then the <a href="https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-decorator/" target="_blank">`dependencies` in the decorator</a>, and then the normal parameter dependencies.
* You can also add <a href="https://fastapi.tiangolo.com/tutorial/security/oauth2-scopes/" target="_blank">`Security` dependencies with `scopes`</a>.
These "tags" are especially useful for the automatic interactive documentation systems (using OpenAPI).
!!! tip
Having `dependencies` in a decorator can be used, for example, to require authentication for a whole group of *path operations*. Even if the dependencies are not added individually to each one of them.
!!! check
The `prefix` and `tags` parameters are (as in many other cases) just a feature from **FastAPI** to help you avoid code duplication.
The `prefix`, `tags`, `responses` and `dependencies` parameters are (as in many other cases) just a feature from **FastAPI** to help you avoid code duplication.
!!! tip
You could also add path operations directly, for example with: `@app.get(...)`.
Apart from `app.include_router()`, in the same **FastAPI** app.
It would still work the same.
Apart from `app.include_router()`, in the same **FastAPI** app.
It would still work the same.
!!! info "Very Technical Details"
**Note**: this is a very technical detail that you probably can **just skip**.

View File

@@ -120,7 +120,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 `UrlStr`:
```Python hl_lines="5 11"
```Python hl_lines="4 10"
{!./src/body_nested_models/tutorial005.py!}
```
@@ -130,7 +130,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="21"
```Python hl_lines="20"
{!./src/body_nested_models/tutorial006.py!}
```
@@ -167,7 +167,7 @@ This will expect (convert, validate, document, etc) a JSON body like:
You can define arbitrarily deeply nested models:
```Python hl_lines="10 15 21 24 28"
```Python hl_lines="9 14 20 23 27"
{!./src/body_nested_models/tutorial007.py!}
```
@@ -184,7 +184,7 @@ images: List[Image]
as in:
```Python hl_lines="16"
```Python hl_lines="15"
{!./src/body_nested_models/tutorial008.py!}
```

View File

@@ -22,12 +22,13 @@ You can then use `Schema` with model attributes:
`Schema` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc.
!!! info
!!! note "Technical Details"
Actually, `Query`, `Path` and others you'll see next are subclasses of a common `Param` which is itself a subclass of Pydantic's `Schema`.
`Body` is also a subclass of `Schema` directly. And there are others you will see later that are subclasses of `Body`.
But remember that when you import `Query`, `Path` and others from `fastapi`, <a href="https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#recap" target="_blank">those are actually functions that return classes of the same name</a>.
!!! tip
Notice how each model's attribute with a type, default value and `Schema` has the same structure as a path operation function's parameter, with `Schema` instead of `Path`, `Query` and `Body`.

View File

@@ -0,0 +1,97 @@
## Update replacing with `PUT`
To update an item you can use the [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) operation.
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!}
```
`PUT` is used to receive data that should replace the existing data.
### Warning about replacing
That means that if you want to update the item `bar` using `PUT` with a body containing:
```Python
{
"name": "Barz",
"price": 3,
"description": None,
}
```
because it doesn't include the already stored attribute `"tax": 20.2`, the input model would take the default value of `"tax": 10.5`.
And the data would be saved with that "new" `tax` of `10.5`.
## Partial updates with `PATCH`
You can also use the [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) operation to *partially* update data.
This means that you can send only the data that you want to update, leaving the rest intact.
!!! Note
`PATCH` is less commonly used and known than `PUT`.
And many teams use only `PUT`, even for partial updates.
You are **free** to use them however you want, **FastAPI** doesn't impose any restrictions.
But this guide shows you, more or less, how they are intended to be used.
### Using Pydantic's `skip_defaults` parameter
If you want to receive partial updates, it's very useful to use the parameter `skip_defaults` in Pydantic's model's `.dict()`.
Like `item.dict(skip_defaults=True)`.
That would generate a `dict` with only the data that was set when creating the `item` model, excluding default values.
Then you can use this to generate a `dict` with only the data that was set, omitting default values:
```Python hl_lines="34"
{!./src/body_updates/tutorial002.py!}
```
### Using Pydantic's `update` parameter
Now, you can create a copy of the existing model using `.copy()`, and pass the `update` parameter with a `dict` containing the data to update.
Like `stored_item_model.copy(update=update_data)`:
```Python hl_lines="35"
{!./src/body_updates/tutorial002.py!}
```
### Partial updates recap
In summary, to apply partial updates you would:
* (Optionally) use `PATCH` instead of `PUT`.
* Retrieve the stored data.
* Put that data in a Pydantic model.
* Generate a `dict` without default values from the input model (using `skip_defaults`).
* This way you can update only the values actually set by the user, instead of overriding values already stored with default values in your model.
* Create a copy of the stored model, updating it's attributes with the received partial updates (using the `update` parameter).
* Convert the copied model to something that can be stored in your DB (for example, using the `jsonable_encoder`).
* This is comparable to using the model's `.dict()` method again, but it makes sure (and converts) the values to data types that can be converted to JSON, for example, `datetime` to `str`.
* Save the data to your DB.
* Return the updated model.
```Python hl_lines="30 31 32 33 34 35 36 37"
{!./src/body_updates/tutorial002.py!}
```
!!! tip
You can actually use this same technique with an HTTP `PUT` operation.
But the example here uses `PATCH` because it was created for these use cases.
!!! note
Notice that the input model is still validated.
So, if you want to receive partial updates that can omit all the attributes, you need to have a model with all the attributes marked as optional (with default values or `None`).
To distinguish from the models with all optional values for **updates** and models with required values for **creation**, you can use the ideas described in <a href="https://fastapi.tiangolo.com/tutorial/extra-models/" target="_blank">Extra Models</a>.

View File

@@ -18,9 +18,11 @@ The first value is the default value, you can pass all the extra validation or a
{!./src/cookie_params/tutorial001.py!}
```
!!! info
!!! note "Technical Details"
`Cookie` is a "sister" class of `Path` and `Query`. It also inherits from the same common `Param` class.
But remember that when you import `Query`, `Path`, `Cookie` and others from `fastapi`, <a href="https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#recap" target="_blank">those are actually functions that return classes of the same name</a>.
!!! info
To declare cookies, you need to use `Cookie`, because otherwise the parameters would be interpreted as query parameters.

55
docs/tutorial/cors.md Normal file
View File

@@ -0,0 +1,55 @@
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" 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
An origin is the combination of protocol (`http`, `https`), domain (`myapp.com`, `localhost`, `localhost.tiangolo.com`), and port (`80`, `443`, `8080`).
So, all these are different origins:
* `http://localhost`
* `https://localhost`
* `http://localhost:8080`
Even if they are all in `localhost`, they use different protocols or ports, so, they are different "origins".
## Steps
So, let's say you have a frontend running in your browser at `http://localhost:8080`, and its JavaScript is trying to communicate with a backend running at `http://localhost` (because we don't specify a port, the browser will assume the default port `80`).
Then, the browser will send an HTTP `OPTIONS` request to the backend, and if the backend sends the appropriate headers authorizing the communication from this different origin (`http://localhost:8080`) then the browser will let the JavaScript in the frontend send its request to the backend.
To achieve this, the backend must have a list of "allowed origins".
In this case, it would have to include `http://localhost:8080` for the frontend to work correctly.
## Wildcards
It's also possible to declare the list as `"*"` (a "wildcard") to say that all are allowed.
But that will only allow certain types of communication, excluding everything that involves credentials: Cookies, Authorization headers like those used with Bearer Tokens, etc.
So, for everything to work correctly, it's better to specify explicitly the allowed origins.
## Use `CORSMiddleware`
You can configure it in your **FastAPI** application using Starlette's <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">`CORSMiddleware`</a>.
* Import it from Starlette.
* Create a list of allowed origins (as strings).
* Add it as a "middleware" to your **FastAPI** application.
You can also specify if your backend allows:
* Credentials (Authorization headers, Cookies, etc).
* Specific HTTP methods (`POST`, `PUT`) or all of them with the wildcard `"*"`.
* 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!}
```
## More info
For more details of what you can specify in `CORSMiddleware`, check <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">Starlette's `CORSMiddleware` docs</a>.
For more info about <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank">Mozilla CORS documentation</a>.

View File

@@ -1,98 +1,88 @@
!!! warning
This is a rather advanced topic.
If you are starting with **FastAPI**, you might not need this.
By default, **FastAPI** will return the responses using Starlette's `JSONResponse`.
But you can override it.
You can override it by returning a `Response` directly, <a href="https://fastapi.tiangolo.com/tutorial/response-directly/" target="_blank">as seen in a previous section</a>.
But if you return a `Response` directly, the data won't be automatically converted, and the documentation won't be automatically generated (for example, including the specific "media type", in the HTTP header `Content-Type`).
But you can also declare the `Response` that you want to be used, in the *path operation decorator*.
The contents that you return from your *path operation function* will be put inside of that `Response`.
And if that `Response` has a JSON media type (`application/json`), like is the case with the `JSONResponse` and `UJSONResponse`, the data you return will be automatically converted (and filtered) with any Pydantic `response_model` that you declared in the *path operation decorator*.
## Use `UJSONResponse`
For example, if you are squeezing performance, you can use `ujson` and set the response to be Starlette's `UJSONResponse`.
For example, if you are squeezing performance, you can install and use `ujson` and set the response to be Starlette's `UJSONResponse`.
### Import `UJSONResponse`
Import the `Response` class (sub-class) you want to use and declare it in the *path operation decorator*.
```Python hl_lines="2"
```Python hl_lines="2 7"
{!./src/custom_response/tutorial001.py!}
```
!!! note
Notice that you import it directly from `starlette.responses`, not from `fastapi`.
### Make your path operation use it
Make your path operation use `UJSONResponse` as the response class using the parameter `content_type`:
```Python hl_lines="7"
{!./src/custom_response/tutorial001.py!}
```
!!! info
The parameter is called `content_type` because it will also be used to define the "media type" of the response.
The parameter `response_class` will also be used to define the "media type" of the response.
And will be documented as such in OpenAPI.
In this case, the HTTP header `Content-Type` will be set to `application/json`.
And it will be documented as such in OpenAPI.
## HTML Response
To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
### Import `HTMLResponse`
* Import `HTMLResponse`.
* Pass `HTMLResponse` as the parameter `content_type` of your path operation.
```Python hl_lines="2"
```Python hl_lines="2 7"
{!./src/custom_response/tutorial002.py!}
```
!!! note
Notice that you import it directly from `starlette.responses`, not from `fastapi`.
### Define your `content_type` class
Pass `HTMLResponse` as the parameter `content_type` of your path operation:
```Python hl_lines="7"
{!./src/custom_response/tutorial002.py!}
```
!!! info
The parameter is called `content_type` because it will also be used to define the "media type" of the response.
The parameter `response_class` will also be used to define the "media type" of the response.
In this case, the HTTP header `Content-Type` will be set to `text/html`.
And it will be documented as such in OpenAPI.
### Return a Starlette `Response`
You can also override the response directly in your path operation.
If you return an object that is an instance of Starlette's `Response`, it will be used as the response directly.
As seen in <a href="https://fastapi.tiangolo.com/tutorial/response-directly/" target="_blank">another section</a>, you can also override the response directly in your path operation, by returning it.
The same example from above, returning an `HTMLResponse`, could look like:
```Python hl_lines="7"
```Python hl_lines="2 7 19"
{!./src/custom_response/tutorial003.py!}
```
!!! info
Of course, the `Content-Type` header will come from the the `Response` object your returned.
!!! warning
A `Response` returned directly by your path operation function won't be documented in OpenAPI and won't be visible in the automatic interactive docs.
A `Response` returned directly by your path operation function won't be documented in OpenAPI (for example, the `Content-Type` won't be documented) and won't be visible in the automatic interactive docs.
!!! info
Of course, the actual `Content-Type` header, status code, etc, will come from the `Response` object your returned.
### Document in OpenAPI and override `Response`
If you want to override the response from inside of the function but at the same time document the "media type" in OpenAPI, you can use the `content_type` parameter AND return a `Response` object.
If you want to override the response from inside of the function but at the same time document the "media type" in OpenAPI, you can use the `response_class` parameter AND return a `Response` object.
The `content_type` class will then be used only to document the OpenAPI path operation, but your `Response` will be used as is.
The `response_class` will then be used only to document the OpenAPI path operation, but your `Response` will be used as is.
#### Return an `HTMLResponse` directly
For example, it could be something like:
```Python hl_lines="7 23"
```Python hl_lines="7 23 21"
{!./src/custom_response/tutorial004.py!}
```
@@ -100,16 +90,10 @@ In this example, the function `generate_html_response()` already generates a Sta
By returning the result of calling `generate_html_response()`, you are already returning a `Response` that will override the default **FastAPI** behavior.
#### Declare `HTMLResponse` as `content_type`
But by declaring it also in the path operation decorator:
```Python hl_lines="21"
{!./src/custom_response/tutorial004.py!}
```
#### OpenAPI knows how to document it
...**FastAPI** will be able to document it in OpenAPI and in the interactive docs as HTML with `text/html`:
But as you passed the `HTMLResponse` in the `response_class`, **FastAPI** will know how to document it in OpenAPI and the interactive docs as HTML with `text/html`:
<img src="/img/tutorial/custom-response/image01.png">
## Additional documentation
You can also declare the media type and many other details in OpenAPI using `responses`: <a href="https://fastapi.tiangolo.com/tutorial/additional-responses/" target="_blank">Additional Responses in OpenAPI</a>.

View File

@@ -69,7 +69,7 @@ will not be executed.
## Run your code with your debugger
Because you are running the Uvicorn server directly from your code, you can call your Python program (your FastAPI application) directly form the debugger.
Because you are running the Uvicorn server directly from your code, you can call your Python program (your FastAPI application) directly from the debugger.
---

Some files were not shown because too many files have changed in this diff Show More