From ea43f227e5c7128c09e3e2d5dceea212552b19dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Aug 2023 21:10:22 +0200 Subject: [PATCH 01/54] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20disabli?= =?UTF-8?q?ng=20the=20separation=20of=20input=20and=20output=20JSON=20Sche?= =?UTF-8?q?mas=20in=20OpenAPI=20with=20Pydantic=20v2=20(#10145)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 📝 Add docs for Separate OpenAPI Schemas for Input and Output * 🔧 Add new docs page to MkDocs config * ✨ Add separate_input_output_schemas parameter to FastAPI class * 📝 Add source examples for separating OpenAPI schemas * ✅ Add tests for separated OpenAPI schemas * 📝 Add source examples for Python 3.10, 3.9, and 3.7+ * 📝 Update docs for Separate OpenAPI Schemas with new multi-version examples * ✅ Add and update tests for different Python versions * ✅ Add tests for corner cases with separate_input_output_schemas * 📝 Update tutorial to use Union instead of Optional * 🐛 Fix type annotations * 🐛 Fix correct import in test * 💄 Add CSS to simulate browser windows for screenshots * ➕ Add playwright as a dev dependency to automate generating screenshots * 🔨 Add Playwright scripts to generate screenshots for new docs * 📝 Update docs, tweak text to match screenshots * 🍱 Add screenshots for new docs --- docs/en/docs/css/custom.css | 36 ++ .../docs/how-to/separate-openapi-schemas.md | 228 ++++++++ .../separate-openapi-schemas/image01.png | Bin 0 -> 81548 bytes .../separate-openapi-schemas/image02.png | Bin 0 -> 92417 bytes .../separate-openapi-schemas/image03.png | Bin 0 -> 85171 bytes .../separate-openapi-schemas/image04.png | Bin 0 -> 58285 bytes .../separate-openapi-schemas/image05.png | Bin 0 -> 45618 bytes docs/en/mkdocs.yml | 1 + .../separate_openapi_schemas/tutorial001.py | 28 + .../tutorial001_py310.py | 26 + .../tutorial001_py39.py | 28 + .../separate_openapi_schemas/tutorial002.py | 28 + .../tutorial002_py310.py | 26 + .../tutorial002_py39.py | 28 + fastapi/_compat.py | 15 +- fastapi/applications.py | 3 + fastapi/openapi/utils.py | 14 + requirements.txt | 2 + .../separate_openapi_schemas/image01.py | 29 ++ .../separate_openapi_schemas/image02.py | 30 ++ .../separate_openapi_schemas/image03.py | 30 ++ .../separate_openapi_schemas/image04.py | 29 ++ .../separate_openapi_schemas/image05.py | 29 ++ ...t_openapi_separate_input_output_schemas.py | 490 ++++++++++++++++++ .../test_separate_openapi_schemas/__init__.py | 0 .../test_tutorial001.py | 147 ++++++ .../test_tutorial001_py310.py | 150 ++++++ .../test_tutorial001_py39.py | 150 ++++++ .../test_tutorial002.py | 133 +++++ .../test_tutorial002_py310.py | 136 +++++ .../test_tutorial002_py39.py | 136 +++++ 31 files changed, 1950 insertions(+), 2 deletions(-) create mode 100644 docs/en/docs/how-to/separate-openapi-schemas.md create mode 100644 docs/en/docs/img/tutorial/separate-openapi-schemas/image01.png create mode 100644 docs/en/docs/img/tutorial/separate-openapi-schemas/image02.png create mode 100644 docs/en/docs/img/tutorial/separate-openapi-schemas/image03.png create mode 100644 docs/en/docs/img/tutorial/separate-openapi-schemas/image04.png create mode 100644 docs/en/docs/img/tutorial/separate-openapi-schemas/image05.png create mode 100644 docs_src/separate_openapi_schemas/tutorial001.py create mode 100644 docs_src/separate_openapi_schemas/tutorial001_py310.py create mode 100644 docs_src/separate_openapi_schemas/tutorial001_py39.py create mode 100644 docs_src/separate_openapi_schemas/tutorial002.py create mode 100644 docs_src/separate_openapi_schemas/tutorial002_py310.py create mode 100644 docs_src/separate_openapi_schemas/tutorial002_py39.py create mode 100644 scripts/playwright/separate_openapi_schemas/image01.py create mode 100644 scripts/playwright/separate_openapi_schemas/image02.py create mode 100644 scripts/playwright/separate_openapi_schemas/image03.py create mode 100644 scripts/playwright/separate_openapi_schemas/image04.py create mode 100644 scripts/playwright/separate_openapi_schemas/image05.py create mode 100644 tests/test_openapi_separate_input_output_schemas.py create mode 100644 tests/test_tutorial/test_separate_openapi_schemas/__init__.py create mode 100644 tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py create mode 100644 tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py310.py create mode 100644 tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py39.py create mode 100644 tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py create mode 100644 tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py310.py create mode 100644 tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py39.py diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css index 066b51725..187040792 100644 --- a/docs/en/docs/css/custom.css +++ b/docs/en/docs/css/custom.css @@ -144,3 +144,39 @@ code { margin-top: 2em; margin-bottom: 2em; } + +/* Screenshots */ +/* +Simulate a browser window frame. +Inspired by Termynal's CSS tricks with modifications +*/ + +.screenshot { + display: block; + background-color: #d3e0de; + border-radius: 4px; + padding: 45px 5px 5px; + position: relative; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.screenshot img { + display: block; + border-radius: 2px; +} + +.screenshot:before { + content: ''; + position: absolute; + top: 15px; + left: 15px; + display: inline-block; + width: 15px; + height: 15px; + border-radius: 50%; + /* A little hack to display the window buttons in one pseudo element. */ + background: #d9515d; + -webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930; + box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930; +} diff --git a/docs/en/docs/how-to/separate-openapi-schemas.md b/docs/en/docs/how-to/separate-openapi-schemas.md new file mode 100644 index 000000000..39d96ea39 --- /dev/null +++ b/docs/en/docs/how-to/separate-openapi-schemas.md @@ -0,0 +1,228 @@ +# Separate OpenAPI Schemas for Input and Output or Not + +When using **Pydantic v2**, the generated OpenAPI is a bit more exact and **correct** than before. 😎 + +In fact, in some cases, it will even have **two JSON Schemas** in OpenAPI for the same Pydantic model, for input and output, depending on if they have **default values**. + +Let's see how that works and how to change it if you need to do that. + +## Pydantic Models for Input and Output + +Let's say you have a Pydantic model with default values, like this one: + +=== "Python 3.10+" + + ```Python hl_lines="7" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-7]!} + + # Code below omitted 👇 + ``` + +
+ 👀 Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py!} + ``` + +
+ +=== "Python 3.9+" + + ```Python hl_lines="9" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-9]!} + + # Code below omitted 👇 + ``` + +
+ 👀 Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py!} + ``` + +
+ +=== "Python 3.7+" + + ```Python hl_lines="9" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-9]!} + + # Code below omitted 👇 + ``` + +
+ 👀 Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py!} + ``` + +
+ +### Model for Input + +If you use this model as an input like here: + +=== "Python 3.10+" + + ```Python hl_lines="14" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-15]!} + + # Code below omitted 👇 + ``` + +
+ 👀 Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py!} + ``` + +
+ +=== "Python 3.9+" + + ```Python hl_lines="16" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-17]!} + + # Code below omitted 👇 + ``` + +
+ 👀 Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py!} + ``` + +
+ +=== "Python 3.7+" + + ```Python hl_lines="16" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-17]!} + + # Code below omitted 👇 + ``` + +
+ 👀 Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py!} + ``` + +
+ +...then the `description` field will **not be required**. Because it has a default value of `None`. + +### Input Model in Docs + +You can confirm that in the docs, the `description` field doesn't have a **red asterisk**, it's not marked as required: + +
+ +
+ +### Model for Output + +But if you use the same model as an output, like here: + +=== "Python 3.10+" + + ```Python hl_lines="19" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="21" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py!} + ``` + +=== "Python 3.7+" + + ```Python hl_lines="21" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py!} + ``` + +...then because `description` has a default value, if you **don't return anything** for that field, it will still have that **default value**. + +### Model for Output Response Data + +If you interact with the docs and check the response, even though the code didn't add anything in one of the `description` fields, the JSON response contains the default value (`null`): + +
+ +
+ +This means that it will **always have a value**, it's just that sometimes the value could be `None` (or `null` in JSON). + +That means that, clients using your API don't have to check if the value exists or not, they can **asume the field will always be there**, but just that in some cases it will have the default value of `None`. + +The way to describe this in OpenAPI, is to mark that field as **required**, because it will always be there. + +Because of that, the JSON Schema for a model can be different depending on if it's used for **input or output**: + +* for **input** the `description` will **not be required** +* for **output** it will be **required** (and possibly `None`, or in JSON terms, `null`) + +### Model for Output in Docs + +You can check the output model in the docs too, **both** `name` and `description` are marked as **required** with a **red asterisk**: + +
+ +
+ +### Model for Input and Output in Docs + +And if you check all the available Schemas (JSON Schemas) in OpenAPI, you will see that there are two, one `Item-Input` and one `Item-Output`. + +For `Item-Input`, `description` is **not required**, it doesn't have a red asterisk. + +But for `Item-Output`, `description` is **required**, it has a red asterisk. + +
+ +
+ +With this feature from **Pydantic v2**, your API documentation is more **precise**, and if you have autogenerated clients and SDKs, they will be more precise too, with a better **developer experience** and consistency. 🎉 + +## Do not Separate Schemas + +Now, there are some cases where you might want to have the **same schema for input and output**. + +Probably the main use case for this is if you already have some autogenerated client code/SDKs and you don't want to update all the autogenerated client code/SDKs yet, you probably will want to do it at some point, but maybe not right now. + +In that case, you can disable this feature in **FastAPI**, with the parameter `separate_input_output_schemas=False`. + +=== "Python 3.10+" + + ```Python hl_lines="10" + {!> ../../../docs_src/separate_openapi_schemas/tutorial002_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="12" + {!> ../../../docs_src/separate_openapi_schemas/tutorial002_py39.py!} + ``` + +=== "Python 3.7+" + + ```Python hl_lines="12" + {!> ../../../docs_src/separate_openapi_schemas/tutorial002.py!} + ``` + +### Same Schema for Input and Output Models in Docs + +And now there will be one single schema for input and output for the model, only `Item`, and it will have `description` as **not required**: + +
+ +
+ +This is the same behavior as in Pydantic v1. 🤓 diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image01.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..aa085f88df45e53aaddb11e35b346075eeff2670 GIT binary patch literal 81548 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¥b$&#Qf4~ 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image02.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image02.png new file mode 100644 index 0000000000000000000000000000000000000000..672ef1d2b71df96e9046fd3080ba5d2837721e41 GIT binary patch literal 92417 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%0A=&HIJw6ofo2IQv*&ppKc@i)9TDSQ1L41B(-m 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 ZmdSXHb5bb@l<>c~vlh+_pKh`HKLGA#a;E?Q literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image03.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image03.png new file mode 100644 index 0000000000000000000000000000000000000000..81340fbece9420cb01981aeb401fc3a6f532e047 GIT binary patch literal 85171 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image04.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image04.png new file mode 100644 index 0000000000000000000000000000000000000000..fc2302aa77ce27ef23caeb7ef0144725c919738a GIT binary patch literal 58285 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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image05.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image05.png new file mode 100644 index 0000000000000000000000000000000000000000..674dd0b2e273078ffea526c0dd8572547a4c04f2 GIT binary patch literal 45618 zcmeFZXH-+&*Do3yJc|7h5D>5c3J54or3xqzkRrW>sPq7#gOmgn6%`>GN~HH*LJJ)N zq99#L2!swoXrYIa5I8&j-}l}-#`${BIA7i|cG@m$?=}1U&AIYXUsvPIDehAs5aJm&Y($auPC-A^k( zFkIk#z$)*FBP!%QL1rsZ7w0Os0m&YwN0>#X>BYfFmz$*FDU)S)j2i|7462K=xd8B#k6@Cs&IJVH5x;d^CR{CxAQ zm{qC8-ideNikGsBf1eNMzPp?8W^M3uPx*dhzsN25m)z=uYpM*(g*sWii*Erb`E7gQ zm52H_8Mlun*s;-}=A6OFBlXho&JS{x&|>B`fY1>&?gWN4k*!pD@8$@dPg zdjH5!*F?ejMEGEVzxLw5w#!*Ox?G9MD>lT~`Tv}j;W|{8t~*s}{_fqlrl1Q(An1!Aydzo`iR#R@w*6-QBN1)tOOlNIWfj<=ZZy z-PbT$O^Rkjwkll@sSy#kO%ZT%>voAY;q!FFp$_BSviM+38?;X)KbrBd#C z?1WN%4Q#sVsU#O~7?+k-$JV&U#G<=35=WFqee8o&T8ZU%Wn~{4GM>128@+{BuSo9E z>0oq$Nj~zM64bJCwP-sIAikn|50#K~h&QG{lJ;b{gSLnVq6CF1l;udmG%w9|?4h}9 zQR=~*$_V>~p{M8@`aK6TLYPfXpV+*l5@IzKlTc{{b*pQfsghII8Q6tGf4OX71ZFY3 zzc(0q&X#kW1SCgDQwIJ0Y@5p#k-QXotNvMd$DaP7Nev^Ro?v|rn3i<8di)WksL1?` zjHrNxe6Q^7Q)kcSVH&yx*x92kYR5O19m96baBxCeH)58|={ORx7&5jVgb2DcqF~Ww zlRj%x#K88pbd4Ar7%UoaUY^7%)z_K^cD?VChn>c&ygm}AaG=U1z` z*_w{6J|6xW9KS*erp6bJl`Wih=EVw(c~dR{RLV_DGni#(KXvkK-)v+nY-d~`8e{sh zP6(f(&m+6KcAu?IW=5*=3^r?Pzl{r77FKbq@EPuf8f%WfJO5)AA3_wL^1?_Lr~C-( z?jyNotbos_xQt;r?pN`wJ09;RmZuA~+MuZ>&zsq~28>TmHOt(ZIwB~9UzB8l8Ws!r zCJUuE74)@Vi9M}!YSS&<1ESpbx_Q&s>gz(E(zT!}7NOB>lc^gCuZJVwl!lPv*15_W znX)0tEe4XXuF=BcWpLKCfZ2Dg-rXrkY9BGy)@M3EapOlAUk`ONn1Ts^lcw$oVffS@2Id=yae)$Gi?px)fep%~z1wVgmER5%_y6bgy z(N28$M#ouAG)pBdTcFLp@|WYC4&s%(s^2PF5}Hv0xUjl;&2zqp5@e1@p`hgD&o%zP zeNXJQ+>-o-umY~{08WSH|F#r;G3y4;!Y5(`+fq25tBuCIs6<`KKKm6jutupy+W++= zai@}wz@JrzZf@;|xz!SsUmj9Eef%hw+JI!Zn&Zf_uERy2J6(RtqLilYCgqfGJ*nU8 z)`;7tNCd3CmS3cVUdVMamq|jouIx5=dhvE7dUr-uUoB`$OLB-!sXN56Sb?={=6iw1J=;0+g11Q z2Umopj6Bq`Px-5Wk25k{V4-p91nfdU#D3?LTqX4e&7;E>Y!EO-x}kX4oA~7tr6)0) z*L-5J`A1Ueu&82$bMT4+qC5*FQuz4Px^wOnB@gNTf;gTq45wh0=@_J5fOSLG`7sZ8 zmvYAa11YBG4gUxlZPfatjT7;xw?sUDx_aZXOlCZKZYjM9zto?jNOvavcs??T^I;VR7vO3e!L3bw8s zN3nBoFVFY9@EJ5VGO8KfdDIFqN?J6CVB?)s82?HQ@2G}^BGI-OTYZ;bAXo6=qpqVQ z(IMi6PGV+VW_#6jpNNJhu5rAH50t*hLx+D_vhxn80h3_vPE41Gv?abCJwfxQ8^d|5 zj4iaib6&;^EWDn23|Pt@1^!OU>FxazfnkbCwB?3frR7*RVLKM^F|S&FIDhHZ*ESUx zB-sxpygPH}qF+z_ZcM=-skt{dpM>w4M9y8>@%6H%jQiBLNoafWh3-{)J|O>76A^D} z!7KHfTycN_Bo%99(FAkt+O6Qs$xDznM!2*krh&Ph((1$$)UG~27yxDUDh@VBw4)LdvUDsf0_*HYwjmblbc-{}ZfoEPQ#9bWokx%7 z@BYfNIHKX}6!T~FjGP3XwzPQt@E6rSvdx@KCX0eaM8v5tb)vsaK0{HPkYZM{O@NJ> zQdr^j3*(?5ew(kb`=xK*Unrho2F7ucAas2w~HH~ke8#Io(=fBCijgd zRuXpooi8r?Es8Q@!dJAuKS$Tj5Uo?MkQe)29ZqsV=^?8)wO)R~w;6 zju2Mg2Flsm^Y*L{yFN7ut=;@v8-UEW`yLD%648!<@|i4AtGK; z9k4y0#-@>&eU>sZkc;S4e< ze9WTv-&89B^3P%ITiLb0hK^mbya#<@|ikfTShNHzWZnc1$GfE5+z z&F6#2=hfAz_SA1!7w*)$OebHucrk+k7N+fnB^#NThzAENkNI@Sh+uQRwArE|eXAdN zoOvs6@?Mwl7=AhouY@(N;GLe34Z6hjGC<*ks)8ujm9QCa z2??_D3cqsq5meU;VW(r_8&TmplAEMhQw1^Pukl%!FG21k9m^i|0|I!Qd)p$+;dR(2 zZRy}Ct#Ce>9}nc6ODw2+_xd3u-a`dQEL4*Ece-AI})lHYzwWhS8vl zzX>-Qkrgwxu*ixke?qQy3r@&)lOa;#jGbkj2yr@assw)TtM=YAt(qj{6hyH6Lv(U7 zcAH=GE5T%QW8&!znDsWoI{u~%9Tji2XmVw@(nLrR3#3n<&Mp=upcAzu%w|fh_6V6t z$)YhCrZLBBqWo-i`XdUQKAm37n`=TCS;Xdl{*DtVEI63>u?p^SCNyypM1rcGs0X*Q zSZMf$jYl)mtu2-hkmOU&Ut4K5%A$Z^{*FrUseKr{)@yq65;9*PJ7Zx}BG^0sa5bJk zL4UWf)NYBNwzavcw_8KnuW+nxrA;-np*#;?T54TP3&cD0QC;vX9Ijmg5Az~ySt!sqm@ViTAW3o59tqX)d z*bb$6l6rh#^6n4aAcw?`#981ux(;1qTPrwGyqU6q*}h3Gt~e~Qw5&Lo8no|_CDs4| zOjm5>uR_QUJkfgwXPW1~d24o-b8&~Tv^7gyk-~;y4vI$L2W0|I`>|zdHM-n)moH z_9(gFoEI;y)S6d*-l=1&=(6wsY`#*KdbjuMVqb3kX_khYV#IW5Ab7Y-H9am4n%;D;VV2o3%QTeuKg1w4cMDoLUINeodz>>6dJv9 z7X;nGbil?6{Wk}dz3)p*6e71yG$+>bpW~7HB?i)th@FW%*_gY)1@95ZM8$}Ri5X5D z-q)7*U0Ht#>ENK!4~9H!)Nd(?XSF!I;ZZYl{Gc9w*=nhCbzOXUx8{W!ty=NlAR#uY zTjnN7p{-K_m{VMV5a%ns$9bWG#Q^2FWxc;xB3w2dQHV<%9P-E3nrwTtlY?W|^H&;X z0x+{JHsV)SJjgSprKNJ=_2L{xQniTj->j{2JJ z#TGwWbG%wBZe9sO5pHZ-P(Re0SV}4NCndzT-?GY1+b|klrf%+UE!azcyR=MHExE=Z zT-&(#=I?y!%0xg=CA$P6ohvg24wBqoRMRo~{F|@jg}T&`OWX#GqWYURJSgg@nZy2f z&12*1@-K!S@Eu#jvc)8AgB1QG9K_v!{)BRd8I7g9mZ=8q_t4?QNfpG>fNW0OY+W*P zydnf*sCjYy>eFEAigF-@bM`cvCP5Odoy6Fjq|q&AY}^G43s5#W_i^KI{BBEje`wN&c(v{??ea60bPvX7#>5_D5hwdmp zF@A*llc?PO!UG|wgXMz^;Gq&elu;E^$XyixXd%_vg(COuB4Wg$ltHM^>cyh`f&w** z%I6)zRFAsH+9rztAlU+ni4@qzPEcg-AfB8uE;nW23X^5-@uJNpvh-ngl!R$S}0YM*XDN%+kR2RPg9R36fNa&nc*5X0!2I12#MP<}Zg%q67hlqNj+&cStVeDJ^Yq zUymQNrfiTmQEUX62M+GaC~D~D2F|}DLT=|TnD0=d&ellidKQP!MH*M&lat5ySEaZS zO~tU0`?4hg#u%%hR5>5-iAONNG>G?X$^sbX4iujqxLWh{_3IEwZ=fwx zU?H1|e&Z?fZnYIH2SA{#(0v=oT5|NTa9l*X)}u0a>dHbjVwx1*Ju?$hQ`Qh6)rDK% z-1N%deDF@$naSJxPg!c~7k?@{U=Z|ku$?4^7FfsBF7t6$yhg4wIbyM|ngQN12ZA~v z6TBrVsu62G+}`PZeD>QnO&QcjlPBI8fH>U@KKH!m-`cUFy8WYe4&*ausQ}>R42tpr`H+ezX=MjA-}Qb9=xm1=6lI`aPInE>={yw zNs)eVBp*M2rg%vMI->{KLzLiQv%_f}8=)>1Dxm}iL{1(O6aNpo$SI}0=8!Ptck@7?ROi8xeuzwfw9d2rf-fqls z`gnr7S6F|2s!2R~ith8SCdK*7baPh#m1re40lA(J;U+0PJZF7LxcMs`Q6UMn&{k8Qf*prhRFYe7)2P;CmRM@vZ11O&PUXoOf9GtDeH!!du%_OOl8&&$ zX`eg%CdMDBat?Yamrrbe>wCf#=Ea7#gznF$qAiyL++8yEgH8w7Sw{#sZO2^K(Z2mV zM_i@G*+{Bz9GZn8&$YuV^K(YC7I@fvmOj|Scqr+sME1P$zM@lM5JSwYlUXZB@vf4^ z2|L;P+FN>P?>oda_CPHH9)~~hRe6i{5~c2~M%eYVRY$jrm)0QO{~6Wd6)ATlG#H4D zn-{RQsxQW=q*~O}KKe-4!ig1Ht%|i7W}7K1BEeAwvI|YCWww|oW5?e1`b^kxrv~xN zNmJdD$Nb`6Q2W2`E=M_Ba<ebH^8IN~+;j(sV|!PD#M zO}*Rigzs)h@eGK3*YFGanmX+n-vBku=`LxgS^9NxaiE!lQCgypP7mriae#T656{v;*oRD+R`Tihl{(R)h{Rt0*?pI?eS@wmMr#OjT z-R{CDf>5*x$=m$!yifS1vG)ga{@WdfIryiC)zTK|OB~Mzj!oDvJk!k-5LWn|p&=d- zCE%(pYPvDi9z+AmO&%uA5??K0sT6KPK&AzL~xULOrQeTu3qcYzm}RH|zJ3ss#{ zYcjujmNmbhybwWly_X%e72ZD1-JNH{Ji2N?XY~trWHxTNZT)ZG1|YHDT7p(sqC9A8p4V_Y1?-j zH0YnbuQ+hZ*+-_o(dqVTLaGZ|F5@QtmOI`1xD`MW`{`y~YF($O_wo!2u*h*o3_&RN zGa6!`605_opo`ABXNsWA{p+OCt?`pTa#w3r(y7q#<6=EJn^4dc-;W$ zDb1S?T+fRSgEPp}^-R;VM6-;yVPr5Bz zI|mm-3!H&3Nq|euC~@_fnu6@Ih#E<#Q2Kz}ca5=WM)`wGtA#xdK!dlow$y0u{?_3; zir*}ALHr>!f!ziDua5!K(ShvDSSso~#e3fWix;!J?`+uXrhr;(43(=WnSukpZ9k$w>QfWEOOh{ zcs})pRAqxuNXyQtK|P*R)Xf&vVM-tSF;zR+2dZgJR~c^W&+F^giaUiuR(N=?0j$MC zem~g>iq6F&5{27J-tNwJ*yPn?d#^&qm5suDqa3H@h0z(WU5`dp;f(;P^op46mXHzv zt02`GOVhW=R2FbFhg0|9bsTE_DSbX&J6?k4d>XWpb4kLm-}cV^7zkA6j?slCA>606 z-e7z3{0X&)&nyci9vbv5X>}&G8y9SV3TgPknv?ZM#-T-D&cQJpzQ(bY}t3q`@ zJiyTPWR*$8^_|me zG6TZ<4eRkU^-W?Zm(E!S*&NHd2s<gRSq>F>yAaV<7hATUdTu195 z&Vz8zm_r&_dv=vfoSb1w*sHQ8F5Xv>XR{WY^|BsxB+BEIXF+u?doX7CRNM!NYzV*j zs?udFRS&=0ZJs2#aNPl<^erI|h_@5T;(YR2UEiCzgFZ8da?iS-er#=FZ9EhzvweQi zcC{gdHbGC8?>I)^5&9brK0NbJV{7p+Mea+~^6l0~8jD3ESkomFF>Vi|zXL3)M_dsG zTa-IKy@ASDPq=%e3Mfm{&s{OHwtijXy^vD;`->dZ(#$M_!HSNKjL)ucy*MCp&00O3 zegL)0v=g8GdgDEi@~bKSO>&|JPTSe>8@TJIq@`U~5XV@q>~W{#fZPrf$re1uQzZn*I$rJD&J2E@xKz|$UoRQaG=f6xx}gD(~H@?oTu~G zNdTZ-zuPWv0p$K8)ouT_ERNT@p@Djhz}U+XS1_dDux>x1Y=3*HCl83|yEo>#MtpV)1H&s8{5{F5@8_k(H?UDZHx_M?nv*RBSRirq5VbD~*gI@m76 z-sIDN_UzTh#)e{rn6R+1hsQ?&VMRql;+SVJ4j}{prhAxi6Mz4ALV8z3!KEXVqVNdO z+C<{Iohe6HCW(%TipnefZZJb-va+tVWNK%Bv&Zj%`+;YMDexrqgT77QXZf1lT!DHP zGij_$8Nzw7Vm5$h3INa!bOrzeIq&+1K)PF7Wr)8ns10QM`GNbs3yMN$r%#{$y|&4c zkEk6KCoHS`aFnSx#g?iP9;?2+XiLh_T? zwmEcsS%&N@YwM;p(JKv%00;nLebUyVHtUs*b(@+uTz@)JvFaJ45pg*!l&?yysYwOE zLI=hC6mpvVfw~@m{q`kRLh|VczGWg}9O3)@?Bc{Rk0og0ER^%M51$_ZD7fJd3ikJd z1i_VKjN;8CRy5k!#2RTaKFq_%mv^{Ne=cURQOg%hvvXh|c18k%C6)0hCvCDUSyHH+a@+oxPd8aieq=aqd|JcJKt7u$e# z5wrjR=M4V&XhZGIp3wBX&7*5orqUb{&!GNkSt^R^vX2x18b}NP4Hgj*862d@LylGo z7@HU+#r&uHOeR-s-(uil#w*DQaIsJcfYSni98wq}kNxr$cG z_V#||!|LdCxC;ZKQL`^+z2JdW&g+hG4W2K}ck5^6M-&pAWiKL`vMbG{r$~(wAUxPN z$vxH7y6sT`E0t&Ye+ocva&=$zjhQTi_yyn3u>D4(2ys28le= zxbD#fY0oFR3@EnZ%oD4cW^k^g@_|ni#QPnlRdQzG>NssoL4(h-p3Om(+enUocCTAAcCF|tG2te znuFf@?KvZ#)j@D@Jzl%g-PMQd^yD-8L6+Nq=bvev?S_&dSKsQ2mn;|v=%yTiagABuUSjm&*cXJ z=+H3~f-K9%7@owV2g)=|F&nQlY`fw%<0T_3U;MS>?v8y&hKNLs)rP$UpjI*E3twwg z3ZP`(ge-nm5812&+O24FVSX|$^H))bb9_S@Py{W8Su8A&`ZYKzvsg;POR;#SDS&uy^m?Ck$MU zSe4pwPx=(5J-cLMVr%<02;rRE`&ZK4yjuR#UJBBE9BF;@FJ&GguKnNWG;JFFea~v0 z9{0XMkV%o0liUF-jV$%a%r04;tqA5mko3`*hksS4PBld0bxcMc*g+_nX&M@9FP~C+KEJBwE)fAxp>#9Y}mHMOj^0^0y4A$mLvan%5g`P z%OY%5LgsGnEoJ?_7~5sf6@F&(O&UveM+py<^6M__VUXG=``@R!1l-E^&t;w#D&+O2 zx7D%artZaMycWw4f65Yj+Q6Uz!nUIw-D+F6dp_5-Y>__nMVuO*zo!&0nUVI1#0~@;O zGTb*yL(Ib7y?vXohI7716c!U3%M`zT+h{D%+tAzF2yv#@Y3jS6mZoEF1n)>~qGgS3 zwW^vL&=rOaz%#35bv@0f2S?q@Kq2-3iof|j8JfM6_kGpBxrf+{y6`H#fbVV}B;?G7 z6mOyY&88ILv5efMWvwSZ13L4!&%n$Xbe{w$+`{Ww1`w{g3cy2sqg_8BcGF7xd3K`y(Acio;I3*Q*S9y!BZbeOVfFRiX0yhvyX~vo+C|cpZN` zM*@vj$yhN$+@+4MvQ3iGQ#T9!R!QlUkwg9Xib6uVgCE9A-fyKZls_nK<5Vm6ifBuIsKqd8oMiou)_e3@HYr(H*CAT#1z`AbEIVStPq zTUn(+kx8l1qNWRt2LkUxLxpeM(nN2Kv$_TDCnz6EL(tOIabJQZ0hyL@Tzfb>_eTzo z0>r-_f9mHz@tX;4L}l}yJYbVzigPBzDPv`NfvAPxru}!_Gv-p{JTI~?w@=d^Z99II+PtGI zs-WsBX=iycUOnt5F=+HK7?6x z2F7|93v?{_EV^m{L%?oy z-5n4;miP6&`d^dZPQ`5fx)Tz2Vpr31*)jUtbp(EFrLM&`>b*eKcK=<~IJ~Jt`SP-w zMcvET@6FB9TXkMz-KZ-Mtbo9)FFP5TJKJGWlZXm;Ejsyc>jMmDYm2Pu4&RsnI8olu zyTUTE%H(4{@z&L=58WCVdDGJ`eCG8d4h|}VZ^_8$Y?37gTq`Fs2>BPIF&J!ilK&I@ zzO)*TtVdMT}Rp)lQ$gQQi6HIoYGw#|*47^L%V6Fmy22%@L^e$&_YMeDS zHwU_IHh40#GIDiB27#^^LaN#W7)S4u%F%#yb;uo6*?7nwD8Qvv_n?1byjwz{ZEVMi zm(i!u*uD9~KO=9om0F(+Rh+4Oz|H#{2bPy?htv$mJ7fO%1+)glb;Uiw2Ix!YwU0Opk|H#Co(sm0zey%hN4!*f!tLvoCSC6n(W z09)$=cLs)TG;Nyg?VX5IbS?rEOB!Z0=3ADpJJC>2{e9z{re~dj(^8CUz?3r9aj>(x z=H;kabW9A4M4WH}Ue)2(fHcI5+)124Dc%6XdasZBBgbmaaNkKu?zC@JZvFE6JPzhF zs%N!$^@gGvI$>um!$GgLti7QjLU}choZ4ltF$^mc0rdNDmpmau4MEA+&|Gki7qBP) zm3T@lg6O_{0+98-7cb8n!Nm0`(~a*SD+?#X6zo&V^$3W&+b?7A zNN?#27;~2ZkB`nE*|;FvjXL2CuGEZ-AA3rpcWuNAFiK(^VXXnJI}2tUyc~RU1*`p) zm`NMrlzLu4gco%IphL9z$3L)@6)#B;e(GkQC|h3qobD^4~{V{ zGrumwXr#iGcvycJV^RKr7$>u|)oIwHjRtDR(P&Ta?V7YSRn~Jt$!oiBP<7)A;g#0L z@v?;i;83q~OKVdK4)J-Dmb3G7FEmUQE?v5GE7kao(&5GpKr)@$&~~(m+SPn0e*9Ay zcD9}=kN5M9-c9DsNF@@*97mHD{&6b&9$u4HtD+?2WcvIIsWr5%)o85y2g}~^w^jRc z+gwvpz2Dzy8v%3nzTMYurg z={48Nu?!9VKuwg=_7`}~UVvaZEce5&5C7IokduQmLs%oJy*F2vHYJq%Le7n?DpUp- zr)@F;O(3`uW`<;)!ibi|N9xjsPENU<_K{4Vy0^&*Xc^?hiFa|drq+PHOrotcx3Q5~ z&Rdg{p8$K+3@q5_M@8sV1DOqtx|$9IgI%$TdOv>(()O~sd>Zh*js}3I005tXB3B;3 zpg6T`nFGH}w6yY)0#^jP6eRnhrjH;0tl3FoE%)h=#W`|e0R@W^FfSOiC<6LP8;2c% z=+5CWU~t`8b{T}|#s2Ra_US4%@>(`>mu)eq&oXt5^&Rr3lm?PD1L zV;qd|3xa1_QJX_TieeCy!v5Q{yzL%?I*iGGnJ>VtEY_bJk4a9pIr-AoC_|t%qR$lK zQK*F)ZrXjrrU4sTOQo%h@JGkRWi4TAjTHl_`o1O=o3Z1KjSmYUW#i^Z>MSu4(XiK2 zTeApjWzm}m-ic&MmeRMZgcHXV>E6$R(c%rZ1tOvm4QV1%-!hv!FopU6In*P#Q*-8X z4C#FWTna8^-tpU3VVn|%*49ZYbxS6SJIi4;GZpv;-S0vdN^bIfZL{tB0iL058TL5! zy%iMz2k$KrNM(W8B>GNRz+!AG(`40eZU+XCDLVss#&1aFu3{m1huY>cUL$1=et>&( zr~wYkP}2_=rh*xU5(Rm^;6E;yo_CU>#H)jx~)f#!j@BdrRn7TOiK;oEY) zx!$}I&ff9&TzdiI%zZxxZy{8kQ!xhMuVx%!j|Xk+kFlQNPGQqP^}X3+W2!X}p!h8G zfoE<;L}IZvzPrQZCI* z?n*qOV3ROoqy|ml*qtyGQCouwD-=>E4Vc(DUTswTUKhs247@P>| zI8(D1lg?wq*uil|fBl-<{z(fEI*G`(^__H^?6b7xuyfHdaYaK_X0csDIt|`$L?Yhq z#Jg2n1MV>gjlKvNMd(Z*8oIa2);*(}D8ESO$D_wqb}fnN8ut(z!>n4`Iv5mc*sg7( zb6B}%%gbfhMYcN1t(vM1@!iX8?`kt%k}b58P3EeNV-$pM6<|DI>Q*+8S!bJ>*E@l8n+{7)cITTxTlCe$6e=j_ICK=1UKO6(xnI5Dxql_gw2mQq%y^%tZU|_Q^8{Qp_ zQK{-W>JAyAzEtq69ou-Rz}y1rTae5#9+C|?J-h770Q~Mh5Z-ML?GQ$`WjxC>RBL)% z9Jie@J4^-qUQ*;-Uds|ZU;OWlNl#x5=RHpa*GL9@qrLkf3IupSJ*w+yaT}3E4eMi= z93NVuwo`naf%_MMuN1PqFdWHq`p*#OZ7aCU-GKuuY@Z?tu;}4Y zS&3V)NT7W*DEg_t{=aGT%Ex8QQ(v8R1nzEU#OJd4^Xtg6Vq=T6BR1Zthk0zW^-ZTN z;pLb*2rlZ%@k-Dn;4k&A5C*wQbS91kDQuoC`n`dMc)o;C#-gQEzYJ%c>}B{M`l_~9 zn16c!@_xxH1nQBmQk}Tu=DZ3|czVSeurTnpq5H8MZ2(P*UalcV`fA zffQx$j|YYMb8=Vi3Fz-VC%v!#M^N_v`~L_4=>U59Ez6#sJA_97%f)#pqPK7LEk-ZR zdIXYE9SU1#wjH~ZlL_QxWdAsXsqS*0v+WO)?VrT@8nk9fm}hYrW-a6n9}?T^b(okMxb88{>w14oH=iDvJ z4@JuXF##+;e=YbphcI3>+$LQIYyI>2_m|?8uI<*D&BfYgd5eW*i_q4YUS;bb!#)3Z zo<{PQxVXlj9Xd6-(*=yKP~aNTR7SuNnU@sHGC7gR8SV07l;CqcqZ16 zaD?yW?oQlYySVA2-^JRva2zL>HVyebeh$WW4xY0#Y{0@ zheb|MHU#Y**wa>1)uA7|7#)9E>LJmWCw+pluOFCq7L4u=S)QirwZu3f~FJZtl z-kUN0HTU5;$hbQj-w=zAM_!J_ot`DLFD8^YT{YXE`bosd+0DJJUe;tVItvoebdn!xY@T_OKUkNC=+?V?c+Y|(%y_k-`XTeB zhreTqpi|+510>_;3)kT~H9zIG_Z(XdycWiM%7GsaYT~vEkg+O<1-Xbi}I;*_*xH-6p17hs?Ms zWZwLSwEYM5oY<{MYVgSp*jY#|Pd&!7JW_2_X&p@ECERxw04vweNruPYX&+kM+$;Cl zJWFXKNr2nCm2%iSh+6227pJ2~v6!cWGwbtseu+Lms6>B5{qU#ou-hPx!D+?C z`UpT05bG0e?7aU90&AL>gxb#~i%3-Jk5t$$PHRj2_PN(>q^Vh)Cz4<8-h^T56n)!X zR8mAW_4zdbGCJ792=#bPh2nzmN*uO*R34cG^r@*fdA>ciU*_2}s7;{0e#%PCAxEM0 zUWfu8YCLHtRkc|)%Im6W1S}M}v&P%5_zg>hB7kKd%O(apk01}cYSa^@RMAlw%an8D zkQ^Up$xED^>191!smY9KtwQT+>*S!V%yunG+$PxpNbmjl%97?192L)vOIgkceeOHw zEER>gYRYM?03HhzSYY@m0c{SM;<0y)O}i72--%2vJ4DQcA5U%rGVyefONII8NiJKq zD1lgk;U^sL%$@OWB3&^u)ALdV6Q=eHD>r6YSo{cqGWme60nx$M!$rY3YmbX9;7?f>AoZT6=7@2~Kvt@)A1ICqw>3gYvhMTgN4I6Z-2ZDzoJ<1lh|^9_4^C30qM6&`1Tpzq`cH-LqV`V>n85So<*W! zKvh=Hx3s)=kufiNGq;?A@s6T*?KbdtDy{tf7G84)Pjj7w1GceP5di@+eDIbyU{dGT zHIhu)QyKsW6Wj8cC)d@|7dF>pf2Hy-Uq&id1{xGuxAI4d3{{X{$M<%QK30D`pJjbY{qYKvbPF_#|!^_ zN$;r>S4g?O`1R?nBNXdh*s3-cp>TR_|ospnbo3^KwT5SGAE7F zGuI2&Vkh;Vm&73Ps$ZX8;PzXYSEt`hyr+ANmD(SF7yw<+CQ6egWKzS#tAp|?uEbg= ze7Wp)yp(n$bIHVQfMm?WDbeN(mxJ zD`_A|ceiwRry`=HbeD8XcMAvzNO$L=yJOFV@4NT6zrFVu-#O=>J;q@$o=4zbcl=_` zYhLr3^M2N7yZRk$VPA>b`b>XM^y1>LJ2|?og#zrZOXpG|zCzm*XYayPxn=Hj5>a_J zr0qZX#YWwQC9d^Z8<#XLw9-+DXr+GoA7<7QRiI!B+pKeyU28M7!&r-7Mr zcs46-MP*SYUrk_vw9s}j6jW%2-0OQ2aH+_8@48o)np94A2$3r1SZcRH_46(EcmkdX z%Bbwk+>b3|(uaePni)I$Xl0l-L}d9ObgT%{RwtI!q^!kz=zM zQB(QeC^t$mrpVBru6pG%`n7B6S-m+fXo0vBMSD%WQ1Ucu^_(b}$97A8wPQGSC)qH# z+RFE%yF0U$T?SpWi)vzVTWjlXqicG{Tj(wx{Ap z-7MuhUc-(3pZ)NSR@&OroyU)dGfj-mgx~3XG3Q#V*=B&9DQl$cvq`(_Pn;VYY9PP` za#)LNR|d%iTKHqbiWLl9c|dD=EF%visaJONKSpxdd;jswhD%7r{UbWl0-AP`p?Y@; zvDM74w3G!+eEWS-hnYT_<>-9Wza)vS9 zeZ7`59~6i1#SROI2k~mszr^h*JI3x{zJfatl^17zNGa9|hf7 zMe@uxCuvvbp6Wo7C6aF_UwcCgCM z;eKEek}2hJS_E}>^Bux_-@%S#3#z5Yb(9y@Rg2woN=G}!CL9q-Np!~czb*yidUkr| zoiA_DNk+vX#u_Cvw|A3kySMG=aF?e~TTVGGe)7TCVN^<(ACD{-)pv^BLBA^#?A8l2 zJ)3xR5cr_NhL6kKamW)L+(i~>w@{;3#a&`5C8FhKg!3@4g*-x-U0i`k-qGWyfxI2| zOgM)_jH#2Va^ahR&<83b#y&ag+@b|XK4DK8dHZl=pVAB)1Y4G>7~4vws&BF(QR@i& znz$YBAax(^E%9TAB$Wuq*-blXliWY~jhQ=hx)V?nPBoy~vjh&xdb!A9F@OW*W|lsy zsU)s(RZvs1W(<`_ZS7TJhd58hLuEWc)#mti`Fg^LuXCnc4jcDCZ|M%Qxv2BGSjFrK z-){65wTUx~)!{OJ)5^Wrt?ir8<|jpr=SVQl^~g7;bZMH>pTI>nG9!~%ai?+LqJnEU zU*FTkb|9|Md6_OGq`%tbiMBY;&}AdVYORpH)%MU%xr&UU#`m&dZdf`ZHTx|&vt>|T z?PQ=nw`TD!%B$h17c|mZzU)aoUhGGYWIMVSAxzm$0BU?LQS`{{Ca+EO2vn==1YorJyf)=~{Yz zF0E`eIJkF|xxTn7Hz5H#LDk`u{wC*^>f|6DL!g0N@Y$i5OCk)Q`EPqX;Xj|gYVO1x z#?i1*sj;azhIN0&lI%)&4=7hK5OR_`4Z|W$`>AnG3VG&5*4+Cg16I48^kL-A2WPG< z4l4@7<UoPqe@v|9^rc8ftV0YXxvtIAY9ndW*rL!3;nlK7NA_QqO2*DKT~ z(t9WY0r4;_S(Yi^yqR%I(EHp_t4MLVXq92W>;?^AA%QDOr=hZ5O;D4Upson0{R^C!NJ?O76Y8-kF#(9!Wy_eHn zNBwJ*vO@WeA zv~nKRfMupI>H^kw*rU%~TAMiKbM~jT=p|I9 zD_PN=^ZM#*V3YJ`&LVSBJn#E=vM6WcuFc@!;1->tUs{aN@=N;R!#X&~M0%|(RV}D< zp^td~>?mm%6*ik4DVHEws`?h#JwAVK)hUSSB~lWVP9?pBwbH%wZpc4^RtKHegJwc0 zu`*)}hM4g!ddpGbeO<;VEe!0?v4x)D$mn6?1f3yaU%6S9Yw}8?E=o&04-`7jXP}YX zfKCAoYmWJ?Q}c+QCMsg-F-M7^2^#IWpH4;`6mAiJu6>L!b1K0=R=V-pHTtA2sk&WX;v?0Y`hRYorE_mOS%ow6by}~JS-If=0}V1^2U!p z863=dAhNW!v_TLVZdWOa&qxVoJN34GNSF_3g&fEQ~+2nsDcP@_ne?a~H|M(Pj z!z8}4(y}xhRC3A5HuhEHdy5wfEZ!GndywNw}f^T zwMH6LA4LS>|I6%Vt&V*NrJ<*nd-du=Mn*<&vJf5xIXM`!BHNOSlk0xLB6WL0L$fn% zm`hDYmRPs<<;(Rkvj$8;ZYMkMgtm%p|||}%gEF?lhvHRd-4Ys5BgDZn5w~D z7m5~>lI0=YxV{f)*A$h*+U5*4s8FY_b+uYVC@UzW8;=wN%GzJcZYFhA?&R8!?%+9h zO8ou(t@m)IBkD*urgxsPmt&%$44q;*?ehZz1IYynblSV;+oK@SlLD!vL}3vTU+#lR zG;J-dG{`r*U&ZYHf6t&z}UEjm+ye z`w`!~aidGjW$TVF3D`sUZ1U;)lkkQ@z@$Wp)b%8< zyQfFHWF#a!Jgv_Cn&H-L3+B;9A#>_`_;+B^dd+!tjAJ*e@ZaT?lB=A#smWiImIZ3R z7~64bft&yQ(_5(D!)!78j)H=MMG?`qu#K#{Mk=kLp^@l-x-liwDjCzN-O%dOy%EY0 zcoGMwmcYGrEB^dsf#+zYpp!5}Kv1xo%%Af+M5AN&3o%gcA<_@}$rLXyud5>@jw=ki zOMOCy137)(^wop2=Gfc^@sg5~J21Njbsy1v_n8D;)o3W>yWDnQ;f zlw2f|IlcYO##gO|{_cd-m;AiEpsbMzoV8-#-E1aZp7JE^Z)cmxDzjWLfZ^jC(rybS zn6f=N*esv%;|LB9f1Gafvv10bIgJB8wm)j=4_7Ad314-7tzpHmk!|cf;FtR9p_{*w-t!eT+fsP(B+dL};W`pyNwUP@|rgm*;RW<+)oi zaoX{?K);8wY|O;@2$|Yse=~sr~!E>oOKXc?dT1*6)Q62-~ zXoU45^`AhiW@6jLATjQ)t+_T|9J$5P4v&Z@4Xtxcc}GL7%~`HZ{Bp60>g z_l-AwNqNQ(Vk09n2$*!O?aro=(n46C-#dRaCx zCnJLFE5rP?`xuYLd%A46}aV=EQ7E5R3iRtSA?8 zdBe3yNWX*JOQw7&BU4&hI*FLWMsKb)r0Lxv$Q*Lu4$|V|UrMh2GEn&<42!1IWv_s8 z*~iZ>RGLGj%x`2>7DS4h&QtXszJ5>X=}kAP&Nd%De3+4zCeF+IDX;x~9ynFj=ku^w zjPL$hM$M7UkoM6=12%=gNQvpd-s;G1-1!NABENrsuIuSCrT=O=Cw)pxPlPG0p z#|mu6W2j${TxDJ=e_Mqbw@F@RJeTEzH`mwxbRs-If2QH!P#PK!G zf4IuAM1qcvPIRooHcYz0Ojc!4<%jx*So?W`)6;cV(?UI2%O%;!oJ>PlQ!NBxP zzL*J;kd>uO?V%QkWHpXV5svuY-Q9h4ij9d$s^)Arm&I|<2y~bF9nmiwV4?b+id5aX z07QOsc2gyyD%aPtIvO7Zc1HYuCCH)K?N^@I7!U>?diy~R_} z8chi2ax4aIsP7N^y&>I_gP|dp)1!2;IPT#J+uUkc>L4e51y^f2Th6IiOX_IUVx(qd zl~%N>-yEX($N3zcz+~H@gljwrk2WjxikvLMY=kxudUtklho(|B++oI`lT| zui78a%+qWp99i<5NS8`oY9cZXCWpv_#2K}q*KC)jt@yrt#%b^jzxpee`oAf>^}L5}M# zE^hL{!2u<|HKdSX7fDM}9Fx#c<^A4@r5OdmzUo>J*4;yT>qXPv-8~Wp56uA zoNOMZK=_k#WN<}Z+_=@PRfcD+clA(r?xyyCDQrZ+n|>4+gWXy(GWIut=_XodP=rzo zLNd9kqML@j@%oSE83`E~+$lWN(m_3$$`X zaoh+FQKR72llu3^3%vH6knn(7tvHHa1J0}xOC}KY84mi=FU72qdp@h6(W6oeS$(lJ+KoE zjrI?n$~T*cCy=WVlwge#$*tV-g5ny9y)oN~J^*JRpE~M^>n+gj)GR&)5VE-4 z$s?z(9SNsdfUjg^EQ;5Q^1la)ma z8?LdbDMKz-m5*n8Yl~22yMJpw%5({~H-}EdLad`GfSc@bR@7+k@gqz=4=fvR=vrz! zajSVR848q@>-t9-78DjrqW~6oNUL_10lnTdi6by0a~5TVuIDabAx9o7;T1R3*H`sX z#{OFi;78=LTwLoHby*(YMHk)yI^BMci8?6 zWq)^Z+{7d%s-3M@iv|cMChQl8?Wg($VLK#Gk822GBszKd% zi9|jD$wd7cuqcr)EK|t!!Bz{3iG`6rRV;jmLb2ftnmel{6M})PCZl>+pb#ntjEq2F zlMjKVr@C@>%6dUn{f4+3#TN77&#PBwxnr-V+l-RG3;LibO;K(*w?RL zGn-Am^d(^8gWERFH;(H}&8)i7}XnXcz&0n=`MGc3D zpBtNPJ4MTs*&?jOK=M<7N_}3qPYPX59ZpwGU3)6+w}S!lZ+CErp`)Y2Tn+3FsO4%j zd`1;D0J!@MkTZE{$pAt^{n=juP-uect6XCMk8M!U%%**~HRrI^LbVHsnRR4BD$ly@ z-i(fbGi=p`vzl{T#bKkb)`kN#H0+9}$NQ!d_Ap`;-gwJd0c6(CsQ5uz%YOXJH@R3+ zVk)q6LCWrVXD;9(E9onfGmmL#x|jMgeb-lC_!gg8i2{BIYDu!}c)<_oTh_*=I9fCn z9DNZyi9k_LTu@LDz+=U#oo*paKb10zWZ4|$^lPL};?&gCzQe$Kp!{0Wu;BxN38!t} zahGG`#NPnQiky%4_?kPS*u;dw=vb;3W@jH$QSrmS`zFrMY_k;#no9j(HGvZT+rYAn zj!p_Hd?F+?*qI98CqX%52{~))B39$!q-!L0FJU79A($8v6qE?NU0YilWW5x8Lx9Z; z0BatNOq}WTDo`;o6-d-1CMM#NlG2xq7)KwEmRb5%A31Ta4(7dqSm$V<=1kkj7V3-W z==$GabCHL&Y4^&3p*Jmf+1_CQUJ%&S+)E{AQ*m?ZZHjLOO^2U_1VApKqMkI<~n&jz;v z3Znk1+YOdo5#!Rq^P3nLN`=4rkm@BPMGm_Lhfdt^EG*ZjZ``;Mm}EZFq`x`c7?=bh z!D3cHM|bE`C31m4lf>A)?a1|w;>YdYofhJTqdUDf&7aiBp%*AB7= zY99;L>potct5nT}X#yEBt5LX4M|3)B|21Iq1h>s~k5@VF_DYE%0W4>3ZEv%v*CNIs ztZ2Hf?+oCGseT={nDvwgo&gy4Be0>f7G=z?XHJ@tHZfg^{D#v%zaAaT_!k)t&?UB$ z`b+a{{=DNm9Q91&qe(e3g>Rt;LSrzM6|YFERC7^N24TpjPglT;IPx7-ZPa71SS^Y> z1B4tdHjc8euqcFhMU%NEeI{yq(j8kcFxF|SrRUzqb{)$g3|BDg#;w1^YtBwXzI}_Y ztmIrBs#4PRy`TOxiVdn?lp7lxK_=$q?>`XVD=kn|a3|l-=OcucG-al0U^bpSc_M`6 z`NnU_03v*vXV1hN_X7d6=%85tRXxB6ye3EY6{vz1CRMp4DwGOyo%KY|s! zG>}yN>(@);3DvB?+szDZ$w@zd=@?cKU8Ar3@#@tpS%~dQWi#&p2Qh);ru5*^qwjUF zw8kk{hgbI~8}@tCrF?P90VIQHQyly(lz@mE8D-&+H2G$pk}gCr>9$Upp=btsd;8&X z>r4qbxF7GMKp-f39S`Timb-=ML&(9l;b)2rl!2i_F@t8$gCio+!3!q5a)f{sLiu2F zFkEaE7CT_}d^*p!dCtk847j&f8Z51Vhlj^-skvsNrps=oS_|M67&Cv)tuN&1Sy@?c z7xW5-2#tvtwZ5#CEyVJTxVyXW{=6fG-)XF?rS&clU}pk&UV#i}n{pG1RhV(s>$N=G zXY!)9*KNv_higpL+>Ir=y1aaRK+y5UMn{K+on5iQW=&dH*oR@YIwJ#mc|u#&x$f#J z$3B*auNW8@pmNRobwhn{e{LMs{On`PW-OSdHl$hF;-81`uS{SJh6{B4_g2QUd+Xeb z!05@y$z|&1sh+&#DA|(E}0ll z@$q?WU&XzPypyhW@<`y40MUFL_Rp2-vbzsXd82XXX(Z znTGtEPwxd$imoJ-mJXlY#g#D}uY3yVoL8qnfQ+AVaoA7_7hexxO_8drbAin&4REng zX!zr!yYbQKdh=q<`B-+~ZBG#D&v#Bd1cQp~3Bn~DKCrzDp7bd{g4++~WX$#av}yk+ z_mu&L_0)(?0W~+bDhg38b|w0rf(8;5#O7Sk{wq76<8=3HLV<#9t)ppsGI?2*R$qvP|50HZ{g$#`!xLXJKAciy zxNW^wHfFuuUWCyCNK|ZlVg1=sdkghIELXCZAC}~+x~_2qHLvyq`zqc`U2 zx{8?%gI}mC7I7Kv=}|KeU9a>0Q(3bgG6lL~dLi3aV8dK0m3k*25CA2+ZF7M=$Y3jG zL|8}&!AOcoR0_3JiXM<;(55?iIK9fc`f#2Ic!zX|YQTRPikkq$Yg!;ODSg$_(&Df` zW*e2gFMql?kQ)c3h~Uf$wOVeAL_e3PuwCy5zK3uZ$=k<8b*jnbxW_rA4tj0W`kb4c z)q{E@lr1{iK_&t|=*LGlMH)1<+fRR`+5r~Wp#Ia1RAYuLFtxpDAbf+}3#1Oz5{H>P zFVT<7sH&m@pRFwmI8~b5`uNgNLF$T41>=&4jOkJlpLJphpr59Nl$4hsht^&jOaMka z8H*$fkjB#&TTaL6W@QGhd=DS;pTGDAGy8O9^FZ1bdW@#*;VOU)a-E--yS&o1JT8-;vHmSTKfiupy$dxOuC9)hh(V+v7c{pdM&L3RA_o>o z=ZY*+PcK6$#2!B2u$bVv189IP!w`lE8Z!j|@Bl(R)pp!I^_A;#Y!MfMaWLg6=ibAO?$y8d_XNzRn=s$quC%E`s0OL zb`zsO|JS$YPnE+d1df(6t8QL@wp_6e@7?L(Dmi9YULE6*WQ|gwpa9q9`RhG{{#d!w z>ZrXuHWxD={6316xclUg<1R6A67CbM*44eG&F0P!a&&ZskSL`DY@ShlA4}W~MKIdE^Fb84*s6%-XBWgU9{}ymQTkM!} ziAhYQs;T#pV~+?M!TLhBWgR*m^J6>$f^^`?1T&mX>^ft)A{n*4By<|RaGT7n7b4=~ zCT6XMe*AcbqNAIRU6!x4q9}f}Ygk5qYEq7zDvhb6QqnEb)6>i6LX~_h)0PdTrGtUR z&*RJ0Fwo~PX4qP`C=1Rr*K|JzOA-IZ!-M9@lODI=yO4#>(Cv(c@_4p;AGYl{6^pIX zS+%tulaup02L|C1;ibmMKS247wop1qTcT>GK9l9nALW%Ve~XUJYHbzFekV2nCM!z$ z+wb>zkHH^0+N}3?QwX7gr}+5ztGR`!G&b_*+1k7As(ruiAzdoHq5S*6yqjR+-^v~_ zB}F+~3L%3yf2^DNOFZX8=}QJBI=>fFO~wdwqE%%2HgqJ_Zm{kb@1Te6&8 zQcO*isvJbM&%6g9Kvy^>C(TU1$tRHsJw;?0njV~NgG{zc-u+rL_2Vz7A_+4Z;p%=T z4IPZ6f2C6lVxXovTTyN7BUcQlLY-%3W}=+t+P^-gqeE>f2XJs&;sFMDpTUoE>kyQT zJgpd`gCy>!QOzO+P_U+@J%$vS)!=@wLzOC=3ILg~N`(zetRa^|TNwQSqzHymdSaE{ zBLgXx25M@cz#qh-P}*YAjC*Id-AA*OV4&hDX)TjPjf=!l z18EcNUp{K;uA4WexKJ!PF~KGL+8f841(RpAFAfKL_QC7^F~8;ZL3GVZ3=LIw&~f+5 zB;~D(_aDY@Bg2J|7dgT|t=DVekN>aom#Mcupc`?qi3L@nk1rX??fVTatD0&VEtnqcN4^Vcp|xzC@MR$a7=Ml8ky z7kHr+K)_gCR80IAs%8FmATY9KFEPmda)!bc$JhM(*?V=tcj?xoU{l$8H8dQ4jvB}J)Xe+Ltli$R!i{<|dT zzkY}Rt}3b<9w%P>azUa_6&A?Tu8v*s#(Gjd|G5Mu{PNf*;8XrGhTe4L?;!bF1ZFBE z0#!~6*b6v~kpgej4Y}RnMVNf-Trk{u0l64dvX~r|B!O(MURZU}Jy*MqL*5Nx6rcX* zkO7^r9d;O;D5zmdZ#@U~`C4ktE2ZctZo;4Y=-0v7(Q+;-4@<~llLh3`ZoiT#HKbr5 z<^u$RN+Je_hEfU)=V^L!pKQDV-P}b63zEE6leL$Uladw}c+ShNgzi67p!&oBIRZyhU6heVj2-b0jq`_Lh$?VccG~qTB|v4<>8O zsLTVSVCQhb5%dIjEn4imHY#+v#isQAlXd3#@`?$sQI8Y!2vJg-BoK6$gd}G`)lnqS z3KDJ^kg!6j4RBm?Yt9^iK0re5FcmdvK=c~IQ(-P4$0|xFMWfSTYTp584S*ch#UIFl zC81;7`(;vM2;&3bnUN*P2dsRu+Q~GY!};m{E)dkHyeBFRYSls!R@hp0@9tfc6bQvv zfbSKMgnZ`J)MWjM@hVtQP}MdZ9FPDr2nzzZsdUpCm-c?76?+k6V?#z(p>u=aJ7H;{ zi6Q7OJo6-lnuS!r_X3g@6V-x(f`R0#gVib^EGL||0{gKCK4^+w> zbPJLtN#rPgi6=`b)qJLzO|J(Ks;z8jIRynZB_$sR6B9IL5yd3pJ_*k4Dz`p7nsgT? z=3Wt(4;PV2+37FTZ&?CpI9BeVf9_H-|63t@dfEV!p!;os4yH5!5ZCi#?BTM4pJ}>% z8Opu{Jt81zZ~$fvD_bE5MMD5VI%d^#OEYrk``hE4Mm$Gpi7828;cu;Nh9DXs1M;D3 ze}eQIx$|zHs`03N+9kB_Ebn;-q`1XUtG(bMBJLw-SY|r$RP7SF&VWt5IYlU;e0_AIU+#Cq>w{f&v0Brnb{MWu(Xo$_|UVl^>rO5x2Isc8|IW>$JuBID_AxqzTjG zsHa^FW{JW9nd}Si#$-QUxnevbn*@lNI{n>8=lYD&M1Y)6Rgo_m1pDUL)sIUL?k2Da`fWNF8apj<( z1END9o??pkpl%ek8X-TTVm}uG$&PjE0fO6vG-9tlM2qUW>o>yV0hpEj9T2b)9-b&= zjG|$P=|m`vM}NG699@eUF$sx@6V~ySrONg4u)L5w2TY| zNJJVZTqokOQhSCTAe6FYLqb9gI@iWfHYln+dn+SxXU9D-Daw>2!?HsFL_8rR4tnXK zPurl#o16S_vj0|Omy`kNuaW3VVCW>^&eY2{QExs|!&LKk1 z=WD^8I4EP0b-k7DMZPhDytl%iaAs4ki1E#@R*1CH?&sp{dRp zyE#>TklcA9BQAY+s9yE8{Ow|La;=FHs6B4^&FSjn^GWzY-Hp26`=<_bZ|8r%SSarh zm~6Cl8L%eyZ*E9%zxLJ7Pp5mf<RhB@&ZhD4 zP^U{1WW(x!zE1P)ikP22d21FdE5__NNv8RIYTxIX z6_yTG2=3f?LQl%&aM!>2O$(JPB{{jcgsSNH+8DxzgbUKtAKO-Scwb*08yjP0Wqtn) z|1qb)weipjQ&|&73DtpamBr^_IJd%PP@F){8eM= zU>}J@MgzS8u;qQpNP13=4y0^OCa>|R59Mpal2BAqx)jcCO~Z54<$u-c>`d1AQh7y% zJzx(zWO7(3fJ3z6%RA;hDPp=}sw99VwvD}gy|=S>phc_zG_+M>b@bficwqO-uKlJ zdv?4tBIvbcfxGpxU!K$9rAK5>m0j$wP8>8nFE-BnsbhJYKwo2k&a}w>qb?v}lMyFUE6Id3j2YOV5qjH$bm<{7`&GoQ^7!DDLkveSO+y;K}1hL*OuqS`+< zOg&&^>}E3>n6r>jP!NE{24qFGNA^`IQBf?Q{bnGuXI&eI<`ms9Rclgmhk#(n(5|R$ z?t6B&FRalT{|8&PbpFjVnO?RwHq$m0LwU{|L)!~8R_r%0F;^MH;Jg|IL)UNIKo-&1 z=;~6%#KiEveH&w8VydJ>1o>@zU%vA4@@EmkF8e$|hjqrrD!gwG)he?pM!HT01ploC z5YbKb{`Jn=RLL2&Y-^YL8l6ry8P>`TZF1w6Y#j9rmmg6!opTxMo8KZf-aWpa?1x45 z@FC^IA3eAPPQXic^VQgw_&!E<>=_7baV;&aTsK3;2z=*yr=bE3kbM1yq|wVve(c~r zgH@){NMTCwO4qD%?f?tZ-PLu;?#Yj4xnJC6zSZ;hKxejR_~oz#!w6kcZ3?f}i1jwX zq5duFGR~8u0V4B?syMdfRQ}`aZbIMB+zs?*t^4&2Po1l&P>cQ1&DuC6XD+IP?Vs=S zfTp?stuLa}nlk9a@p@-Ud3nt5-}2KloklLDfX=>riGG2uPJprnH||hjL2++nVd3NM z?#moT7Zb~SBo>4Y+6MR{e++ww|Jgq+xTvSaxxt!&@V+?1J8^Nuy^G%k#K$9OFK*!x zYz6thX8_RqRuS}#6(SFT&6u*lL7nt7r?7i=t zobV@3*X}m?dZSH_*?NO9e19Jc7)yrU{^B4Q8_q=MvYFuln|~u&+y0ynoCCj z8ULTb-rr5p#9F>0%~Olh$OYBiD%Y&6j}p`ZCnx78ZWy|qv+(M(grXwf*`xqzY1tkf zLn>~%&{YmwCdYne*7=qAjPlU^0VDN8!zT((n@%Q2^8?VPo2TY@ogeDZ?CR_F=pQ43 zZn&*c2rW7tAusKYOqrocOa&-j{(*2>BD%(IAp3Jae*6h=hf|1dV*es;Pm92@;oM1*6# zW*u`_Mut^3>-j&mSqcJo@z^vAUI++!;V=6CYq9%W{z00ZoqdUCp^*B{7k_UGXDb@p z^J&&lW&0bun7+&`B?z;rXpDEnAwQ1|S;b`~&|hjuP+L|%BX)a2UlXptlzNNkPWw|f z7c{qwCHByo;y_4Fu(Pi)Gqd85;DVLt`W~wyv(G>$XTa9(_|xzy~UB zmzSq35&xVVG&3FS*JKXW)cB2#5?WXq+ASu$C8zwXxuK&HEovLL@I&6mhlH3V-sTcG zCd3!7n+at@Qyh3N<-#yFWYhjymZLYYG9Nv<%oAOlRq54~qC-Ptn3j{1I9ZE>*uuc- z8A8^YtZPXNKGN5xE-W5K462!Z`Tl1eeJLhUGMh$wA25;CVAtR^SDCXVhOpJV~~4mZGDS-e@OdhP5?}nBpB}lpwUVjbW|6GtVo@Ki(Vh zFdAKS=HaQi;5`EBr zadFWt&Qfkob!AVKW~I+)q%6vssO0iSS9!Z~;l}Igd@Y9cEY&u8*Hiu!u_#`7`NyW& zitar_m@hj*W0Y->m*I0;7?qalZ1YA7HKYd=iIRcxn|sIA1{>OH%3t~j!$Y#TNY>m=1W0`VnJyyTn_Ee_Y4+Y zZxb2t)sOdR#vOA92Rd3qJU)3uC=}{36S3O4g9J^)XhL<4qq!qSM%i)I&Sg6a1BDwi zGKLA5C?mVOYq1sZ{u-U;$rrI^9f9piwv4XhD{ip`+1XFy7Yt2IC|Oxq;}=%2E5?*$ z;7y&x8+j%rL{Zr>i;EwyS-4|TQbfUV!fyZKkKJgr#$^_t+2+wU_mI|TgGVZFs9eu@ zwH|4;U5{}X99FV9s2Qfgh?!OX^kVIw!iyURvl#G)HmsyC?KPN`U<)9)gC-rLyY%h{ zZ(!WQTUdo$w_V)vr%&NmlZ{aTUWEc_pxGU?Z^U;n3L|Me-9Z`Q-1z4$3$ ziof#`w@~4a{xZ-){o7s7(u$)GVxvF$_aT=Cv7dgVxEK`1lgEhTuA!k9y(+i<{u$A8 zU!4cEACM3xSTgyga64y|$s?X&Zx-u%xXk^nf&j``>?Z1qTf350y<)kcJ+wtNq>%uHJPDf*ZUtjH}-w|*A zkmZUHu`wDSSxrw*9~HT(7(WFHL)mJx(P%8+17h0_QZ|!sjs*BcMa1OfpEQ^WI|Lo+ z!aU_vU%Yd0U}j+GFX&D|O-?j148+f-Cak5yIJ+fnEE2kUEoO`LTo?AFhafTyB|V!Z zIWwD}4}YO)QRDw4H?2vJ`56sG%lffD&+ctp+`f}Jv6>swa;L2=EgDdKl%-f?@Mjo5 z;9D((W{yU{hP(HVt8YZl@4mFMtw_%?p?dl>L+!Yv@OfIgzV2x0!KD%z1^t&tBCbXJ;8IKSqmFBmZbY03{#*K}OKoAfd z{H0)A7v>r;!S1_7Z&DH1DeXZO4e zz!omC2uu(BIy@X7x{Q3NQ;#nzi$Ft1x3aapLrMyWpQj!+u%zAWb(;#}%sxRKS=pCz zEbEJATb?{d+D$&Z)rajjPT6%}0Q$2znxw>3KGZ$?L1Utq76CB#_U+H>X+FKZ@32UW z;;YB~8oDgGkG|k&{A~7=kRRl=wCrp=EH76cwN=9cRiiXrrCIOLNSAb|G}i8e2-tK)o#9pM@nA4euBjDo*RdY z!xQ)@VX`*v=viV^+0J*PvzQ8hSMGxQVQq~8-xGaAx9LubIOyY=;~c*3bS0)`!p@Ew3F_YAyq7a`vO{B$h$S6YG z9|{|EZ*9oE@x6vH-&O5qzulpMlhfm`UwpJ$;Sv(69YE!v5xSAO*x`wY#Gu^5L~&D- zXso>ssfUM1sWOQ$CE9=rTWq6u^ABf7+{43NMCDfND<3|zp`moZ2yX$`igA}+b0a;~ zWAEgN6VueBVjF$-0d>5kE(?8ixPRN+)UN=_?w%@FDsQjI!{Z6d8<;G22n|v)TAN18 z5`hGucC-Dp6C}2lP*@m}mUgSYp}nxk+I+;ADf~IZ25D<_2G7%{SZ5oa+0SF>T+WZt zv*gV`sZ?YrYWr=D|$JBnckBGhd;t^A^w`X_m8s`)+W`F3kU7q{H z?Ckzo(H0uKLRthNTfO~onaz0Sc;b|j=V-hHc3$)97Tw3f`9zV*&D=h6KjFy?3bk21 z0fP3Y*@LSwy!`w)cZlD<)n>7sIKFk`#wPD4PYpxEYw8fJ%yf_nS&I+@2&%6B+1%Vc zK3>-b8#^a>&tVN>w|1^fpx|_wsUwiOoArx*CiT zkEx$7oBL)?s5J+5(q2>Fq}ZnBcJNV~*mr#)E8FtxlO17HbT7I`q!+WYAF8&BS0732cL^2~Zk8sx8FGMnZs(2YWtGcs(vyrUFKpJ4_edj!`2qghP8L>o}!`LLWr z{7Ky5vVA3D)(H7Rb*#>s%8y^Zn7#j=DDNb|ihj+1!<)n97X@DX za#v~|LE_<5_QdYQ9TZ*bt^YfV9-pdt6J6S8ZWq zou|F6Gf{?y9L$qNFfuvH5=u!`H8h0L^VBYONoeV&9(|rY+bh|&+Z#HaoekdZbXD!r ze3%I|%DtzA?L?;cr&FRR&5_ASu8yb(f;McIXTEXgPAdMZU%yTXhd=vB%#m?0N3ScT zI^IO)zw*7bGy*Kj-fE_1Z`!-HO3QmdR*l*(G;3)$1_pLJ;yXS7>jI|icNCi!+XUx7 zwcp<+LjJ=2k|75pESKy$>1DDT+EnuF-6FIzBKFz47T70 zHC5T3U)dJuw2OJhz09QM&O-hZFT;nAOjLK@&Cm9ErA)4PX31^5vzBkjoE$MZ1yMm^ z!~>evW2Qy!=D4nrKY!eS-cx@jZa4eRKO`YWl&W7W2P%ElZ`?@8$PYX^asYiGpRyAt z_=;-#dbf!e`2b&lv*skhzUuzL&kw7{S>Mnwv9dCnfq(!CU3-RyTVpFL-Bb)U6N%jx z7r&8=EOdw@BsbPU%pM$CEU7pw=v);8=xLs6V0Nq%X{A|oPmfNf@Gv5s}&N5R>yTY9d9goMER zcx>yUZT!w3uv>TEtvnuYM$D2vf87+${9f}r_*)IF`sxgZAYp zIcbAGy7QyLw3F35-NQ|>_2hz{SN3mlGi6lK^gsPSa&arn@yV4tgXkL?NEi%skDAX$GFUmU0P5O z1QHSwHP$H1k`a+tF5F!V3_fwsKFrVSEEyO&HxvKIoWY;*alaO=N33*Mo(-?8t#_#v z_Xs1x7cmAQZ*Uh6_i!wCIS3m+Fes>M6%P+>r%b*7r7z)JwqD$c(^ycXbamy*l*N@$8u`%PKbL7o!a2AYrCABTg>(!7)9v)!63g|fsDpM>R`l6nu{r6} zOTT_?xGaLSz=L!9H#g!YMwHoeWoA~Jd;=LA$Nm0GKXgQH81@H4hr@hae4DX*<7x#TfIV|sm^Xwv6piB!PH@OqCPN0Q63kkYHhn~e5&(jppDuV0u8y~M zZMIrK9g+7vJG@vZXKCyoubZk*q>bi@%B*qlSa--#%nyfm#G{t>7vHb*-#skz6yFS1 zTZ;LYRfusHM8lQfU{9i)ikq1%pHS?l{W4vOXhdyE&N+<~rSHtDE%#58^`v^$b};%` z6NQ)?pLb?Xk!|Xq)oSq^#6Zs>DlL5%Ty9Gcm1dD5HT{#B$vXGnm6Mkdijh%6KU}zA zuY+(N$niYIY>?;v(4XN$K;^Bzo?bjibvyTb`TkpTXC6;wyYBHNq@vnXWOy|YZ}O_l zWay2kOwAN!NRe1%E@P=w)XGp1QW2F*FE0tp6f24q%FLo=DAOXt!V2fNvfF!q&e?yQ zy+7xi&*{JP^epSSpZmVA>vw&B*DbL*K@YX+-*@lk77QtOe(H_#6OaiGTfBeLGc)(S(2YooM2pbSwFeJwJeHMor7XCR=~1?r;XAtdkiZ`7)?F^6Ra>zmk}^ z#KEBjZ@PN-><6i>>Gy!$ljmoj8%F(w+FQNGFjn<)L4k>OX*jH?URf| zm-?zRrV7Spm>TSQLztD_2-gdZk0vp>!?tq;%^aF`=H{(my+i`xe-sZ9<}Mw*dfh@! z1y#Mbd*;`O1}E^Md}se9nRgPg9tt9ZadDj`j94?wTpu5v0|(;$9-hj5SI)UoYuCA$ zTk~`6C;TQq4SCkr)-wN$y;NqoLdCck zV!zL5#wxWqA~D}-xfe|{coY>4`y6d-mSpa%MLkng`uuE>!Nui9Y=LNLcKxij`=iAY zq7QG&6#Gj`O7gYj8A;JM2gQGCVQFU~w(%o-LAT-CGsW#a@>svQPi}?LH1ZB;N0ZCJ%M|?I0m3-*){T3ngwx5I)n6}F-+0`ayc4-6W z`Jq4Q&4u~*?rsTr)wP)M#F7%^VmanR+F{O-`lPhNkJ&SI5`|*&_|x}Ub(7Dz)W7HC zcxL+h3DZ~|hp$?)2iX50VY197lg~rw+D9hYP1AC&&W0c>s33f*?%FGTKl2PL4qido zwf)3#94NR4g*5vS4O6pJDREyHjx}p?>KPik2MEAxs%^>j%3 znsFgWl!~USuiDza;qx$M%Q0Fiid-$E60t?Uxu&hX&2fVLv&B@GwTn`ZJX(-YC4aSF zlFg-gWY>?sUJgQ%d`WzcZ`rYhYKo4L&fhNl$12XhQ5{;ip}^{YUKaY7Z&r zChxfX{(B|aMHw~^^RPp=ojj5G*|BBd<1=$iOyGzyo zlrLxYuK8Q}5Cv9_;Id1tLlw62?E2l8ArCJv3T0pBSB1Q+m=f7sVP@t-IJZvp-fCH*M*)5{1T64lQ&yezTF z9D%=NazKMKEGFh1iYW83uJM56;?&%FxeA;XUaC3F?NcBx$%I(ISrUZ4o}P&&=k*}M zg@*<_^I3itn9nc`${kI)i;hUXJ7;$sn$1hQWWnm&n^7aw*v1z2_@_14x9R`*9LqV< zG&rVxr{7sl7UD=)A_0+<@OGOw!g2HW%!#P5O@xxxJ=+~37#1CUqugecMW)b8thR9_ zrj~~YMIf~}=W`U|TFtt*iEXM$#&K0>`_y9h7D6Wv%sqzD@>k)cUKt3&jolgG z_Afj1V0I&Y@QZC7>V@z949*@y!XAO_eQK1R2d}cQlEdm0)ATcd0|LDsj-pplsZyhb z&Vd8`qAEm5r1QLTuZq3Ma5esMrdkA0OQxA@Vp5VT{gw**Y-rB?78dW(qle=aEFjZx zrmDJjFM;oi{v<@s28d$ej4HaTRFKxu`U?Hv(*||XTUT&U8n`!q#$Mgu4;yTKnv`^{ zI!0wIj^P^&UKfC`-qE9ipzR9ag*AMjcmp1#OPDaQ852a5tD2e`q_ao>R1 zw+q@WE#J3f@l@$xb72m=c+2;h2UU($nyxRLXy6CEV%1fuNS^sLHq*u!%H=&)_&O^2 z;p_07tJBPni=k4gK(zR7ryb2+seIFZB`~c)v5~Dmz*u$$b|!Kc74;E>3L|qY25Yhi z@2{|$t0WxoPw^em=!YpBXflbW88hT~1-linfp(*-)tfU}(>eL=#2jLK|3E8R2AJU0 za3)VnLF0xy^cz}DMXlL#6wM_T%L?+Mt=4*cCD=m7?bCB|8ie45U6ltO9ieXLEtQVq zukPR8D^N$?N|44?rGN-I2e4XkWK{@W`$ZkoAEbFY(JA3+;{+hDQ6MybQj`(RSy+fg zNEvNZQ_G`xhLo3rI*C?x5{XfE`gWCewmu21k4!VLKxoZ;k%%>x2DC1d+wN%&ZMjO5 z*~VF1_tb#rH!giWy~&nd*Ssc>Hux0{qg46x+l`0QPS~D4U0YYT%gajz+FMPHFy@FJSIQH0eiUQS$aCfUQyoqv#x-E05q4?-F@{< zP1lVx1uOs&f&5_snKTa9tRX zeNg%ch)QRP1K_U+p`t3cu`K@*h%P8-pA4g%5HeABPfu6)IMLmq$0t1@A?V8&d&^FF zky}8xW}Fyr_Dy<`$9|DAdcfr!GztLntdkSgi6qK)l@4zSyaTrI*S|E+U4daRFfb@e zqte>w5FXi`xTcreGHC%t&Rv4 zwzihsv?(k+eAnK+OOflGpNfbNIOr-5$6R)H_MHd!^sqbxul(h+{rT*JHpoQhl>+uoj?n@ji17lzIWIYms%{W_R!_QLDur&+mqvv(WuMM}!-(MK^c zG0#&|Hw_ew0iWu^jn?$^B;FFAjZUKtP5yY|jqA$JxXHWPs;jRJj-8C^7*qi*gatW)tEG%M>#q4Wtuw_vC@Jd7p24tbdoaEi#j*qC+wso=z0eZF;J9JxS1sQrdFkM83mRE6wx# z{A_b#vOedBk01A1Sp2GNE|gyAc_%x2kCchA)u0*UJ29pj$H*$Ark)^=X^p-Suc|uE zu0p(4-(j9}xYIRnx|WnQR>Gr?Q&^?9Z;!pPNIqh$))H_=#BmF;&L^uH7TF^ zS>&{|8m1oxhBON#-Oq22fx#*C{?Ntp@Ak5&T=7DffI^u<4gSFNI(kMI_h$lrnV zK1~7tvteiukPN-t_2rCP& zq`?zic3H(qhNp9m)wfFY+-VRmC%resrI8`e@J~kHN3U$ji5hX6RP$U_}rTmFc0eJ~xChn1=pV^O>0K%TT;K;{w zX?fSsg}`!Z$oX!AqcW@1gk1OP~7v zh%Vl*mGO4Sd?Hz?-k}?*?o+8{@TK5aRVbJ(Yc!!xM$%kt-C6VZ2rx zd@JXtMy%Nhz-=+L&py;1*IG+UR!gHdx~90OihUpUDjLhDj$U|8Fwq$0LZzGhmn9u{ zBRObv4+PoT^V8JnuOCHkpV@m|HtI;`8}M8wK?Bp#vvxw-fs=AIoYgat0@)H!!NV-nBND#`)t5Ktj z3Kw9w42Q_6PXvnq??b5yyb?)I9t0MP_DM{u?X6Ie>a~|I&2HX&aA7c0BgxokJv6UE zpMfc~0Vs1&;uq|lwPRcr`i27BV7vJ{r`&3*&u_BEEQsuMMHpOcJX%^Q_|l}Mq~y`S zls2#>y&xR^6T;+hd&nn;9$w3-MV%)OKPxCGpyb^){c0>uz6dv#3mU30n{vEIKZ~cI zva#`HVaG)Gj`yeUpXl|OpBfA3dml|t`Bg>$Rkvn1ccCeBaJ3Mh745G#@1?iJ*J;1i^e$=lodLVc#OB)d+PikM~{vF_)~wE<*1=P+I{6 zUQ$NpN{sWvH{ed2GfG%Y38{*ze1@PKG;X1jsyC;{d}_LKTJwDha*i9dc{GXv&a|8U z##u0B!_m{@WZ}A3oxsMr!JJJp(&@ms)m#&AY)M-?kg|&!AAj?cgUvw0K2YJ3+qYki zjC4EqrGOm=^Q{Q#o3bs*vK?!PdmrD(YJL{K+j0ZLaCzcI-j2MiGg*1mBllS;g@ti9 zZ!QDa;YVGf6q|mWMr0QW(q|Ifxa>GDJJO zWZKQ)8+hJMPEJU(CZ>0AcF=tC+lOQH+hJR?vr>*W@$~V2+(B;zQ>EnB(eHDl!M`h{S+PPLor=g89RZsLc+`v;9 zKXmx8mC%Y`*d#X)AU;Jx2v^l8L1RLZx=q}{P9Ts6#a@?Ir*kg(h4UKVu-&i=2em9f zLoF^#iXU*wx~{Tq-Tt0-B)|j@u5dP8L}BdEX+)NdS3%%1Kh&fwcd?wH6TUjjp#v z1b<34Vf6?89Z3A=ulYYD1OEMc|NVxs69gRecs|d&NmEwn>hniz(MV2K=bKtj% z3cW+-jV?Jc3mRFNo37Id&dkhOyTbM?@j(6LTTc?RLtpeCKXQ3tj4oftDhy~jyiQ&( z`Ih>?kSLt~eU2&)=bV#Y7KEemM;npZOgzcX;*rM(*4j%dD?g|`n{Yk!y6V6X7{Z0o z List[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial001_py310.py b/docs_src/separate_openapi_schemas/tutorial001_py310.py new file mode 100644 index 000000000..289cb54ed --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial001_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: str | None = None + + +app = FastAPI() + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> list[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial001_py39.py b/docs_src/separate_openapi_schemas/tutorial001_py39.py new file mode 100644 index 000000000..63cffd1e3 --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial001_py39.py @@ -0,0 +1,28 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: Optional[str] = None + + +app = FastAPI() + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> list[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial002.py b/docs_src/separate_openapi_schemas/tutorial002.py new file mode 100644 index 000000000..7df93783b --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial002.py @@ -0,0 +1,28 @@ +from typing import List, Union + +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: Union[str, None] = None + + +app = FastAPI(separate_input_output_schemas=False) + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> List[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial002_py310.py b/docs_src/separate_openapi_schemas/tutorial002_py310.py new file mode 100644 index 000000000..5db210872 --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial002_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: str | None = None + + +app = FastAPI(separate_input_output_schemas=False) + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> list[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial002_py39.py b/docs_src/separate_openapi_schemas/tutorial002_py39.py new file mode 100644 index 000000000..50d997d92 --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial002_py39.py @@ -0,0 +1,28 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: Optional[str] = None + + +app = FastAPI(separate_input_output_schemas=False) + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> list[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/fastapi/_compat.py b/fastapi/_compat.py index 9ffcaf409..eb55b08f2 100644 --- a/fastapi/_compat.py +++ b/fastapi/_compat.py @@ -181,9 +181,13 @@ if PYDANTIC_V2: field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> Dict[str, Any]: + override_mode: Union[Literal["validation"], None] = ( + None if separate_input_output_schemas else "validation" + ) # This expects that GenerateJsonSchema was already used to generate the definitions - json_schema = field_mapping[(field, field.mode)] + json_schema = field_mapping[(field, override_mode or field.mode)] if "$ref" not in json_schema: # TODO remove when deprecating Pydantic v1 # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207 @@ -200,14 +204,19 @@ if PYDANTIC_V2: fields: List[ModelField], schema_generator: GenerateJsonSchema, model_name_map: ModelNameMap, + separate_input_output_schemas: bool = True, ) -> Tuple[ Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], Dict[str, Dict[str, Any]], ]: + override_mode: Union[Literal["validation"], None] = ( + None if separate_input_output_schemas else "validation" + ) inputs = [ - (field, field.mode, field._type_adapter.core_schema) for field in fields + (field, override_mode or field.mode, field._type_adapter.core_schema) + for field in fields ] field_mapping, definitions = schema_generator.generate_definitions( inputs=inputs @@ -429,6 +438,7 @@ else: field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> Dict[str, Any]: # This expects that GenerateJsonSchema was already used to generate the definitions return field_schema( # type: ignore[no-any-return] @@ -444,6 +454,7 @@ else: fields: List[ModelField], schema_generator: GenerateJsonSchema, model_name_map: ModelNameMap, + separate_input_output_schemas: bool = True, ) -> Tuple[ Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue diff --git a/fastapi/applications.py b/fastapi/applications.py index e32cfa03d..b681e50b3 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -92,6 +92,7 @@ class FastAPI(Starlette): generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( generate_unique_id ), + separate_input_output_schemas: bool = True, **extra: Any, ) -> None: self.debug = debug @@ -111,6 +112,7 @@ class FastAPI(Starlette): self.swagger_ui_init_oauth = swagger_ui_init_oauth self.swagger_ui_parameters = swagger_ui_parameters self.servers = servers or [] + self.separate_input_output_schemas = separate_input_output_schemas self.extra = extra self.openapi_version = "3.1.0" self.openapi_schema: Optional[Dict[str, Any]] = None @@ -227,6 +229,7 @@ class FastAPI(Starlette): webhooks=self.webhooks.routes, tags=self.openapi_tags, servers=self.servers, + separate_input_output_schemas=self.separate_input_output_schemas, ) return self.openapi_schema diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index e295361e6..9498375fe 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -95,6 +95,7 @@ def get_openapi_operation_parameters( field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> List[Dict[str, Any]]: parameters = [] for param in all_route_params: @@ -107,6 +108,7 @@ def get_openapi_operation_parameters( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) parameter = { "name": param.alias, @@ -132,6 +134,7 @@ def get_openapi_operation_request_body( field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> Optional[Dict[str, Any]]: if not body_field: return None @@ -141,6 +144,7 @@ def get_openapi_operation_request_body( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) field_info = cast(Body, body_field.field_info) request_media_type = field_info.media_type @@ -211,6 +215,7 @@ def get_openapi_path( field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]: path = {} security_schemes: Dict[str, Any] = {} @@ -242,6 +247,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) parameters.extend(operation_parameters) if parameters: @@ -263,6 +269,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) if request_body_oai: operation["requestBody"] = request_body_oai @@ -280,6 +287,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) callbacks[callback.name] = {callback.path: cb_path} operation["callbacks"] = callbacks @@ -310,6 +318,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) else: response_schema = {} @@ -343,6 +352,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) media_type = route_response_media_type or "application/json" additional_schema = ( @@ -433,6 +443,7 @@ def get_openapi( terms_of_service: Optional[str] = None, contact: Optional[Dict[str, Union[str, Any]]] = None, license_info: Optional[Dict[str, Union[str, Any]]] = None, + separate_input_output_schemas: bool = True, ) -> Dict[str, Any]: info: Dict[str, Any] = {"title": title, "version": version} if summary: @@ -459,6 +470,7 @@ def get_openapi( fields=all_fields, schema_generator=schema_generator, model_name_map=model_name_map, + separate_input_output_schemas=separate_input_output_schemas, ) for route in routes or []: if isinstance(route, routing.APIRoute): @@ -468,6 +480,7 @@ def get_openapi( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) if result: path, security_schemes, path_definitions = result @@ -487,6 +500,7 @@ def get_openapi( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) if result: path, security_schemes, path_definitions = result diff --git a/requirements.txt b/requirements.txt index 7e746016a..ef25ec483 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,5 @@ -r requirements-docs.txt uvicorn[standard] >=0.12.0,<0.23.0 pre-commit >=2.17.0,<4.0.0 +# For generating screenshots +playwright diff --git a/scripts/playwright/separate_openapi_schemas/image01.py b/scripts/playwright/separate_openapi_schemas/image01.py new file mode 100644 index 000000000..0b40f3bbc --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image01.py @@ -0,0 +1,29 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_text("POST/items/Create Item").click() + page.get_by_role("tab", name="Schema").first.click() + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image01.png" + ) + + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial001:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/scripts/playwright/separate_openapi_schemas/image02.py b/scripts/playwright/separate_openapi_schemas/image02.py new file mode 100644 index 000000000..f76af7ee2 --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image02.py @@ -0,0 +1,30 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_text("GET/items/Read Items").click() + page.get_by_role("button", name="Try it out").click() + page.get_by_role("button", name="Execute").click() + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image02.png" + ) + + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial001:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/scripts/playwright/separate_openapi_schemas/image03.py b/scripts/playwright/separate_openapi_schemas/image03.py new file mode 100644 index 000000000..127f5c428 --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image03.py @@ -0,0 +1,30 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_text("GET/items/Read Items").click() + page.get_by_role("tab", name="Schema").click() + page.get_by_label("Schema").get_by_role("button", name="Expand all").click() + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image03.png" + ) + + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial001:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/scripts/playwright/separate_openapi_schemas/image04.py b/scripts/playwright/separate_openapi_schemas/image04.py new file mode 100644 index 000000000..208eaf8a0 --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image04.py @@ -0,0 +1,29 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_role("button", name="Item-Input").click() + page.get_by_role("button", name="Item-Output").click() + page.set_viewport_size({"width": 960, "height": 820}) + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image04.png" + ) + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial001:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/scripts/playwright/separate_openapi_schemas/image05.py b/scripts/playwright/separate_openapi_schemas/image05.py new file mode 100644 index 000000000..83966b449 --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image05.py @@ -0,0 +1,29 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_role("button", name="Item", exact=True).click() + page.set_viewport_size({"width": 960, "height": 700}) + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image05.png" + ) + + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial002:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/tests/test_openapi_separate_input_output_schemas.py b/tests/test_openapi_separate_input_output_schemas.py new file mode 100644 index 000000000..70f4b90d7 --- /dev/null +++ b/tests/test_openapi_separate_input_output_schemas.py @@ -0,0 +1,490 @@ +from typing import List, Optional + +from fastapi import FastAPI +from fastapi.testclient import TestClient +from pydantic import BaseModel + +from .utils import needs_pydanticv2 + + +class SubItem(BaseModel): + subname: str + sub_description: Optional[str] = None + tags: List[str] = [] + + +class Item(BaseModel): + name: str + description: Optional[str] = None + sub: Optional[SubItem] = None + + +def get_app_client(separate_input_output_schemas: bool = True) -> TestClient: + app = FastAPI(separate_input_output_schemas=separate_input_output_schemas) + + @app.post("/items/") + def create_item(item: Item): + return item + + @app.post("/items-list/") + def create_item_list(item: List[Item]): + return item + + @app.get("/items/") + def read_items() -> List[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + sub=SubItem(subname="subname"), + ), + Item(name="Plumbus"), + ] + + client = TestClient(app) + return client + + +def test_create_item(): + client = get_app_client() + client_no = get_app_client(separate_input_output_schemas=False) + response = client.post("/items/", json={"name": "Plumbus"}) + response2 = client_no.post("/items/", json={"name": "Plumbus"}) + assert response.status_code == response2.status_code == 200, response.text + assert ( + response.json() + == response2.json() + == {"name": "Plumbus", "description": None, "sub": None} + ) + + +def test_create_item_with_sub(): + client = get_app_client() + client_no = get_app_client(separate_input_output_schemas=False) + data = { + "name": "Plumbus", + "sub": {"subname": "SubPlumbus", "sub_description": "Sub WTF"}, + } + response = client.post("/items/", json=data) + response2 = client_no.post("/items/", json=data) + assert response.status_code == response2.status_code == 200, response.text + assert ( + response.json() + == response2.json() + == { + "name": "Plumbus", + "description": None, + "sub": {"subname": "SubPlumbus", "sub_description": "Sub WTF", "tags": []}, + } + ) + + +def test_create_item_list(): + client = get_app_client() + client_no = get_app_client(separate_input_output_schemas=False) + data = [ + {"name": "Plumbus"}, + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + ] + response = client.post("/items-list/", json=data) + response2 = client_no.post("/items-list/", json=data) + assert response.status_code == response2.status_code == 200, response.text + assert ( + response.json() + == response2.json() + == [ + {"name": "Plumbus", "description": None, "sub": None}, + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + "sub": None, + }, + ] + ) + + +def test_read_items(): + client = get_app_client() + client_no = get_app_client(separate_input_output_schemas=False) + response = client.get("/items/") + response2 = client_no.get("/items/") + assert response.status_code == response2.status_code == 200, response.text + assert ( + response.json() + == response2.json() + == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + "sub": {"subname": "subname", "sub_description": None, "tags": []}, + }, + {"name": "Plumbus", "description": None, "sub": None}, + ] + ) + + +@needs_pydanticv2 +def test_openapi_schema(): + client = get_app_client() + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Item-Output" + }, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item-Input"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/items-list/": { + "post": { + "summary": "Create Item List", + "operationId": "create_item_list_items_list__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Item-Input" + }, + "type": "array", + "title": "Item", + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item-Input": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + "sub": { + "anyOf": [ + {"$ref": "#/components/schemas/SubItem-Input"}, + {"type": "null"}, + ] + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "Item-Output": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + "sub": { + "anyOf": [ + {"$ref": "#/components/schemas/SubItem-Output"}, + {"type": "null"}, + ] + }, + }, + "type": "object", + "required": ["name", "description", "sub"], + "title": "Item", + }, + "SubItem-Input": { + "properties": { + "subname": {"type": "string", "title": "Subname"}, + "sub_description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Sub Description", + }, + "tags": { + "items": {"type": "string"}, + "type": "array", + "title": "Tags", + "default": [], + }, + }, + "type": "object", + "required": ["subname"], + "title": "SubItem", + }, + "SubItem-Output": { + "properties": { + "subname": {"type": "string", "title": "Subname"}, + "sub_description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Sub Description", + }, + "tags": { + "items": {"type": "string"}, + "type": "array", + "title": "Tags", + "default": [], + }, + }, + "type": "object", + "required": ["subname", "sub_description", "tags"], + "title": "SubItem", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } + + +@needs_pydanticv2 +def test_openapi_schema_no_separate(): + client = get_app_client(separate_input_output_schemas=False) + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/items-list/": { + "post": { + "summary": "Create Item List", + "operationId": "create_item_list_items_list__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Item", + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + "sub": { + "anyOf": [ + {"$ref": "#/components/schemas/SubItem"}, + {"type": "null"}, + ] + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "SubItem": { + "properties": { + "subname": {"type": "string", "title": "Subname"}, + "sub_description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Sub Description", + }, + "tags": { + "items": {"type": "string"}, + "type": "array", + "title": "Tags", + "default": [], + }, + }, + "type": "object", + "required": ["subname"], + "title": "SubItem", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/__init__.py b/tests/test_tutorial/test_separate_openapi_schemas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py new file mode 100644 index 000000000..8079c1134 --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py @@ -0,0 +1,147 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial001 import app + + client = TestClient(app) + return client + + +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Item-Output" + }, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item-Input"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item-Input": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "Item-Output": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name", "description"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py310.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py310.py new file mode 100644 index 000000000..4fa98ccbe --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py310.py @@ -0,0 +1,150 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310, needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +@needs_py310 +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_py310 +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Item-Output" + }, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item-Input"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item-Input": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "Item-Output": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name", "description"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py39.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py39.py new file mode 100644 index 000000000..ad36582ed --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py39.py @@ -0,0 +1,150 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39, needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial001_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +@needs_py39 +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_py39 +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Item-Output" + }, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item-Input"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item-Input": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "Item-Output": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name", "description"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py new file mode 100644 index 000000000..d2cf7945b --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py @@ -0,0 +1,133 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial002 import app + + client = TestClient(app) + return client + + +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py310.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py310.py new file mode 100644 index 000000000..89c9ce977 --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py310.py @@ -0,0 +1,136 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310, needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial002_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +@needs_py310 +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_py310 +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py39.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py39.py new file mode 100644 index 000000000..6ac3d8f79 --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py39.py @@ -0,0 +1,136 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39, needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial002_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +@needs_py39 +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_py39 +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } From 098778e07f8d04d3fbf3a21f812ca97ab7daa46e Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 25 Aug 2023 19:11:02 +0000 Subject: [PATCH 02/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 61ec91b4a..3858f47da 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for disabling the separation of input and output JSON Schemas in OpenAPI with Pydantic v2. PR [#10145](https://github.com/tiangolo/fastapi/pull/10145) by [@tiangolo](https://github.com/tiangolo). * 📝 Add new docs section, How To - Recipes, move docs that don't have to be read by everyone to How To. PR [#10114](https://github.com/tiangolo/fastapi/pull/10114) by [@tiangolo](https://github.com/tiangolo). * ♻️ Refactor tests for new Pydantic 2.2.1. PR [#10115](https://github.com/tiangolo/fastapi/pull/10115) by [@tiangolo](https://github.com/tiangolo). * 📝 Update Advanced docs, add links to sponsor courses. PR [#10113](https://github.com/tiangolo/fastapi/pull/10113) by [@tiangolo](https://github.com/tiangolo). From 859d40407caa3850862526ee689e2d22177cf19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Aug 2023 21:18:09 +0200 Subject: [PATCH 03/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3858f47da..517553c9a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,14 +2,28 @@ ## Latest Changes -* ✨ Add support for disabling the separation of input and output JSON Schemas in OpenAPI with Pydantic v2. PR [#10145](https://github.com/tiangolo/fastapi/pull/10145) by [@tiangolo](https://github.com/tiangolo). -* 📝 Add new docs section, How To - Recipes, move docs that don't have to be read by everyone to How To. PR [#10114](https://github.com/tiangolo/fastapi/pull/10114) by [@tiangolo](https://github.com/tiangolo). + +### Features + +* ✨ Add support for disabling the separation of input and output JSON Schemas in OpenAPI with Pydantic v2 with `separate_input_output_schemas=False`. PR [#10145](https://github.com/tiangolo/fastapi/pull/10145) by [@tiangolo](https://github.com/tiangolo). + * New docs [Separate OpenAPI Schemas for Input and Output or Not](https://fastapi.tiangolo.com/how-to/separate-openapi-schemas/). + +### Refactors + * ♻️ Refactor tests for new Pydantic 2.2.1. PR [#10115](https://github.com/tiangolo/fastapi/pull/10115) by [@tiangolo](https://github.com/tiangolo). + +### Docs + +* 📝 Add new docs section, How To - Recipes, move docs that don't have to be read by everyone to How To. PR [#10114](https://github.com/tiangolo/fastapi/pull/10114) by [@tiangolo](https://github.com/tiangolo). * 📝 Update Advanced docs, add links to sponsor courses. PR [#10113](https://github.com/tiangolo/fastapi/pull/10113) by [@tiangolo](https://github.com/tiangolo). * 📝 Update docs for generating clients. PR [#10112](https://github.com/tiangolo/fastapi/pull/10112) by [@tiangolo](https://github.com/tiangolo). * 📝 Tweak MkDocs and add redirects. PR [#10111](https://github.com/tiangolo/fastapi/pull/10111) by [@tiangolo](https://github.com/tiangolo). * 📝 Restructure docs for cloud providers, include links to sponsors. PR [#10110](https://github.com/tiangolo/fastapi/pull/10110) by [@tiangolo](https://github.com/tiangolo). + +### Internal + * 🔧 Update sponsors, add Speakeasy. PR [#10098](https://github.com/tiangolo/fastapi/pull/10098) by [@tiangolo](https://github.com/tiangolo). + ## 0.101.1 ### Fixes From 9cf9e1084dceb45e50946e4130801012ac0c0c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Aug 2023 21:18:38 +0200 Subject: [PATCH 04/54] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.102.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + fastapi/__init__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 517553c9a..2375bfee5 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +## 0.102.0 ### Features diff --git a/fastapi/__init__.py b/fastapi/__init__.py index d8abf2103..6979ec5fb 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.101.1" +__version__ = "0.102.0" from starlette import status as status From f3ab547c0c6e5b42b81e3669aaea753f742b742c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Aug 2023 21:23:44 +0200 Subject: [PATCH 05/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2375bfee5..1a9721e2c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -8,6 +8,7 @@ * ✨ Add support for disabling the separation of input and output JSON Schemas in OpenAPI with Pydantic v2 with `separate_input_output_schemas=False`. PR [#10145](https://github.com/tiangolo/fastapi/pull/10145) by [@tiangolo](https://github.com/tiangolo). * New docs [Separate OpenAPI Schemas for Input and Output or Not](https://fastapi.tiangolo.com/how-to/separate-openapi-schemas/). + * This PR also includes a new setup (internal tools) for generating screenshots for the docs. ### Refactors From 594b1ae0c38550ddfdedab314276c1a659ce4719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Aug 2023 15:20:04 +0200 Subject: [PATCH 06/54] =?UTF-8?q?=F0=9F=93=9D=20Add=20note=20to=20docs=20a?= =?UTF-8?q?bout=20Separate=20Input=20and=20Output=20Schemas=20with=20FastA?= =?UTF-8?q?PI=20version=20(#10150)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/how-to/separate-openapi-schemas.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/en/docs/how-to/separate-openapi-schemas.md b/docs/en/docs/how-to/separate-openapi-schemas.md index 39d96ea39..d289391ca 100644 --- a/docs/en/docs/how-to/separate-openapi-schemas.md +++ b/docs/en/docs/how-to/separate-openapi-schemas.md @@ -199,6 +199,9 @@ Probably the main use case for this is if you already have some autogenerated cl In that case, you can disable this feature in **FastAPI**, with the parameter `separate_input_output_schemas=False`. +!!! info + Support for `separate_input_output_schemas` was added in FastAPI `0.102.0`. 🤓 + === "Python 3.10+" ```Python hl_lines="10" From 5f855b1179d06c8b82f479013e5888c48e68c716 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 26 Aug 2023 13:20:54 +0000 Subject: [PATCH 07/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1a9721e2c..5d15e1c25 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Add note to docs about Separate Input and Output Schemas with FastAPI version. PR [#10150](https://github.com/tiangolo/fastapi/pull/10150) by [@tiangolo](https://github.com/tiangolo). ## 0.102.0 ### Features From 1b714b317732df1e08983e4a8ffe2e4e02c995e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Aug 2023 20:03:13 +0200 Subject: [PATCH 08/54] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20`openap?= =?UTF-8?q?i=5Fexamples`=20in=20all=20FastAPI=20parameters=20(#10152)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ♻️ Refactor model for OpenAPI Examples to use a reusable TypedDict * ✨ Add support for openapi_examples in parameters * 📝 Add new docs examples for new parameter openapi_examples * 📝 Update docs for Schema Extra to include OpenAPI examples * ✅ Add tests for new source examples, for openapi_examples * ✅ Add tests for openapi_examples corner cases and all parameters * 💡 Tweak and ignore type annotation checks for custom TypedDict --- docs/en/docs/tutorial/schema-extra-example.md | 105 +++- docs_src/schema_extra_example/tutorial005.py | 51 ++ .../schema_extra_example/tutorial005_an.py | 55 +++ .../tutorial005_an_py310.py | 54 +++ .../tutorial005_an_py39.py | 54 +++ .../schema_extra_example/tutorial005_py310.py | 49 ++ fastapi/openapi/models.py | 16 +- fastapi/openapi/utils.py | 10 +- fastapi/param_functions.py | 15 + fastapi/params.py | 17 + tests/test_openapi_examples.py | 455 ++++++++++++++++++ .../test_tutorial005.py | 166 +++++++ .../test_tutorial005_an.py | 166 +++++++ .../test_tutorial005_an_py310.py | 170 +++++++ .../test_tutorial005_an_py39.py | 170 +++++++ .../test_tutorial005_py310.py | 170 +++++++ 16 files changed, 1695 insertions(+), 28 deletions(-) create mode 100644 docs_src/schema_extra_example/tutorial005.py create mode 100644 docs_src/schema_extra_example/tutorial005_an.py create mode 100644 docs_src/schema_extra_example/tutorial005_an_py310.py create mode 100644 docs_src/schema_extra_example/tutorial005_an_py39.py create mode 100644 docs_src/schema_extra_example/tutorial005_py310.py create mode 100644 tests/test_openapi_examples.py create mode 100644 tests/test_tutorial/test_schema_extra_example/test_tutorial005.py create mode 100644 tests/test_tutorial/test_schema_extra_example/test_tutorial005_an.py create mode 100644 tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py310.py create mode 100644 tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py39.py create mode 100644 tests/test_tutorial/test_schema_extra_example/test_tutorial005_py310.py diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md index 39d184763..8cf1b9c09 100644 --- a/docs/en/docs/tutorial/schema-extra-example.md +++ b/docs/en/docs/tutorial/schema-extra-example.md @@ -74,7 +74,7 @@ When using `Field()` with Pydantic models, you can also declare additional `exam {!> ../../../docs_src/schema_extra_example/tutorial002.py!} ``` -## `examples` in OpenAPI +## `examples` in JSON Schema - OpenAPI When using any of: @@ -86,7 +86,7 @@ When using any of: * `Form()` * `File()` -you can also declare a group of `examples` with additional information that will be added to **OpenAPI**. +you can also declare a group of `examples` with additional information that will be added to their **JSON Schemas** inside of **OpenAPI**. ### `Body` with `examples` @@ -174,9 +174,84 @@ You can of course also pass multiple `examples`: {!> ../../../docs_src/schema_extra_example/tutorial004.py!} ``` -### Examples in the docs UI +When you do this, the examples will be part of the internal **JSON Schema** for that body data. -With `examples` added to `Body()` the `/docs` would look like: +Nevertheless, at the time of writing this, Swagger UI, the tool in charge of showing the docs UI, doesn't support showing multiple examples for the data in **JSON Schema**. But read below for a workaround. + +### OpenAPI-specific `examples` + +Since before **JSON Schema** supported `examples` OpenAPI had support for a different field also called `examples`. + +This **OpenAPI-specific** `examples` goes in another section in the OpenAPI specification. It goes in the **details for each *path operation***, not inside each JSON Schema. + +And Swagger UI has supported this particular `examples` field for a while. So, you can use it to **show** different **examples in the docs UI**. + +The shape of this OpenAPI-specific field `examples` is a `dict` with **multiple examples** (instead of a `list`), each with extra information that will be added to **OpenAPI** too. + +This doesn't go inside of each JSON Schema contained in OpenAPI, this goes outside, in the *path operation* directly. + +### Using the `openapi_examples` Parameter + +You can declare the OpenAPI-specific `examples` in FastAPI with the parameter `openapi_examples` for: + +* `Path()` +* `Query()` +* `Header()` +* `Cookie()` +* `Body()` +* `Form()` +* `File()` + +The keys of the `dict` identify each example, and each value is another `dict`. + +Each specific example `dict` in the `examples` can contain: + +* `summary`: Short description for the example. +* `description`: A long description that can contain Markdown text. +* `value`: This is the actual example shown, e.g. a `dict`. +* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`. + +You can use it like this: + +=== "Python 3.10+" + + ```Python hl_lines="23-49" + {!> ../../../docs_src/schema_extra_example/tutorial005_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="23-49" + {!> ../../../docs_src/schema_extra_example/tutorial005_an_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="24-50" + {!> ../../../docs_src/schema_extra_example/tutorial005_an.py!} + ``` + +=== "Python 3.10+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="19-45" + {!> ../../../docs_src/schema_extra_example/tutorial005_py310.py!} + ``` + +=== "Python 3.6+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="21-47" + {!> ../../../docs_src/schema_extra_example/tutorial005.py!} + ``` + +### OpenAPI Examples in the Docs UI + +With `openapi_examples` added to `Body()` the `/docs` would look like: @@ -210,20 +285,8 @@ OpenAPI also added `example` and `examples` fields to other parts of the specifi * `File()` * `Form()` -### OpenAPI's `examples` field - -The shape of this field `examples` from OpenAPI is a `dict` with **multiple examples**, each with extra information that will be added to **OpenAPI** too. - -The keys of the `dict` identify each example, and each value is another `dict`. - -Each specific example `dict` in the `examples` can contain: - -* `summary`: Short description for the example. -* `description`: A long description that can contain Markdown text. -* `value`: This is the actual example shown, e.g. a `dict`. -* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`. - -This applies to those other parts of the OpenAPI specification apart from JSON Schema. +!!! info + This old OpenAPI-specific `examples` parameter is now `openapi_examples` since FastAPI `0.103.0`. ### JSON Schema's `examples` field @@ -250,6 +313,12 @@ In versions of FastAPI before 0.99.0 (0.99.0 and above use the newer OpenAPI 3.1 But now that FastAPI 0.99.0 and above uses OpenAPI 3.1.0, that uses JSON Schema 2020-12, and Swagger UI 5.0.0 and above, everything is more consistent and the examples are included in JSON Schema. +### Swagger UI and OpenAPI-specific `examples` + +Now, as Swagger UI didn't support multiple JSON Schema examples (as of 2023-08-26), users didn't have a way to show multiple examples in the docs. + +To solve that, FastAPI `0.103.0` **added support** for declaring the same old **OpenAPI-specific** `examples` field with the new parameter `openapi_examples`. 🤓 + ### Summary I used to say I didn't like history that much... and look at me now giving "tech history" lessons. 😅 diff --git a/docs_src/schema_extra_example/tutorial005.py b/docs_src/schema_extra_example/tutorial005.py new file mode 100644 index 000000000..b8217c27e --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005.py @@ -0,0 +1,51 @@ +from typing import Union + +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Union[str, None] = None + price: float + tax: Union[float, None] = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Item = Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial005_an.py b/docs_src/schema_extra_example/tutorial005_an.py new file mode 100644 index 000000000..4b2d9c662 --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005_an.py @@ -0,0 +1,55 @@ +from typing import Union + +from fastapi import Body, FastAPI +from pydantic import BaseModel +from typing_extensions import Annotated + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Union[str, None] = None + price: float + tax: Union[float, None] = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Annotated[ + Item, + Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), + ], +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial005_an_py310.py b/docs_src/schema_extra_example/tutorial005_an_py310.py new file mode 100644 index 000000000..64dc2cf90 --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005_an_py310.py @@ -0,0 +1,54 @@ +from typing import Annotated + +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Annotated[ + Item, + Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), + ], +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial005_an_py39.py b/docs_src/schema_extra_example/tutorial005_an_py39.py new file mode 100644 index 000000000..edeb1affc --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005_an_py39.py @@ -0,0 +1,54 @@ +from typing import Annotated, Union + +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Union[str, None] = None + price: float + tax: Union[float, None] = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Annotated[ + Item, + Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), + ], +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial005_py310.py b/docs_src/schema_extra_example/tutorial005_py310.py new file mode 100644 index 000000000..eef973343 --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005_py310.py @@ -0,0 +1,49 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Item = Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), +): + results = {"item_id": item_id, "item": item} + return results diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 2268dd229..3d982eb9a 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -11,7 +11,7 @@ from fastapi._compat import ( ) from fastapi.logger import logger from pydantic import AnyUrl, BaseModel, Field -from typing_extensions import Annotated, Literal +from typing_extensions import Annotated, Literal, TypedDict from typing_extensions import deprecated as typing_deprecated try: @@ -267,14 +267,14 @@ class Schema(BaseModel): SchemaOrBool = Union[Schema, bool] -class Example(BaseModel): - summary: Optional[str] = None - description: Optional[str] = None - value: Optional[Any] = None - externalValue: Optional[AnyUrl] = None +class Example(TypedDict, total=False): + summary: Optional[str] + description: Optional[str] + value: Optional[Any] + externalValue: Optional[AnyUrl] - if PYDANTIC_V2: - model_config = {"extra": "allow"} + if PYDANTIC_V2: # type: ignore [misc] + __pydantic_config__ = {"extra": "allow"} else: diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 9498375fe..5bfb5acef 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -118,7 +118,9 @@ def get_openapi_operation_parameters( } if field_info.description: parameter["description"] = field_info.description - if field_info.example != Undefined: + if field_info.openapi_examples: + parameter["examples"] = jsonable_encoder(field_info.openapi_examples) + elif field_info.example != Undefined: parameter["example"] = jsonable_encoder(field_info.example) if field_info.deprecated: parameter["deprecated"] = field_info.deprecated @@ -153,7 +155,11 @@ def get_openapi_operation_request_body( if required: request_body_oai["required"] = required request_media_content: Dict[str, Any] = {"schema": body_schema} - if field_info.example != Undefined: + if field_info.openapi_examples: + request_media_content["examples"] = jsonable_encoder( + field_info.openapi_examples + ) + elif field_info.example != Undefined: request_media_content["example"] = jsonable_encoder(field_info.example) request_body_oai["content"] = {request_media_type: request_media_content} return request_body_oai diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py index a43afaf31..63914d1d6 100644 --- a/fastapi/param_functions.py +++ b/fastapi/param_functions.py @@ -2,6 +2,7 @@ from typing import Any, Callable, Dict, List, Optional, Sequence, Union from fastapi import params from fastapi._compat import Undefined +from fastapi.openapi.models import Example from typing_extensions import Annotated, deprecated _Unset: Any = Undefined @@ -46,6 +47,7 @@ def Path( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -76,6 +78,7 @@ def Path( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -122,6 +125,7 @@ def Query( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -152,6 +156,7 @@ def Query( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -199,6 +204,7 @@ def Header( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -230,6 +236,7 @@ def Header( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -276,6 +283,7 @@ def Cookie( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -306,6 +314,7 @@ def Cookie( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -354,6 +363,7 @@ def Body( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -386,6 +396,7 @@ def Body( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -433,6 +444,7 @@ def Form( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -464,6 +476,7 @@ def Form( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -511,6 +524,7 @@ def File( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -542,6 +556,7 @@ def File( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, diff --git a/fastapi/params.py b/fastapi/params.py index 2d8100650..b40944dba 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -2,6 +2,7 @@ import warnings from enum import Enum from typing import Any, Callable, Dict, List, Optional, Sequence, Union +from fastapi.openapi.models import Example from pydantic.fields import FieldInfo from typing_extensions import Annotated, deprecated @@ -61,6 +62,7 @@ class Param(FieldInfo): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -75,6 +77,7 @@ class Param(FieldInfo): ) self.example = example self.include_in_schema = include_in_schema + self.openapi_examples = openapi_examples kwargs = dict( default=default, default_factory=default_factory, @@ -170,6 +173,7 @@ class Path(Param): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -204,6 +208,7 @@ class Path(Param): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -254,6 +259,7 @@ class Query(Param): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -286,6 +292,7 @@ class Query(Param): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -337,6 +344,7 @@ class Header(Param): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -370,6 +378,7 @@ class Header(Param): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -420,6 +429,7 @@ class Cookie(Param): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -452,6 +462,7 @@ class Cookie(Param): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -502,6 +513,7 @@ class Body(FieldInfo): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -518,6 +530,7 @@ class Body(FieldInfo): ) self.example = example self.include_in_schema = include_in_schema + self.openapi_examples = openapi_examples kwargs = dict( default=default, default_factory=default_factory, @@ -613,6 +626,7 @@ class Form(Body): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -647,6 +661,7 @@ class Form(Body): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -696,6 +711,7 @@ class File(Form): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -729,6 +745,7 @@ class File(Form): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, diff --git a/tests/test_openapi_examples.py b/tests/test_openapi_examples.py new file mode 100644 index 000000000..d0e35953e --- /dev/null +++ b/tests/test_openapi_examples.py @@ -0,0 +1,455 @@ +from typing import Union + +from dirty_equals import IsDict +from fastapi import Body, Cookie, FastAPI, Header, Path, Query +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + data: str + + +@app.post("/examples/") +def examples( + item: Item = Body( + examples=[ + {"data": "Data in Body examples, example1"}, + ], + openapi_examples={ + "Example One": { + "summary": "Example One Summary", + "description": "Example One Description", + "value": {"data": "Data in Body examples, example1"}, + }, + "Example Two": { + "value": {"data": "Data in Body examples, example2"}, + }, + }, + ) +): + return item + + +@app.get("/path_examples/{item_id}") +def path_examples( + item_id: str = Path( + examples=[ + "json_schema_item_1", + "json_schema_item_2", + ], + openapi_examples={ + "Path One": { + "summary": "Path One Summary", + "description": "Path One Description", + "value": "item_1", + }, + "Path Two": { + "value": "item_2", + }, + }, + ), +): + return item_id + + +@app.get("/query_examples/") +def query_examples( + data: Union[str, None] = Query( + default=None, + examples=[ + "json_schema_query1", + "json_schema_query2", + ], + openapi_examples={ + "Query One": { + "summary": "Query One Summary", + "description": "Query One Description", + "value": "query1", + }, + "Query Two": { + "value": "query2", + }, + }, + ), +): + return data + + +@app.get("/header_examples/") +def header_examples( + data: Union[str, None] = Header( + default=None, + examples=[ + "json_schema_header1", + "json_schema_header2", + ], + openapi_examples={ + "Header One": { + "summary": "Header One Summary", + "description": "Header One Description", + "value": "header1", + }, + "Header Two": { + "value": "header2", + }, + }, + ), +): + return data + + +@app.get("/cookie_examples/") +def cookie_examples( + data: Union[str, None] = Cookie( + default=None, + examples=["json_schema_cookie1", "json_schema_cookie2"], + openapi_examples={ + "Cookie One": { + "summary": "Cookie One Summary", + "description": "Cookie One Description", + "value": "cookie1", + }, + "Cookie Two": { + "value": "cookie2", + }, + }, + ), +): + return data + + +client = TestClient(app) + + +def test_call_api(): + response = client.get("/path_examples/foo") + assert response.status_code == 200, response.text + + response = client.get("/query_examples/") + assert response.status_code == 200, response.text + + response = client.get("/header_examples/") + assert response.status_code == 200, response.text + + response = client.get("/cookie_examples/") + assert response.status_code == 200, response.text + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/examples/": { + "post": { + "summary": "Examples", + "operationId": "examples_examples__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "allOf": [{"$ref": "#/components/schemas/Item"}], + "title": "Item", + "examples": [ + {"data": "Data in Body examples, example1"} + ], + }, + "examples": { + "Example One": { + "summary": "Example One Summary", + "description": "Example One Description", + "value": { + "data": "Data in Body examples, example1" + }, + }, + "Example Two": { + "value": { + "data": "Data in Body examples, example2" + } + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/path_examples/{item_id}": { + "get": { + "summary": "Path Examples", + "operationId": "path_examples_path_examples__item_id__get", + "parameters": [ + { + "name": "item_id", + "in": "path", + "required": True, + "schema": { + "type": "string", + "examples": [ + "json_schema_item_1", + "json_schema_item_2", + ], + "title": "Item Id", + }, + "examples": { + "Path One": { + "summary": "Path One Summary", + "description": "Path One Description", + "value": "item_1", + }, + "Path Two": {"value": "item_2"}, + }, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/query_examples/": { + "get": { + "summary": "Query Examples", + "operationId": "query_examples_query_examples__get", + "parameters": [ + { + "name": "data", + "in": "query", + "required": False, + "schema": IsDict( + { + "anyOf": [{"type": "string"}, {"type": "null"}], + "examples": [ + "json_schema_query1", + "json_schema_query2", + ], + "title": "Data", + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "examples": [ + "json_schema_query1", + "json_schema_query2", + ], + "type": "string", + "title": "Data", + } + ), + "examples": { + "Query One": { + "summary": "Query One Summary", + "description": "Query One Description", + "value": "query1", + }, + "Query Two": {"value": "query2"}, + }, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/header_examples/": { + "get": { + "summary": "Header Examples", + "operationId": "header_examples_header_examples__get", + "parameters": [ + { + "name": "data", + "in": "header", + "required": False, + "schema": IsDict( + { + "anyOf": [{"type": "string"}, {"type": "null"}], + "examples": [ + "json_schema_header1", + "json_schema_header2", + ], + "title": "Data", + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "type": "string", + "examples": [ + "json_schema_header1", + "json_schema_header2", + ], + "title": "Data", + } + ), + "examples": { + "Header One": { + "summary": "Header One Summary", + "description": "Header One Description", + "value": "header1", + }, + "Header Two": {"value": "header2"}, + }, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/cookie_examples/": { + "get": { + "summary": "Cookie Examples", + "operationId": "cookie_examples_cookie_examples__get", + "parameters": [ + { + "name": "data", + "in": "cookie", + "required": False, + "schema": IsDict( + { + "anyOf": [{"type": "string"}, {"type": "null"}], + "examples": [ + "json_schema_cookie1", + "json_schema_cookie2", + ], + "title": "Data", + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "type": "string", + "examples": [ + "json_schema_cookie1", + "json_schema_cookie2", + ], + "title": "Data", + } + ), + "examples": { + "Cookie One": { + "summary": "Cookie One Summary", + "description": "Cookie One Description", + "value": "cookie1", + }, + "Cookie Two": {"value": "cookie2"}, + }, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": {"data": {"type": "string", "title": "Data"}}, + "type": "object", + "required": ["data"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py new file mode 100644 index 000000000..94a40ed5a --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py @@ -0,0 +1,166 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005 import app + + client = TestClient(app) + return client + + +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an.py new file mode 100644 index 000000000..da92f98f6 --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an.py @@ -0,0 +1,166 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005_an import app + + client = TestClient(app) + return client + + +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py310.py new file mode 100644 index 000000000..9109cb14e --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py310.py @@ -0,0 +1,170 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005_an_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +@needs_py310 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py39.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py39.py new file mode 100644 index 000000000..fd4ec0575 --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py39.py @@ -0,0 +1,170 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005_an_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +@needs_py39 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_py310.py new file mode 100644 index 000000000..05df53422 --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_py310.py @@ -0,0 +1,170 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +@needs_py310 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } From df16699dd8a5909b7de2d8c79f53f7153d922625 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 26 Aug 2023 18:03:56 +0000 Subject: [PATCH 09/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5d15e1c25..4021532d2 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for `openapi_examples` in all FastAPI parameters. PR [#10152](https://github.com/tiangolo/fastapi/pull/10152) by [@tiangolo](https://github.com/tiangolo). * 📝 Add note to docs about Separate Input and Output Schemas with FastAPI version. PR [#10150](https://github.com/tiangolo/fastapi/pull/10150) by [@tiangolo](https://github.com/tiangolo). ## 0.102.0 From bd32bca55cdbf3ca3e9de66b0e790772e019b55f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Aug 2023 20:09:59 +0200 Subject: [PATCH 10/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4021532d2..f61d1360d 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,8 +2,14 @@ ## Latest Changes +### Features + * ✨ Add support for `openapi_examples` in all FastAPI parameters. PR [#10152](https://github.com/tiangolo/fastapi/pull/10152) by [@tiangolo](https://github.com/tiangolo). + +### Docs + * 📝 Add note to docs about Separate Input and Output Schemas with FastAPI version. PR [#10150](https://github.com/tiangolo/fastapi/pull/10150) by [@tiangolo](https://github.com/tiangolo). + ## 0.102.0 ### Features From 415eb1405a5bc93a32e14c15d690517c95d26743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Aug 2023 20:10:27 +0200 Subject: [PATCH 11/54] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.103.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f61d1360d..91b29e772 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.103.0 + ### Features * ✨ Add support for `openapi_examples` in all FastAPI parameters. PR [#10152](https://github.com/tiangolo/fastapi/pull/10152) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 6979ec5fb..ff8b98d3b 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.102.0" +__version__ = "0.103.0" from starlette import status as status From a3f1689d78abef3d5d54ba655ec87cef81bf7384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Aug 2023 20:14:42 +0200 Subject: [PATCH 12/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 91b29e772..b60e024e5 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -8,6 +8,7 @@ ### Features * ✨ Add support for `openapi_examples` in all FastAPI parameters. PR [#10152](https://github.com/tiangolo/fastapi/pull/10152) by [@tiangolo](https://github.com/tiangolo). + * New docs: [OpenAPI-specific examples](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#openapi-specific-examples). ### Docs From 37d46e6b6c58c0e38747d91c4a0cdc0ea76c9d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 1 Sep 2023 23:36:08 +0200 Subject: [PATCH 13/54] =?UTF-8?q?=E2=9C=85=20Add=20missing=20test=20for=20?= =?UTF-8?q?OpenAPI=20examples,=20it=20was=20missing=20in=20coverage=20(#10?= =?UTF-8?q?188)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ Add missing test for OpenAPI examples, it seems it was discovered in coverage by an upgrade in AnyIO --- tests/test_openapi_examples.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_openapi_examples.py b/tests/test_openapi_examples.py index d0e35953e..70664a8a4 100644 --- a/tests/test_openapi_examples.py +++ b/tests/test_openapi_examples.py @@ -125,6 +125,9 @@ client = TestClient(app) def test_call_api(): + response = client.post("/examples/", json={"data": "example1"}) + assert response.status_code == 200, response.text + response = client.get("/path_examples/foo") assert response.status_code == 200, response.text From 7a63d11093d17de34a62dd10f81b1cf149c2e37b Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 1 Sep 2023 21:36:46 +0000 Subject: [PATCH 14/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b60e024e5..198bf3823 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✅ Add missing test for OpenAPI examples, it was missing in coverage. PR [#10188](https://github.com/tiangolo/fastapi/pull/10188) by [@tiangolo](https://github.com/tiangolo). ## 0.103.0 From 4bfe83bd2706536fcb0fa911c0e1e0bb95ba39ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 2 Sep 2023 01:32:40 +0200 Subject: [PATCH 15/54] =?UTF-8?q?=F0=9F=91=A5=20Update=20FastAPI=20People?= =?UTF-8?q?=20(#10186)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions --- docs/en/data/github_sponsors.yml | 80 ++++++++++------- docs/en/data/people.yml | 148 +++++++++++++++---------------- 2 files changed, 120 insertions(+), 108 deletions(-) diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml index 3a68ba62b..1ec71dd49 100644 --- a/docs/en/data/github_sponsors.yml +++ b/docs/en/data/github_sponsors.yml @@ -2,6 +2,9 @@ sponsors: - - login: cryptapi avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4 url: https://github.com/cryptapi + - login: porter-dev + avatarUrl: https://avatars.githubusercontent.com/u/62078005?v=4 + url: https://github.com/porter-dev - login: fern-api avatarUrl: https://avatars.githubusercontent.com/u/102944815?v=4 url: https://github.com/fern-api @@ -17,24 +20,21 @@ sponsors: - - login: mikeckennedy avatarUrl: https://avatars.githubusercontent.com/u/2035561?u=1bb18268bcd4d9249e1f783a063c27df9a84c05b&v=4 url: https://github.com/mikeckennedy + - login: ndimares + avatarUrl: https://avatars.githubusercontent.com/u/6267663?u=cfb27efde7a7212be8142abb6c058a1aeadb41b1&v=4 + url: https://github.com/ndimares - login: deta avatarUrl: https://avatars.githubusercontent.com/u/47275976?v=4 url: https://github.com/deta - login: deepset-ai avatarUrl: https://avatars.githubusercontent.com/u/51827949?v=4 url: https://github.com/deepset-ai - - login: svix - avatarUrl: https://avatars.githubusercontent.com/u/80175132?v=4 - url: https://github.com/svix - login: databento-bot avatarUrl: https://avatars.githubusercontent.com/u/98378480?u=494f679996e39427f7ddb1a7de8441b7c96fb670&v=4 url: https://github.com/databento-bot - login: VincentParedes avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4 url: https://github.com/VincentParedes -- - login: arcticfly - avatarUrl: https://avatars.githubusercontent.com/u/41524992?u=03c88529a86cf51f7a380e890d84d84c71468848&v=4 - url: https://github.com/arcticfly - - login: getsentry avatarUrl: https://avatars.githubusercontent.com/u/1396951?v=4 url: https://github.com/getsentry @@ -89,18 +89,18 @@ sponsors: - - login: povilasb avatarUrl: https://avatars.githubusercontent.com/u/1213442?u=b11f58ed6ceea6e8297c9b310030478ebdac894d&v=4 url: https://github.com/povilasb + - login: mukulmantosh + avatarUrl: https://avatars.githubusercontent.com/u/15572034?u=006f0a33c0e15bb2de57474a2cf7d2f8ee05f5a0&v=4 + url: https://github.com/mukulmantosh - login: primer-io avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4 url: https://github.com/primer-io - - login: indeedeng avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4 url: https://github.com/indeedeng - - login: iguit0 - avatarUrl: https://avatars.githubusercontent.com/u/12905770?u=63a1a96d1e6c27d85c4f946b84836599de047f65&v=4 - url: https://github.com/iguit0 - - login: JacobKochems - avatarUrl: https://avatars.githubusercontent.com/u/41692189?u=a75f62ddc0d060ee6233a91e19c433d2687b8eb6&v=4 - url: https://github.com/JacobKochems + - login: NateXVI + avatarUrl: https://avatars.githubusercontent.com/u/48195620?u=4bc8751ae50cb087c40c1fe811764aa070b9eea6&v=4 + url: https://github.com/NateXVI - - login: Kludex avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex @@ -200,12 +200,12 @@ sponsors: - login: hiancdtrsnm avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4 url: https://github.com/hiancdtrsnm - - login: Shackelford-Arden - avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4 - url: https://github.com/Shackelford-Arden - login: wdwinslow avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 url: https://github.com/wdwinslow + - login: jsoques + avatarUrl: https://avatars.githubusercontent.com/u/12414216?u=620921d94196546cc8b9eae2cc4cbc3f95bab42f&v=4 + url: https://github.com/jsoques - login: joeds13 avatarUrl: https://avatars.githubusercontent.com/u/13631604?u=628eb122e08bef43767b3738752b883e8e7f6259&v=4 url: https://github.com/joeds13 @@ -227,9 +227,6 @@ sponsors: - login: Filimoa avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=0be845711495bbd7b756e13fcaeb8efc1ebd78ba&v=4 url: https://github.com/Filimoa - - login: LarryGF - avatarUrl: https://avatars.githubusercontent.com/u/26148349?u=431bb34d36d41c172466252242175281ae132152&v=4 - url: https://github.com/LarryGF - login: BrettskiPy avatarUrl: https://avatars.githubusercontent.com/u/30988215?u=d8a94a67e140d5ee5427724b292cc52d8827087a&v=4 url: https://github.com/BrettskiPy @@ -239,6 +236,9 @@ sponsors: - login: Leay15 avatarUrl: https://avatars.githubusercontent.com/u/32212558?u=c4aa9c1737e515959382a5515381757b1fd86c53&v=4 url: https://github.com/Leay15 + - login: dvlpjrs + avatarUrl: https://avatars.githubusercontent.com/u/32254642?u=fbd6ad0324d4f1eb6231cf775be1c7bd4404e961&v=4 + url: https://github.com/dvlpjrs - login: ygorpontelo avatarUrl: https://avatars.githubusercontent.com/u/32963605?u=35f7103f9c4c4c2589ae5737ee882e9375ef072e&v=4 url: https://github.com/ygorpontelo @@ -284,15 +284,15 @@ sponsors: - login: DelfinaCare avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4 url: https://github.com/DelfinaCare + - login: hbakri + avatarUrl: https://avatars.githubusercontent.com/u/92298226?u=36eee6d75db1272264d3ee92f1871f70b8917bd8&v=4 + url: https://github.com/hbakri - login: osawa-koki avatarUrl: https://avatars.githubusercontent.com/u/94336223?u=59c6fe6945bcbbaff87b2a794238671b060620d2&v=4 url: https://github.com/osawa-koki - login: pyt3h avatarUrl: https://avatars.githubusercontent.com/u/99658549?v=4 url: https://github.com/pyt3h - - login: Dagmaara - avatarUrl: https://avatars.githubusercontent.com/u/115501964?v=4 - url: https://github.com/Dagmaara - - login: SebTota avatarUrl: https://avatars.githubusercontent.com/u/25122511?v=4 url: https://github.com/SebTota @@ -329,6 +329,9 @@ sponsors: - login: janfilips avatarUrl: https://avatars.githubusercontent.com/u/870699?u=80702ec63f14e675cd4cdcc6ce3821d2ed207fd7&v=4 url: https://github.com/janfilips + - login: dodo5522 + avatarUrl: https://avatars.githubusercontent.com/u/1362607?u=9bf1e0e520cccc547c046610c468ce6115bbcf9f&v=4 + url: https://github.com/dodo5522 - login: WillHogan avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4 url: https://github.com/WillHogan @@ -374,9 +377,6 @@ sponsors: - login: katnoria avatarUrl: https://avatars.githubusercontent.com/u/7674948?u=09767eb13e07e09496c5fee4e5ce21d9eac34a56&v=4 url: https://github.com/katnoria - - login: mattwelke - avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=80f02a799323b1472b389b836d95957c93a6d856&v=4 - url: https://github.com/mattwelke - login: harsh183 avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4 url: https://github.com/harsh183 @@ -422,6 +422,9 @@ sponsors: - login: jangia avatarUrl: https://avatars.githubusercontent.com/u/17927101?u=9261b9bb0c3e3bb1ecba43e8915dc58d8c9a077e&v=4 url: https://github.com/jangia + - login: timzaz + avatarUrl: https://avatars.githubusercontent.com/u/19709244?u=e6658f6b0b188294ce2db20dad94a678fcea718d&v=4 + url: https://github.com/timzaz - login: shuheng-liu avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4 url: https://github.com/shuheng-liu @@ -431,6 +434,9 @@ sponsors: - login: kxzk avatarUrl: https://avatars.githubusercontent.com/u/25046261?u=e185e58080090f9e678192cd214a14b14a2b232b&v=4 url: https://github.com/kxzk + - login: nisutec + avatarUrl: https://avatars.githubusercontent.com/u/25281462?u=e562484c451fdfc59053163f64405f8eb262b8b0&v=4 + url: https://github.com/nisutec - login: hoenie-ams avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4 url: https://github.com/hoenie-ams @@ -450,7 +456,7 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4 url: https://github.com/engineerjoe440 - login: bnkc - avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=527044d90b5ebb7f8dad517db5da1f45253b774b&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=1a104991a2ea90bfe304bc0b9ef191c7e4891a0e&v=4 url: https://github.com/bnkc - login: declon avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4 @@ -482,6 +488,15 @@ sponsors: - login: 0417taehyun avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4 url: https://github.com/0417taehyun + - login: romabozhanovgithub + avatarUrl: https://avatars.githubusercontent.com/u/67696229?u=e4b921eef096415300425aca249348f8abb78ad7&v=4 + url: https://github.com/romabozhanovgithub + - login: mnicolleUTC + avatarUrl: https://avatars.githubusercontent.com/u/68548924?u=1fdd7f436bb1f4857c3415e62aa8fbc055fc1a76&v=4 + url: https://github.com/mnicolleUTC + - login: mbukeRepo + avatarUrl: https://avatars.githubusercontent.com/u/70356088?u=e125069c6ac5c49355e2b3ca2aa66a445fc4cccd&v=4 + url: https://github.com/mbukeRepo - - login: ssbarnea avatarUrl: https://avatars.githubusercontent.com/u/102495?u=b4bf6818deefe59952ac22fec6ed8c76de1b8f7c&v=4 url: https://github.com/ssbarnea @@ -494,21 +509,18 @@ sponsors: - login: sadikkuzu avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=d179c06bb9f65c4167fcab118526819f8e0dac17&v=4 url: https://github.com/sadikkuzu - - login: ruizdiazever - avatarUrl: https://avatars.githubusercontent.com/u/29817086?u=2df54af55663d246e3a4dc8273711c37f1adb117&v=4 - url: https://github.com/ruizdiazever - login: samnimoh avatarUrl: https://avatars.githubusercontent.com/u/33413170?u=147bc516be6cb647b28d7e3b3fea3a018a331145&v=4 url: https://github.com/samnimoh - login: danburonline avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4 url: https://github.com/danburonline - - login: iharshgor - avatarUrl: https://avatars.githubusercontent.com/u/35490011?u=2dea054476e752d9e92c9d71a9a7cc919b1c2f8e&v=4 - url: https://github.com/iharshgor + - login: koalawangyang + avatarUrl: https://avatars.githubusercontent.com/u/40114367?u=3bb94010f0473b8d4c2edea5a8c1cab61e6a1b22&v=4 + url: https://github.com/koalawangyang - login: rwxd avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4 url: https://github.com/rwxd - - login: ThomasPalma1 - avatarUrl: https://avatars.githubusercontent.com/u/66331874?u=5763f7402d784ba189b60d704ff5849b4d0a63fb&v=4 - url: https://github.com/ThomasPalma1 + - login: lodine-software + avatarUrl: https://avatars.githubusercontent.com/u/133536046?v=4 + url: https://github.com/lodine-software diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 89d189564..8ebd2f84c 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,16 +1,16 @@ maintainers: - login: tiangolo - answers: 1849 - prs: 466 + answers: 1866 + prs: 486 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 463 + count: 480 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: dmontagu - count: 239 + count: 240 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 url: https://github.com/dmontagu - login: Mause @@ -26,7 +26,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 url: https://github.com/JarroVGIT - login: jgould22 - count: 157 + count: 164 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 url: https://github.com/jgould22 - login: euri10 @@ -38,7 +38,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 - login: iudeen - count: 121 + count: 122 avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 url: https://github.com/iudeen - login: raphaelauv @@ -61,34 +61,34 @@ experts: count: 49 avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 url: https://github.com/sm-Fifteen -- login: insomnes - count: 45 - avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 - url: https://github.com/insomnes - login: yinziyan1206 count: 45 avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4 url: https://github.com/yinziyan1206 -- login: acidjunk +- login: insomnes count: 45 - avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 - url: https://github.com/acidjunk + avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 + url: https://github.com/insomnes - login: Dustyposa count: 45 avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 url: https://github.com/Dustyposa +- login: acidjunk + count: 45 + avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 + url: https://github.com/acidjunk - login: adriangb count: 44 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4 url: https://github.com/adriangb -- login: frankie567 - count: 43 - avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 - url: https://github.com/frankie567 - login: odiseo0 count: 43 avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4 url: https://github.com/odiseo0 +- login: frankie567 + count: 43 + avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=c159fe047727aedecbbeeaa96a1b03ceb9d39add&v=4 + url: https://github.com/frankie567 - login: includeamin count: 40 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 @@ -97,14 +97,14 @@ experts: count: 37 avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 url: https://github.com/STeveShary +- login: chbndrhnns + count: 36 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: krishnardt count: 35 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 url: https://github.com/krishnardt -- login: chbndrhnns - count: 35 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns - login: panla count: 32 avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 @@ -117,26 +117,30 @@ experts: count: 26 avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4 url: https://github.com/dbanty +- login: n8sty + count: 25 + avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 + url: https://github.com/n8sty - login: wshayes count: 25 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes -- login: acnebs - count: 23 - avatarUrl: https://avatars.githubusercontent.com/u/9054108?v=4 - url: https://github.com/acnebs - login: SirTelemak count: 23 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak +- login: acnebs + count: 23 + avatarUrl: https://avatars.githubusercontent.com/u/9054108?v=4 + url: https://github.com/acnebs - login: rafsaf count: 21 - avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=5fe59a56e1f2f9ccd8005d71752a8276f133ae1a&v=4 url: https://github.com/rafsaf -- login: n8sty +- login: JavierSanchezCastro count: 20 - avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 - url: https://github.com/n8sty + avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4 + url: https://github.com/JavierSanchezCastro - login: nsidnev count: 20 avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4 @@ -173,55 +177,51 @@ experts: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4 url: https://github.com/jonatasoli +- login: ebottos94 + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=e2c672da5a7977fd24d87ce6ab35f8bf5b1ed9fa&v=4 + url: https://github.com/ebottos94 - login: dstlny count: 16 avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 url: https://github.com/dstlny -- login: abhint +- login: chrisK824 count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=b5d219277b4d001ac26fb8be357fddd88c29d51b&v=4 - url: https://github.com/abhint + avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4 + url: https://github.com/chrisK824 - login: nymous count: 15 avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4 url: https://github.com/nymous -- login: ghost - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/10137?u=b1951d34a583cf12ec0d3b0781ba19be97726318&v=4 - url: https://github.com/ghost -- login: simondale00 - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/33907262?v=4 - url: https://github.com/simondale00 -- login: jorgerpo +- login: abhint count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4 - url: https://github.com/jorgerpo + avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=b5d219277b4d001ac26fb8be357fddd88c29d51b&v=4 + url: https://github.com/abhint last_month_active: +- login: JavierSanchezCastro + count: 12 + avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4 + url: https://github.com/JavierSanchezCastro - login: Kludex - count: 24 + count: 10 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: jgould22 - count: 17 + count: 8 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 url: https://github.com/jgould22 -- login: arjwilliams - count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/22227620?v=4 - url: https://github.com/arjwilliams -- login: Ahmed-Abdou14 - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/104530599?u=05365b155a1ff911532e8be316acfad2e0736f98&v=4 - url: https://github.com/Ahmed-Abdou14 -- login: iudeen - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 - url: https://github.com/iudeen -- login: mikeedjones +- login: romabozhanovgithub + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/67696229?u=e4b921eef096415300425aca249348f8abb78ad7&v=4 + url: https://github.com/romabozhanovgithub +- login: n8sty + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 + url: https://github.com/n8sty +- login: chrisK824 count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/4087139?u=cc4a242896ac2fcf88a53acfaf190d0fe0a1f0c9&v=4 - url: https://github.com/mikeedjones + avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4 + url: https://github.com/chrisK824 top_contributors: - login: waynerv count: 25 @@ -235,22 +235,22 @@ top_contributors: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex +- login: dmontagu + count: 17 + avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 + url: https://github.com/dmontagu - login: jaystone776 count: 17 avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 url: https://github.com/jaystone776 -- login: dmontagu - count: 16 - avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 - url: https://github.com/dmontagu +- login: Xewus + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4 + url: https://github.com/Xewus - login: euri10 count: 13 avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4 url: https://github.com/euri10 -- login: Xewus - count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4 - url: https://github.com/Xewus - login: mariacamilagl count: 12 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 @@ -360,6 +360,10 @@ top_reviewers: count: 78 avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=d7062cbc6eb7671d5dc9cc0e32a24ae335e0f225&v=4 url: https://github.com/yezz123 +- login: iudeen + count: 53 + avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 + url: https://github.com/iudeen - login: tokusumi count: 51 avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 @@ -372,10 +376,6 @@ top_reviewers: count: 47 avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4 url: https://github.com/Laineyzhang55 -- login: iudeen - count: 46 - avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 - url: https://github.com/iudeen - login: ycd count: 45 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4 @@ -385,7 +385,7 @@ top_reviewers: avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 url: https://github.com/cikay - login: Xewus - count: 38 + count: 39 avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4 url: https://github.com/Xewus - login: JarroVGIT @@ -482,7 +482,7 @@ top_reviewers: url: https://github.com/sh0nk - login: peidrao count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=5b94b548ef0002ef3219d7c07ac0fac17c6201a2&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=a66902b40c13647d0ed0e573d598128240a4dd04&v=4 url: https://github.com/peidrao - login: r0b2g1t count: 13 From ee0b28a398db5e4f7bfe8d53284e9c0575c9543d Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 1 Sep 2023 23:33:31 +0000 Subject: [PATCH 16/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 198bf3823..3b10fe405 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 👥 Update FastAPI People. PR [#10186](https://github.com/tiangolo/fastapi/pull/10186) by [@tiangolo](https://github.com/tiangolo). * ✅ Add missing test for OpenAPI examples, it was missing in coverage. PR [#10188](https://github.com/tiangolo/fastapi/pull/10188) by [@tiangolo](https://github.com/tiangolo). ## 0.103.0 From bf952d345c36807b5931ce6f74c40aa4e7308ccf Mon Sep 17 00:00:00 2001 From: PieCat <53287533+funny-cat-happy@users.noreply.github.com> Date: Sat, 2 Sep 2023 23:18:30 +0800 Subject: [PATCH 17/54] =?UTF-8?q?=F0=9F=8C=90=20Add=20Chinese=20translatio?= =?UTF-8?q?n=20for=20`docs/zh/docs/advanced/generate-clients.md`=20(#9883)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: xzmeng Co-authored-by: Sebastián Ramírez --- docs/zh/docs/advanced/generate-clients.md | 266 ++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 docs/zh/docs/advanced/generate-clients.md diff --git a/docs/zh/docs/advanced/generate-clients.md b/docs/zh/docs/advanced/generate-clients.md new file mode 100644 index 000000000..f3a58c062 --- /dev/null +++ b/docs/zh/docs/advanced/generate-clients.md @@ -0,0 +1,266 @@ +# 生成客户端 + +因为 **FastAPI** 是基于OpenAPI规范的,自然您可以使用许多相匹配的工具,包括自动生成API文档 (由 Swagger UI 提供)。 + +一个不太明显而又特别的优势是,你可以为你的API针对不同的**编程语言**来**生成客户端**(有时候被叫做 **SDKs** )。 + +## OpenAPI 客户端生成 + +有许多工具可以从**OpenAPI**生成客户端。 + +一个常见的工具是 OpenAPI Generator。 + +如果您正在开发**前端**,一个非常有趣的替代方案是 openapi-typescript-codegen。 + +## 生成一个 TypeScript 前端客户端 + +让我们从一个简单的 FastAPI 应用开始: + +=== "Python 3.9+" + + ```Python hl_lines="7-9 12-13 16-17 21" + {!> ../../../docs_src/generate_clients/tutorial001_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="9-11 14-15 18 19 23" + {!> ../../../docs_src/generate_clients/tutorial001.py!} + ``` + +请注意,*路径操作* 定义了他们所用于请求数据和回应数据的模型,所使用的模型是`Item` 和 `ResponseMessage`。 + +### API 文档 + +如果您访问API文档,您将看到它具有在请求中发送和在响应中接收数据的**模式(schemas)**: + + + +您可以看到这些模式,因为它们是用程序中的模型声明的。 + +那些信息可以在应用的 **OpenAPI模式** 被找到,然后显示在API文档中(通过Swagger UI)。 + +OpenAPI中所包含的模型里有相同的信息可以用于 **生成客户端代码**。 + +### 生成一个TypeScript 客户端 + +现在我们有了带有模型的应用,我们可以为前端生成客户端代码。 + +#### 安装 `openapi-typescript-codegen` + +您可以使用以下工具在前端代码中安装 `openapi-typescript-codegen`: + +
+ +```console +$ npm install openapi-typescript-codegen --save-dev + +---> 100% +``` + +
+ +#### 生成客户端代码 + +要生成客户端代码,您可以使用现在将要安装的命令行应用程序 `openapi`。 + +因为它安装在本地项目中,所以您可能无法直接使用此命令,但您可以将其放在 `package.json` 文件中。 + +它可能看起来是这样的: + +```JSON hl_lines="7" +{ + "name": "frontend-app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios" + }, + "author": "", + "license": "", + "devDependencies": { + "openapi-typescript-codegen": "^0.20.1", + "typescript": "^4.6.2" + } +} +``` + +在这里添加 NPM `generate-client` 脚本后,您可以使用以下命令运行它: + +
+ +```console +$ npm run generate-client + +frontend-app@1.0.0 generate-client /home/user/code/frontend-app +> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios +``` + +
+ +此命令将在 `./src/client` 中生成代码,并将在其内部使用 `axios`(前端HTTP库)。 + +### 尝试客户端代码 + +现在您可以导入并使用客户端代码,它可能看起来像这样,请注意,您可以为这些方法使用自动补全: + + + +您还将自动补全要发送的数据: + + + +!!! tip + 请注意, `name` 和 `price` 的自动补全,是通过其在`Item`模型(FastAPI)中的定义实现的。 + +如果发送的数据字段不符,你也会看到编辑器的错误提示: + + + +响应(response)对象也拥有自动补全: + + + +## 带有标签的 FastAPI 应用 + +在许多情况下,你的FastAPI应用程序会更复杂,你可能会使用标签来分隔不同组的*路径操作(path operations)*。 + +例如,您可以有一个用 `items` 的部分和另一个用于 `users` 的部分,它们可以用标签来分隔: + +=== "Python 3.9+" + + ```Python hl_lines="21 26 34" + {!> ../../../docs_src/generate_clients/tutorial002_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="23 28 36" + {!> ../../../docs_src/generate_clients/tutorial002.py!} + ``` + +### 生成带有标签的 TypeScript 客户端 + +如果您使用标签为FastAPI应用生成客户端,它通常也会根据标签分割客户端代码。 + +通过这种方式,您将能够为客户端代码进行正确地排序和分组: + + + +在这个案例中,您有: + +* `ItemsService` +* `UsersService` + +### 客户端方法名称 + +现在生成的方法名像 `createItemItemsPost` 看起来不太简洁: + +```TypeScript +ItemsService.createItemItemsPost({name: "Plumbus", price: 5}) +``` + +...这是因为客户端生成器为每个 *路径操作* 使用OpenAPI的内部 **操作 ID(operation ID)**。 + +OpenAPI要求每个操作 ID 在所有 *路径操作* 中都是唯一的,因此 FastAPI 使用**函数名**、**路径**和**HTTP方法/操作**来生成此操作ID,因为这样可以确保这些操作 ID 是唯一的。 + +但接下来我会告诉你如何改进。 🤓 + +## 自定义操作ID和更好的方法名 + +您可以**修改**这些操作ID的**生成**方式,以使其更简洁,并在客户端中具有**更简洁的方法名称**。 + +在这种情况下,您必须确保每个操作ID在其他方面是**唯一**的。 + +例如,您可以确保每个*路径操作*都有一个标签,然后根据**标签**和*路径操作***名称**(函数名)来生成操作ID。 + +### 自定义生成唯一ID函数 + +FastAPI为每个*路径操作*使用一个**唯一ID**,它用于**操作ID**,也用于任何所需自定义模型的名称,用于请求或响应。 + +你可以自定义该函数。它接受一个 `APIRoute` 对象作为输入,并输出一个字符串。 + +例如,以下是一个示例,它使用第一个标签(你可能只有一个标签)和*路径操作*名称(函数名)。 + +然后,你可以将这个自定义函数作为 `generate_unique_id_function` 参数传递给 **FastAPI**: + +=== "Python 3.9+" + + ```Python hl_lines="6-7 10" + {!> ../../../docs_src/generate_clients/tutorial003_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="8-9 12" + {!> ../../../docs_src/generate_clients/tutorial003.py!} + ``` + +### 使用自定义操作ID生成TypeScript客户端 + +现在,如果你再次生成客户端,你会发现它具有改善的方法名称: + + + +正如你所见,现在方法名称中只包含标签和函数名,不再包含URL路径和HTTP操作的信息。 + +### 预处理用于客户端生成器的OpenAPI规范 + +生成的代码仍然存在一些**重复的信息**。 + +我们已经知道该方法与 **items** 相关,因为它在 `ItemsService` 中(从标签中获取),但方法名中仍然有标签名作为前缀。😕 + +一般情况下对于OpenAPI,我们可能仍然希望保留它,因为这将确保操作ID是**唯一的**。 + +但对于生成的客户端,我们可以在生成客户端之前**修改** OpenAPI 操作ID,以使方法名称更加美观和**简洁**。 + +我们可以将 OpenAPI JSON 下载到一个名为`openapi.json`的文件中,然后使用以下脚本**删除此前缀的标签**: + +```Python +{!../../../docs_src/generate_clients/tutorial004.py!} +``` + +通过这样做,操作ID将从类似于 `items-get_items` 的名称重命名为 `get_items` ,这样客户端生成器就可以生成更简洁的方法名称。 + +### 使用预处理的OpenAPI生成TypeScript客户端 + +现在,由于最终结果保存在文件openapi.json中,你可以修改 package.json 文件以使用此本地文件,例如: + +```JSON hl_lines="7" +{ + "name": "frontend-app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "generate-client": "openapi --input ./openapi.json --output ./src/client --client axios" + }, + "author": "", + "license": "", + "devDependencies": { + "openapi-typescript-codegen": "^0.20.1", + "typescript": "^4.6.2" + } +} +``` + +生成新的客户端之后,你现在将拥有**清晰的方法名称**,具备**自动补全**、**错误提示**等功能: + + + +## 优点 + +当使用自动生成的客户端时,你将获得以下的自动补全功能: + +* 方法。 +* 请求体中的数据、查询参数等。 +* 响应数据。 + +你还将获得针对所有内容的错误提示。 + +每当你更新后端代码并**重新生成**前端代码时,新的*路径操作*将作为方法可用,旧的方法将被删除,并且其他任何更改将反映在生成的代码中。 🤓 + +这也意味着如果有任何更改,它将自动**反映**在客户端代码中。如果你**构建**客户端,在使用的数据上存在**不匹配**时,它将报错。 + +因此,你将在开发周期的早期**检测到许多错误**,而不必等待错误在生产环境中向最终用户展示,然后尝试调试问题所在。 ✨ From 82ff9a6920115f6b2c00acdf03452a297b926604 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 15:19:08 +0000 Subject: [PATCH 18/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 3b10fe405..5852de5d0 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Chinese translation for `docs/zh/docs/advanced/generate-clients.md`. PR [#9883](https://github.com/tiangolo/fastapi/pull/9883) by [@funny-cat-happy](https://github.com/funny-cat-happy). * 👥 Update FastAPI People. PR [#10186](https://github.com/tiangolo/fastapi/pull/10186) by [@tiangolo](https://github.com/tiangolo). * ✅ Add missing test for OpenAPI examples, it was missing in coverage. PR [#10188](https://github.com/tiangolo/fastapi/pull/10188) by [@tiangolo](https://github.com/tiangolo). From d8f2f39f6ddc07aa9bc25f7eea8cb752330d7374 Mon Sep 17 00:00:00 2001 From: xzmeng Date: Sat, 2 Sep 2023 23:22:24 +0800 Subject: [PATCH 19/54] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20typos=20in=20`?= =?UTF-8?q?docs/en/docs/how-to/separate-openapi-schemas.md`=20and=20`docs/?= =?UTF-8?q?en/docs/tutorial/schema-extra-example.md`=20(#10189)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/how-to/separate-openapi-schemas.md | 2 +- docs/en/docs/tutorial/schema-extra-example.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/docs/how-to/separate-openapi-schemas.md b/docs/en/docs/how-to/separate-openapi-schemas.md index d289391ca..d38be3c59 100644 --- a/docs/en/docs/how-to/separate-openapi-schemas.md +++ b/docs/en/docs/how-to/separate-openapi-schemas.md @@ -160,7 +160,7 @@ If you interact with the docs and check the response, even though the code didn' This means that it will **always have a value**, it's just that sometimes the value could be `None` (or `null` in JSON). -That means that, clients using your API don't have to check if the value exists or not, they can **asume the field will always be there**, but just that in some cases it will have the default value of `None`. +That means that, clients using your API don't have to check if the value exists or not, they can **assume the field will always be there**, but just that in some cases it will have the default value of `None`. The way to describe this in OpenAPI, is to mark that field as **required**, because it will always be there. diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md index 8cf1b9c09..9eeb3f1f2 100644 --- a/docs/en/docs/tutorial/schema-extra-example.md +++ b/docs/en/docs/tutorial/schema-extra-example.md @@ -38,13 +38,13 @@ That extra info will be added as-is to the output **JSON Schema** for that model In Pydantic version 2, you would use the attribute `model_config`, that takes a `dict` as described in Pydantic's docs: Model Config. - You can set `"json_schema_extra"` with a `dict` containing any additonal data you would like to show up in the generated JSON Schema, including `examples`. + You can set `"json_schema_extra"` with a `dict` containing any additional data you would like to show up in the generated JSON Schema, including `examples`. === "Pydantic v1" In Pydantic version 1, you would use an internal class `Config` and `schema_extra`, as described in Pydantic's docs: Schema customization. - You can set `schema_extra` with a `dict` containing any additonal data you would like to show up in the generated JSON Schema, including `examples`. + You can set `schema_extra` with a `dict` containing any additional data you would like to show up in the generated JSON Schema, including `examples`. !!! tip You could use the same technique to extend the JSON Schema and add your own custom extra info. From 8cb33e9b477a32ccac867bd5be655e9426d4ccb9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 15:24:05 +0000 Subject: [PATCH 20/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5852de5d0..357adc8d3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix typos in `docs/en/docs/how-to/separate-openapi-schemas.md` and `docs/en/docs/tutorial/schema-extra-example.md`. PR [#10189](https://github.com/tiangolo/fastapi/pull/10189) by [@xzmeng](https://github.com/xzmeng). * 🌐 Add Chinese translation for `docs/zh/docs/advanced/generate-clients.md`. PR [#9883](https://github.com/tiangolo/fastapi/pull/9883) by [@funny-cat-happy](https://github.com/funny-cat-happy). * 👥 Update FastAPI People. PR [#10186](https://github.com/tiangolo/fastapi/pull/10186) by [@tiangolo](https://github.com/tiangolo). * ✅ Add missing test for OpenAPI examples, it was missing in coverage. PR [#10188](https://github.com/tiangolo/fastapi/pull/10188) by [@tiangolo](https://github.com/tiangolo). From 1d688a062e59b11b160191d77a9f11971b316cb5 Mon Sep 17 00:00:00 2001 From: Rostyslav Date: Sat, 2 Sep 2023 18:29:36 +0300 Subject: [PATCH 21/54] =?UTF-8?q?=F0=9F=8C=90=20Add=20Ukrainian=20translat?= =?UTF-8?q?ion=20for=20`docs/uk/docs/tutorial/index.md`=20(#10079)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/uk/docs/tutorial/index.md | 80 ++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 docs/uk/docs/tutorial/index.md diff --git a/docs/uk/docs/tutorial/index.md b/docs/uk/docs/tutorial/index.md new file mode 100644 index 000000000..e5bae74bc --- /dev/null +++ b/docs/uk/docs/tutorial/index.md @@ -0,0 +1,80 @@ +# Туторіал - Посібник користувача + +У цьому посібнику показано, як користуватися **FastAPI** з більшістю його функцій, крок за кроком. + +Кожен розділ поступово надбудовується на попередні, але він структурований на окремі теми, щоб ви могли перейти безпосередньо до будь-якої конкретної, щоб вирішити ваші конкретні потреби API. + +Він також створений як довідник для роботи у майбутньому. + +Тож ви можете повернутися і побачити саме те, що вам потрібно. + +## Запустіть код + +Усі блоки коду можна скопіювати та використовувати безпосередньо (це фактично перевірені файли Python). + +Щоб запустити будь-який із прикладів, скопіюйте код у файл `main.py` і запустіть `uvicorn` за допомогою: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +**ДУЖЕ радимо** написати або скопіювати код, відредагувати його та запустити локально. + +Використання його у своєму редакторі – це те, що дійсно показує вам переваги FastAPI, бачите, як мало коду вам потрібно написати, всі перевірки типів, автозаповнення тощо. + +--- + +## Встановлення FastAPI + +Першим кроком є встановлення FastAPI. + +Для туторіалу ви можете встановити його з усіма необов’язковими залежностями та функціями: + +
+ +```console +$ pip install "fastapi[all]" + +---> 100% +``` + +
+ +...який також включає `uvicorn`, який ви можете використовувати як сервер, який запускає ваш код. + +!!! note + Ви також можете встановити його частина за частиною. + + Це те, що ви, ймовірно, зробили б, коли захочете розгорнути свою програму у виробничому середовищі: + + ``` + pip install fastapi + ``` + + Також встановіть `uvicorn`, щоб він працював як сервер: + + ``` + pip install "uvicorn[standard]" + ``` + + І те саме для кожної з опціональних залежностей, які ви хочете використовувати. + +## Розширений посібник користувача + +Існує також **Розширений посібник користувача**, який ви зможете прочитати пізніше після цього **Туторіал - Посібник користувача**. + +**Розширений посібник користувача** засновано на цьому, використовує ті самі концепції та навчає вас деяким додатковим функціям. + +Але вам слід спочатку прочитати **Туторіал - Посібник користувача** (те, що ви зараз читаєте). + +Він розроблений таким чином, що ви можете створити повну програму лише за допомогою **Туторіал - Посібник користувача**, а потім розширити її різними способами, залежно від ваших потреб, використовуючи деякі з додаткових ідей з **Розширеного посібника користувача** . From 48f6ccfe7d852867ca1be3aa0e0d782e613cfe61 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 15:31:37 +0000 Subject: [PATCH 22/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 357adc8d3..09f19f0f6 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/index.md`. PR [#10079](https://github.com/tiangolo/fastapi/pull/10079) by [@rostik1410](https://github.com/rostik1410). * ✏️ Fix typos in `docs/en/docs/how-to/separate-openapi-schemas.md` and `docs/en/docs/tutorial/schema-extra-example.md`. PR [#10189](https://github.com/tiangolo/fastapi/pull/10189) by [@xzmeng](https://github.com/xzmeng). * 🌐 Add Chinese translation for `docs/zh/docs/advanced/generate-clients.md`. PR [#9883](https://github.com/tiangolo/fastapi/pull/9883) by [@funny-cat-happy](https://github.com/funny-cat-happy). * 👥 Update FastAPI People. PR [#10186](https://github.com/tiangolo/fastapi/pull/10186) by [@tiangolo](https://github.com/tiangolo). From ad76dd1aa806fb62ad64a2b5c14fe00393ed2589 Mon Sep 17 00:00:00 2001 From: whysage <67018871+whysage@users.noreply.github.com> Date: Sat, 2 Sep 2023 18:32:30 +0300 Subject: [PATCH 23/54] =?UTF-8?q?=F0=9F=8C=90=20Add=20Ukrainian=20translat?= =?UTF-8?q?ion=20for=20`docs/uk/docs/alternatives.md`=20(#10060)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/uk/docs/alternatives.md | 412 +++++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 docs/uk/docs/alternatives.md diff --git a/docs/uk/docs/alternatives.md b/docs/uk/docs/alternatives.md new file mode 100644 index 000000000..e71257976 --- /dev/null +++ b/docs/uk/docs/alternatives.md @@ -0,0 +1,412 @@ +# Альтернативи, натхнення та порівняння + +Що надихнуло на створення **FastAPI**, який він у порінянні з іншими альтернативами та чого він у них навчився. + +## Вступ + +**FastAPI** не існувало б, якби не попередні роботи інших. + +Раніше було створено багато інструментів, які надихнули на його створення. + +Я кілька років уникав створення нового фреймворку. Спочатку я спробував вирішити всі функції, охоплені **FastAPI**, використовуючи багато різних фреймворків, плагінів та інструментів. + +Але в якийсь момент не було іншого виходу, окрім створення чогось, що надавало б усі ці функції, взявши найкращі ідеї з попередніх інструментів і поєднавши їх найкращим чином, використовуючи мовні функції, які навіть не були доступні раніше (Python 3.6+ підказки типів). + +## Попередні інструменти + +### Django + +Це найпопулярніший фреймворк Python, який користується широкою довірою. Він використовується для створення таких систем, як Instagram. + +Він відносно тісно пов’язаний з реляційними базами даних (наприклад, MySQL або PostgreSQL), тому мати базу даних NoSQL (наприклад, Couchbase, MongoDB, Cassandra тощо) як основний механізм зберігання не дуже просто. + +Він був створений для створення HTML у серверній частині, а не для створення API, які використовуються сучасним інтерфейсом (як-от React, Vue.js і Angular) або іншими системами (як-от IoT пристрої), які спілкуються з ним. + +### Django REST Framework + +Фреймворк Django REST був створений як гнучкий інструментарій для створення веб-інтерфейсів API використовуючи Django в основі, щоб покращити його можливості API. + +Його використовують багато компаній, включаючи Mozilla, Red Hat і Eventbrite. + +Це був один із перших прикладів **автоматичної документації API**, і саме це була одна з перших ідей, яка надихнула на «пошук» **FastAPI**. + +!!! Примітка + Django REST Framework створив Том Крісті. Той самий творець Starlette і Uvicorn, на яких базується **FastAPI**. + + +!!! Перегляньте "Надихнуло **FastAPI** на" + Мати автоматичний веб-інтерфейс документації API. + +### Flask + +Flask — це «мікрофреймворк», він не включає інтеграцію бази даних, а також багато речей, які за замовчуванням є в Django. + +Ця простота та гнучкість дозволяють використовувати бази даних NoSQL як основну систему зберігання даних. + +Оскільки він дуже простий, він порівняно легкий та інтуїтивний для освоєння, хоча в деяких моментах документація стає дещо технічною. + +Він також зазвичай використовується для інших програм, яким не обов’язково потрібна база даних, керування користувачами або будь-яка з багатьох функцій, які є попередньо вбудованими в Django. Хоча багато з цих функцій можна додати за допомогою плагінів. + +Відокремлення частин було ключовою особливістю, яку я хотів зберегти, при цьому залишаючись «мікрофреймворком», який можна розширити, щоб охопити саме те, що потрібно. + +Враховуючи простоту Flask, він здавався хорошим підходом для створення API. Наступним, що знайшов, був «Django REST Framework» для Flask. + +!!! Переглянте "Надихнуло **FastAPI** на" + Бути мікрофреймоворком. Зробити легким комбінування та поєднання необхідних інструментів та частин. + + Мати просту та легку у використанні систему маршрутизації. + + +### Requests + +**FastAPI** насправді не є альтернативою **Requests**. Сфера їх застосування дуже різна. + +Насправді цілком звична річ використовувати Requests *всередині* програми FastAPI. + +Але все ж FastAPI черпав натхнення з Requests. + +**Requests** — це бібліотека для *взаємодії* з API (як клієнт), а **FastAPI** — це бібліотека для *створення* API (як сервер). + +Вони більш-менш знаходяться на протилежних кінцях, доповнюючи одна одну. + +Requests мають дуже простий та інтуїтивно зрозумілий дизайн, дуже простий у використанні, з розумними параметрами за замовчуванням. Але в той же час він дуже потужний і налаштовується. + +Ось чому, як сказано на офіційному сайті: + +> Requests є одним із найбільш завантажуваних пакетів Python усіх часів + +Використовувати його дуже просто. Наприклад, щоб виконати запит `GET`, ви повинні написати: + +```Python +response = requests.get("http://example.com/some/url") +``` + +Відповідна операція *роуту* API FastAPI може виглядати так: + +```Python hl_lines="1" +@app.get("/some/url") +def read_url(): + return {"message": "Hello World"} +``` + +Зверніть увагу на схожість у `requests.get(...)` і `@app.get(...)`. + +!!! Перегляньте "Надихнуло **FastAPI** на" + * Майте простий та інтуїтивно зрозумілий API. + * Використовуйте імена (операції) методів HTTP безпосередньо, простим та інтуїтивно зрозумілим способом. + * Розумні параметри за замовчуванням, але потужні налаштування. + + +### Swagger / OpenAPI + +Головною функцією, яку я хотів від Django REST Framework, була автоматична API документація. + +Потім я виявив, що існує стандарт для документування API з використанням JSON (або YAML, розширення JSON) під назвою Swagger. + +І вже був створений веб-інтерфейс користувача для Swagger API. Отже, можливість генерувати документацію Swagger для API дозволить використовувати цей веб-інтерфейс автоматично. + +У якийсь момент Swagger було передано Linux Foundation, щоб перейменувати його на OpenAPI. + +Тому, коли говорять про версію 2.0, прийнято говорити «Swagger», а про версію 3+ «OpenAPI». + +!!! Перегляньте "Надихнуло **FastAPI** на" + Прийняти і використовувати відкритий стандарт для специфікацій API замість спеціальної схеми. + + Інтегрувати інструменти інтерфейсу на основі стандартів: + + * Інтерфейс Swagger + * ReDoc + + Ці два було обрано через те, що вони досить популярні та стабільні, але, виконавши швидкий пошук, ви можете знайти десятки додаткових альтернативних інтерфейсів для OpenAPI (які можна використовувати з **FastAPI**). + +### Фреймворки REST для Flask + +Існує кілька фреймворків Flask REST, але, витративши час і роботу на їх дослідження, я виявив, що багато з них припинено або залишено, з кількома постійними проблемами, які зробили їх непридатними. + +### Marshmallow + +Однією з головних функцій, необхідних для систем API, є "серіалізація", яка бере дані з коду (Python) і перетворює їх на щось, що можна надіслати через мережу. Наприклад, перетворення об’єкта, що містить дані з бази даних, на об’єкт JSON. Перетворення об’єктів `datetime` на строки тощо. + +Іншою важливою функцією, необхідною для API, є перевірка даних, яка забезпечує дійсність даних за певними параметрами. Наприклад, що деяке поле є `int`, а не деяка випадкова строка. Це особливо корисно для вхідних даних. + +Без системи перевірки даних вам довелося б виконувати всі перевірки вручну, у коді. + +Marshmallow створено для забезпечення цих функцій. Це чудова бібліотека, і я часто нею користувався раніше. + +Але він був створений до того, як існували підказки типу Python. Отже, щоб визначити кожну схему, вам потрібно використовувати спеціальні утиліти та класи, надані Marshmallow. + +!!! Перегляньте "Надихнуло **FastAPI** на" + Використовувати код для автоматичного визначення "схем", які надають типи даних і перевірку. + +### Webargs + +Іншою важливою функцією, необхідною для API, є аналіз даних із вхідних запитів. + +Webargs — це інструмент, створений, щоб забезпечити це поверх кількох фреймворків, включаючи Flask. + +Він використовує Marshmallow в основі для перевірки даних. І створений тими ж розробниками. + +Це чудовий інструмент, і я також часто використовував його, перш ніж створити **FastAPI**. + +!!! Інформація + Webargs був створений тими ж розробниками Marshmallow. + +!!! Перегляньте "Надихнуло **FastAPI** на" + Мати автоматичну перевірку даних вхідного запиту. + +### APISpec + +Marshmallow і Webargs забезпечують перевірку, аналіз і серіалізацію як плагіни. + +Але документація досі відсутня. Потім було створено APISpec. + +Це плагін для багатьох фреймворків (також є плагін для Starlette). + +Принцип роботи полягає в тому, що ви пишете визначення схеми, використовуючи формат YAML, у docstring кожної функції, що обробляє маршрут. + +І він генерує схеми OpenAPI. + +Так це працює у Flask, Starlette, Responder тощо. + +Але потім ми знову маємо проблему наявності мікросинтаксису всередині Python строки (великий YAML). + +Редактор тут нічим не може допомогти. І якщо ми змінимо параметри чи схеми Marshmallow і забудемо також змінити цю строку документа YAML, згенерована схема буде застарілою. + +!!! Інформація + APISpec був створений тими ж розробниками Marshmallow. + + +!!! Перегляньте "Надихнуло **FastAPI** на" + Підтримувати відкритий стандарт API, OpenAPI. + +### Flask-apispec + +Це плагін Flask, який об’єднує Webargs, Marshmallow і APISpec. + +Він використовує інформацію з Webargs і Marshmallow для автоматичного створення схем OpenAPI за допомогою APISpec. + +Це чудовий інструмент, дуже недооцінений. Він має бути набагато популярнішим, ніж багато плагінів Flask. Це може бути пов’язано з тим, що його документація надто стисла й абстрактна. + +Це вирішило необхідність писати YAML (інший синтаксис) всередині рядків документів Python. + +Ця комбінація Flask, Flask-apispec із Marshmallow і Webargs була моїм улюбленим бекенд-стеком до створення **FastAPI**. + +Їі використання призвело до створення кількох генераторів повного стека Flask. Це основний стек, який я (та кілька зовнішніх команд) використовував досі: + +* https://github.com/tiangolo/full-stack +* https://github.com/tiangolo/full-stack-flask-couchbase +* https://github.com/tiangolo/full-stack-flask-couchdb + +І ці самі генератори повного стеку були основою [**FastAPI** генераторів проектів](project-generation.md){.internal-link target=_blank}. + +!!! Інформація + Flask-apispec був створений тими ж розробниками Marshmallow. + +!!! Перегляньте "Надихнуло **FastAPI** на" + Створення схеми OpenAPI автоматично з того самого коду, який визначає серіалізацію та перевірку. + +### NestJS (та Angular) + +Це навіть не Python, NestJS — це фреймворк NodeJS JavaScript (TypeScript), натхненний Angular. + +Це досягає чогось подібного до того, що можна зробити з Flask-apispec. + +Він має інтегровану систему впровадження залежностей, натхненну Angular two. Він потребує попередньої реєстрації «injectables» (як і всі інші системи впровадження залежностей, які я знаю), тому це збільшує багатослівність та повторення коду. + +Оскільки параметри описані за допомогою типів TypeScript (подібно до підказок типу Python), підтримка редактора досить хороша. + +Але оскільки дані TypeScript не зберігаються після компіляції в JavaScript, вони не можуть покладатися на типи для визначення перевірки, серіалізації та документації одночасно. Через це та деякі дизайнерські рішення, щоб отримати перевірку, серіалізацію та автоматичну генерацію схеми, потрібно додати декоратори в багатьох місцях. Таким чином код стає досить багатослівним. + +Він не дуже добре обробляє вкладені моделі. Отже, якщо тіло JSON у запиті є об’єктом JSON із внутрішніми полями, які, у свою чергу, є вкладеними об’єктами JSON, його неможливо належним чином задокументувати та перевірити. + +!!! Перегляньте "Надихнуло **FastAPI** на" + Використовувати типи Python, щоб мати чудову підтримку редактора. + + Мати потужну систему впровадження залежностей. Знайдіть спосіб звести до мінімуму повторення коду. + +### Sanic + +Це був один із перших надзвичайно швидких фреймворків Python на основі `asyncio`. Він був дуже схожий на Flask. + +!!! Примітка "Технічні деталі" + Він використовував `uvloop` замість стандартного циклу Python `asyncio`. Ось що зробило його таким швидким. + + Це явно надихнуло Uvicorn і Starlette, які зараз швидші за Sanic у відкритих тестах. + +!!! Перегляньте "Надихнуло **FastAPI** на" + Знайти спосіб отримати божевільну продуктивність. + + Ось чому **FastAPI** базується на Starlette, оскільки це найшвидша доступна структура (перевірена тестами сторонніх розробників). + +### Falcon + +Falcon — ще один високопродуктивний фреймворк Python, він розроблений як мінімальний і працює як основа інших фреймворків, таких як Hug. + +Він розроблений таким чином, щоб мати функції, які отримують два параметри, один «запит» і один «відповідь». Потім ви «читаєте» частини запиту та «записуєте» частини у відповідь. Через такий дизайн неможливо оголосити параметри запиту та тіла за допомогою стандартних підказок типу Python як параметри функції. + +Таким чином, перевірка даних, серіалізація та документація повинні виконуватися в коді, а не автоматично. Або вони повинні бути реалізовані як фреймворк поверх Falcon, як Hug. Така сама відмінність спостерігається в інших фреймворках, натхненних дизайном Falcon, що мають один об’єкт запиту та один об’єкт відповіді як параметри. + +!!! Перегляньте "Надихнуло **FastAPI** на" + Знайти способи отримати чудову продуктивність. + + Разом із Hug (оскільки Hug базується на Falcon) надихнув **FastAPI** оголосити параметр `response` у функціях. + + Хоча у FastAPI це необов’язково, і використовується в основному для встановлення заголовків, файлів cookie та альтернативних кодів стану. + +### Molten + +Я відкрив для себе Molten на перших етапах створення **FastAPI**. І він має досить схожі ідеї: + +* Базується на підказках типу Python. +* Перевірка та документація цих типів. +* Система впровадження залежностей. + +Він не використовує перевірку даних, серіалізацію та бібліотеку документації сторонніх розробників, як Pydantic, він має свою власну. Таким чином, ці визначення типів даних не можна було б використовувати повторно так легко. + +Це вимагає трохи більш докладних конфігурацій. І оскільки він заснований на WSGI (замість ASGI), він не призначений для використання високопродуктивних інструментів, таких як Uvicorn, Starlette і Sanic. + +Система впровадження залежностей вимагає попередньої реєстрації залежностей, і залежності вирішуються на основі оголошених типів. Отже, неможливо оголосити більше ніж один «компонент», який надає певний тип. + +Маршрути оголошуються в одному місці з використанням функцій, оголошених в інших місцях (замість використання декораторів, які можна розмістити безпосередньо поверх функції, яка обробляє кінцеву точку). Це ближче до того, як це робить Django, ніж до Flask (і Starlette). Він розділяє в коді речі, які відносно тісно пов’язані. + +!!! Перегляньте "Надихнуло **FastAPI** на" + Визначити додаткові перевірки для типів даних, використовуючи значення "за замовчуванням" атрибутів моделі. Це покращує підтримку редактора, а раніше вона була недоступна в Pydantic. + + Це фактично надихнуло оновити частини Pydantic, щоб підтримувати той самий стиль оголошення перевірки (всі ці функції вже доступні в Pydantic). + +### Hug + +Hug був одним із перших фреймворків, який реалізував оголошення типів параметрів API за допомогою підказок типу Python. Це була чудова ідея, яка надихнула інші інструменти зробити те саме. + +Він використовував спеціальні типи у своїх оголошеннях замість стандартних типів Python, але це все одно був величезний крок вперед. + +Це також був один із перших фреймворків, який генерував спеціальну схему, що оголошувала весь API у JSON. + +Він не базувався на таких стандартах, як OpenAPI та JSON Schema. Тому було б непросто інтегрувати його з іншими інструментами, як-от Swagger UI. Але знову ж таки, це була дуже інноваційна ідея. + +Він має цікаву незвичайну функцію: використовуючи ту саму структуру, можна створювати API, а також CLI. + +Оскільки він заснований на попередньому стандарті для синхронних веб-фреймворків Python (WSGI), він не може працювати з Websockets та іншими речами, хоча він також має високу продуктивність. + +!!! Інформація + Hug створив Тімоті Крослі, той самий творець `isort`, чудовий інструмент для автоматичного сортування імпорту у файлах Python. + +!!! Перегляньте "Надихнуло **FastAPI** на" + Hug надихнув частину APIStar і був одним із найбільш перспективних інструментів, поряд із APIStar. + + Hug надихнув **FastAPI** на використання підказок типу Python для оголошення параметрів і автоматичного створення схеми, що визначає API. + + Hug надихнув **FastAPI** оголосити параметр `response` у функціях для встановлення заголовків і файлів cookie. + +### APIStar (<= 0,5) + +Безпосередньо перед тим, як вирішити створити **FastAPI**, я знайшов сервер **APIStar**. Він мав майже все, що я шукав, і мав чудовий дизайн. + +Це була одна з перших реалізацій фреймворку, що використовує підказки типу Python для оголошення параметрів і запитів, яку я коли-небудь бачив (до NestJS і Molten). Я знайшов його більш-менш одночасно з Hug. Але APIStar використовував стандарт OpenAPI. + +Він мав автоматичну перевірку даних, серіалізацію даних і генерацію схеми OpenAPI на основі підказок того самого типу в кількох місцях. + +Визначення схеми тіла не використовували ті самі підказки типу Python, як Pydantic, воно було трохи схоже на Marshmallow, тому підтримка редактора була б не такою хорошою, але все ж APIStar був найкращим доступним варіантом. + +Він мав найкращі показники продуктивності на той час (перевершив лише Starlette). + +Спочатку він не мав автоматичного веб-інтерфейсу документації API, але я знав, що можу додати до нього інтерфейс користувача Swagger. + +Він мав систему введення залежностей. Він вимагав попередньої реєстрації компонентів, як і інші інструменти, розглянуті вище. Але все одно це була чудова функція. + +Я ніколи не міг використовувати його в повноцінному проекті, оскільки він не мав інтеграції безпеки, тому я не міг замінити всі функції, які мав, генераторами повного стеку на основі Flask-apispec. У моїх невиконаних проектах я мав створити запит на вилучення, додавши цю функцію. + +Але потім фокус проекту змінився. + +Це вже не був веб-фреймворк API, оскільки творцю потрібно було зосередитися на Starlette. + +Тепер APIStar — це набір інструментів для перевірки специфікацій OpenAPI, а не веб-фреймворк. + +!!! Інформація + APIStar створив Том Крісті. Той самий хлопець, який створив: + + * Django REST Framework + * Starlette (на якому базується **FastAPI**) + * Uvicorn (використовується Starlette і **FastAPI**) + +!!! Перегляньте "Надихнуло **FastAPI** на" + Існувати. + + Ідею оголошення кількох речей (перевірки даних, серіалізації та документації) за допомогою тих самих типів Python, які в той же час забезпечували чудову підтримку редактора, я вважав геніальною ідеєю. + + І після тривалого пошуку подібної структури та тестування багатьох різних альтернатив, APIStar став найкращим доступним варіантом. + + Потім APIStar перестав існувати як сервер, і було створено Starlette, який став новою кращою основою для такої системи. Це стало останнім джерелом натхнення для створення **FastAPI**. Я вважаю **FastAPI** «духовним спадкоємцем» APIStar, удосконалюючи та розширюючи функції, систему введення тексту та інші частини на основі досвіду, отриманого від усіх цих попередніх інструментів. + +## Використовується **FastAPI** + +### Pydantic + +Pydantic — це бібліотека для визначення перевірки даних, серіалізації та документації (за допомогою схеми JSON) на основі підказок типу Python. + +Це робить його надзвичайно інтуїтивним. + +Його можна порівняти з Marshmallow. Хоча він швидший за Marshmallow у тестах. Оскільки він базується на тих самих підказках типу Python, підтримка редактора чудова. + +!!! Перегляньте "**FastAPI** використовує його для" + Виконання перевірки всіх даних, серіалізації даних і автоматичної документацію моделі (на основі схеми JSON). + + Потім **FastAPI** бере ці дані схеми JSON і розміщує їх у OpenAPI, окремо від усіх інших речей, які він робить. + +### Starlette + +Starlette — це легкий фреймворк/набір інструментів ASGI, який ідеально підходить для створення високопродуктивних asyncio сервісів. + +Він дуже простий та інтуїтивно зрозумілий. Його розроблено таким чином, щоб його можна було легко розширювати та мати модульні компоненти. + +Він має: + +* Серйозно вражаючу продуктивність. +* Підтримку WebSocket. +* Фонові завдання в процесі. +* Події запуску та завершення роботи. +* Тестового клієнта, побудований на HTTPX. +* CORS, GZip, статичні файли, потокові відповіді. +* Підтримку сеансів і файлів cookie. +* 100% покриття тестом. +* 100% анотовану кодову базу. +* Кілька жорстких залежностей. + +Starlette наразі є найшвидшим фреймворком Python із перевірених. Перевершує лише Uvicorn, який є не фреймворком, а сервером. + +Starlette надає всі основні функції веб-мікрофреймворку. + +Але він не забезпечує автоматичної перевірки даних, серіалізації чи документації. + +Це одна з головних речей, які **FastAPI** додає зверху, все на основі підказок типу Python (з використанням Pydantic). Це, а також система впровадження залежностей, утиліти безпеки, створення схеми OpenAPI тощо. + +!!! Примітка "Технічні деталі" + ASGI — це новий «стандарт», який розробляється членами основної команди Django. Це ще не «стандарт Python» (PEP), хоча вони в процесі цього. + + Тим не менш, він уже використовується як «стандарт» кількома інструментами. Це значно покращує сумісність, оскільки ви можете переключити Uvicorn на будь-який інший сервер ASGI (наприклад, Daphne або Hypercorn), або ви можете додати інструменти, сумісні з ASGI, як-от `python-socketio`. + +!!! Перегляньте "**FastAPI** використовує його для" + Керування всіма основними веб-частинами. Додавання функцій зверху. + + Сам клас `FastAPI` безпосередньо успадковує клас `Starlette`. + + Отже, усе, що ви можете робити зі Starlette, ви можете робити це безпосередньо за допомогою **FastAPI**, оскільки це, по суті, Starlette на стероїдах. + +### Uvicorn + +Uvicorn — це блискавичний сервер ASGI, побудований на uvloop і httptools. + +Це не веб-фреймворк, а сервер. Наприклад, він не надає інструментів для маршрутизації. Це те, що фреймворк на кшталт Starlette (або **FastAPI**) забезпечить поверх нього. + +Це рекомендований сервер для Starlette і **FastAPI**. + +!!! Перегляньте "**FastAPI** рекомендує це як" + Основний веб-сервер для запуску програм **FastAPI**. + + Ви можете поєднати його з Gunicorn, щоб мати асинхронний багатопроцесний сервер. + + Додаткову інформацію див. у розділі [Розгортання](deployment/index.md){.internal-link target=_blank}. + +## Орієнтири та швидкість + +Щоб зрозуміти, порівняти та побачити різницю між Uvicorn, Starlette і FastAPI, перегляньте розділ про [Бенчмарки](benchmarks.md){.internal-link target=_blank}. From 4e93f8e0bc94f72adc79cf1517061f2a1bd17677 Mon Sep 17 00:00:00 2001 From: Ragul K <78537172+ragul-kachiappan@users.noreply.github.com> Date: Sat, 2 Sep 2023 21:02:48 +0530 Subject: [PATCH 24/54] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20typo=20in=20`d?= =?UTF-8?q?ocs/en/docs/tutorial/dependencies/dependencies-in-path-operatio?= =?UTF-8?q?n-decorators.md`=20(#10172)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- .../dependencies/dependencies-in-path-operation-decorators.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md index 935555339..ccef5aef4 100644 --- a/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md @@ -35,7 +35,7 @@ It should be a `list` of `Depends()`: {!> ../../../docs_src/dependencies/tutorial006.py!} ``` -These dependencies will be executed/solved the same way normal dependencies. But their value (if they return any) won't be passed to your *path operation function*. +These dependencies will be executed/solved the same way as normal dependencies. But their value (if they return any) won't be passed to your *path operation function*. !!! tip Some editors check for unused function parameters, and show them as errors. From 59cbeccac02cf66cbdc55fd1d7ec2675fa5e8e9e Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 15:36:34 +0000 Subject: [PATCH 25/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 09f19f0f6..a74499d88 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Ukrainian translation for `docs/uk/docs/alternatives.md`. PR [#10060](https://github.com/tiangolo/fastapi/pull/10060) by [@whysage](https://github.com/whysage). * 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/index.md`. PR [#10079](https://github.com/tiangolo/fastapi/pull/10079) by [@rostik1410](https://github.com/rostik1410). * ✏️ Fix typos in `docs/en/docs/how-to/separate-openapi-schemas.md` and `docs/en/docs/tutorial/schema-extra-example.md`. PR [#10189](https://github.com/tiangolo/fastapi/pull/10189) by [@xzmeng](https://github.com/xzmeng). * 🌐 Add Chinese translation for `docs/zh/docs/advanced/generate-clients.md`. PR [#9883](https://github.com/tiangolo/fastapi/pull/9883) by [@funny-cat-happy](https://github.com/funny-cat-happy). From 9fc33f8565be369ed7b40d8202a8cf4a49c951b6 Mon Sep 17 00:00:00 2001 From: Ahsan Sheraz Date: Sat, 2 Sep 2023 20:37:40 +0500 Subject: [PATCH 26/54] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20typos=20in=20c?= =?UTF-8?q?omment=20in=20`fastapi/applications.py`=20(#10045)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/applications.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index b681e50b3..5cc568292 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -189,20 +189,20 @@ class FastAPI(Starlette): # contextvars. # This needs to happen after user middlewares because those create a # new contextvars context copy by using a new AnyIO task group. - # The initial part of dependencies with yield is executed in the - # FastAPI code, inside all the middlewares, but the teardown part - # (after yield) is executed in the AsyncExitStack in this middleware, - # if the AsyncExitStack lived outside of the custom middlewares and - # contextvars were set in a dependency with yield in that internal + # The initial part of dependencies with 'yield' is executed in the + # FastAPI code, inside all the middlewares. However, the teardown part + # (after 'yield') is executed in the AsyncExitStack in this middleware. + # If the AsyncExitStack lived outside of the custom middlewares and + # contextvars were set in a dependency with 'yield' in that internal # contextvars context, the values would not be available in the - # outside context of the AsyncExitStack. - # By putting the middleware and the AsyncExitStack here, inside all - # user middlewares, the code before and after yield in dependencies - # with yield is executed in the same contextvars context, so all values - # set in contextvars before yield is still available after yield as - # would be expected. + # outer context of the AsyncExitStack. + # By placing the middleware and the AsyncExitStack here, inside all + # user middlewares, the code before and after 'yield' in dependencies + # with 'yield' is executed in the same contextvars context. Thus, all values + # set in contextvars before 'yield' are still available after 'yield,' as + # expected. # Additionally, by having this AsyncExitStack here, after the - # ExceptionMiddleware, now dependencies can catch handled exceptions, + # ExceptionMiddleware, dependencies can now catch handled exceptions, # e.g. HTTPException, to customize the teardown code (e.g. DB session # rollback). Middleware(AsyncExitStackMiddleware), From a55f3204ef2577045a0ab0585dd58c40686a2da2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 15:37:56 +0000 Subject: [PATCH 27/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index a74499d88..2a9ffc954 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix typo in `docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#10172](https://github.com/tiangolo/fastapi/pull/10172) by [@ragul-kachiappan](https://github.com/ragul-kachiappan). * 🌐 Add Ukrainian translation for `docs/uk/docs/alternatives.md`. PR [#10060](https://github.com/tiangolo/fastapi/pull/10060) by [@whysage](https://github.com/whysage). * 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/index.md`. PR [#10079](https://github.com/tiangolo/fastapi/pull/10079) by [@rostik1410](https://github.com/rostik1410). * ✏️ Fix typos in `docs/en/docs/how-to/separate-openapi-schemas.md` and `docs/en/docs/tutorial/schema-extra-example.md`. PR [#10189](https://github.com/tiangolo/fastapi/pull/10189) by [@xzmeng](https://github.com/xzmeng). From b2562c5c73440c992e2bd9a1ad07312f3358361f Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 15:41:53 +0000 Subject: [PATCH 28/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 2a9ffc954..8af275623 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix typos in comment in `fastapi/applications.py`. PR [#10045](https://github.com/tiangolo/fastapi/pull/10045) by [@AhsanSheraz](https://github.com/AhsanSheraz). * ✏️ Fix typo in `docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#10172](https://github.com/tiangolo/fastapi/pull/10172) by [@ragul-kachiappan](https://github.com/ragul-kachiappan). * 🌐 Add Ukrainian translation for `docs/uk/docs/alternatives.md`. PR [#10060](https://github.com/tiangolo/fastapi/pull/10060) by [@whysage](https://github.com/whysage). * 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/index.md`. PR [#10079](https://github.com/tiangolo/fastapi/pull/10079) by [@rostik1410](https://github.com/rostik1410). From 2e3295719814fdfb957c31d0720c578053c230fc Mon Sep 17 00:00:00 2001 From: Poupapaa <3238986+poupapaa@users.noreply.github.com> Date: Sat, 2 Sep 2023 22:43:16 +0700 Subject: [PATCH 29/54] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20typo=20in=20`d?= =?UTF-8?q?ocs/en/docs/tutorial/handling-errors.md`=20(#10170)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/handling-errors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/handling-errors.md b/docs/en/docs/tutorial/handling-errors.md index 8c30326ce..a03029e81 100644 --- a/docs/en/docs/tutorial/handling-errors.md +++ b/docs/en/docs/tutorial/handling-errors.md @@ -1,6 +1,6 @@ # Handling Errors -There are many situations in where you need to notify an error to a client that is using your API. +There are many situations in which you need to notify an error to a client that is using your API. This client could be a browser with a frontend, a code from someone else, an IoT device, etc. From 8979166bc308067951f5361df0cf85b0b73fb1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Kh=E1=BA=AFc=20Th=C3=A0nh?= Date: Sat, 2 Sep 2023 22:44:17 +0700 Subject: [PATCH 30/54] =?UTF-8?q?=F0=9F=8C=90=20Add=20Vietnamese=20transla?= =?UTF-8?q?tions=20for=20`docs/vi/docs/tutorial/first-steps.md`=20and=20`d?= =?UTF-8?q?ocs/vi/docs/tutorial/index.md`=20(#10088)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/vi/docs/tutorial/first-steps.md | 333 +++++++++++++++++++++++++++ docs/vi/docs/tutorial/index.md | 80 +++++++ 2 files changed, 413 insertions(+) create mode 100644 docs/vi/docs/tutorial/first-steps.md create mode 100644 docs/vi/docs/tutorial/index.md diff --git a/docs/vi/docs/tutorial/first-steps.md b/docs/vi/docs/tutorial/first-steps.md new file mode 100644 index 000000000..712f00852 --- /dev/null +++ b/docs/vi/docs/tutorial/first-steps.md @@ -0,0 +1,333 @@ +# Những bước đầu tiên + +Tệp tin FastAPI đơn giản nhất có thể trông như này: + +```Python +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Sao chép sang một tệp tin `main.py`. + +Chạy live server: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +!!! note + Câu lệnh `uvicorn main:app` được giải thích như sau: + + * `main`: tệp tin `main.py` (một Python "mô đun"). + * `app`: một object được tạo ra bên trong `main.py` với dòng `app = FastAPI()`. + * `--reload`: làm server khởi động lại sau mỗi lần thay đổi. Chỉ sử dụng trong môi trường phát triển. + +Trong output, có một dòng giống như: + +```hl_lines="4" +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +Dòng đó cho thấy URL, nơi mà app của bạn đang được chạy, trong máy local của bạn. + +### Kiểm tra + +Mở trình duyệt của bạn tại http://127.0.0.1:8000. + +Bạn sẽ thấy một JSON response như: + +```JSON +{"message": "Hello World"} +``` + +### Tài liệu tương tác API + +Bây giờ tới http://127.0.0.1:8000/docs. + +Bạn sẽ thấy một tài liệu tương tác API (cung cấp bởi Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Phiên bản thay thế của tài liệu API + +Và bây giờ tới http://127.0.0.1:8000/redoc. + +Bạn sẽ thấy một bản thay thế của tài liệu (cung cấp bởi ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +### OpenAPI + +**FastAPI** sinh một "schema" với tất cả API của bạn sử dụng tiêu chuẩn **OpenAPI** cho định nghĩa các API. + +#### "Schema" + +Một "schema" là một định nghĩa hoặc mô tả thứ gì đó. Không phải code triển khai của nó, nhưng chỉ là một bản mô tả trừu tượng. + +#### API "schema" + +Trong trường hợp này, OpenAPI là một bản mô tả bắt buộc cơ chế định nghĩa API của bạn. + +Định nghĩa cấu trúc này bao gồm những đường dẫn API của bạn, các tham số có thể có,... + +#### "Cấu trúc" dữ liệu + +Thuật ngữ "cấu trúc" (schema) cũng có thể được coi như là hình dạng của dữ liệu, tương tự như một JSON content. + +Trong trường hợp đó, nó có nghĩa là các thuộc tính JSON và các kiểu dữ liệu họ có,... + +#### OpenAPI và JSON Schema + +OpenAPI định nghĩa một cấu trúc API cho API của bạn. Và cấu trúc đó bao gồm các dịnh nghĩa (or "schema") về dữ liệu được gửi đi và nhận về bởi API của bạn, sử dụng **JSON Schema**, một tiêu chuẩn cho cấu trúc dữ liệu JSON. + +#### Kiểm tra `openapi.json` + +Nếu bạn tò mò về việc cấu trúc OpenAPI nhìn như thế nào thì FastAPI tự động sinh một JSON (schema) với các mô tả cho tất cả API của bạn. + +Bạn có thể thấy nó trực tiếp tại: http://127.0.0.1:8000/openapi.json. + +Nó sẽ cho thấy một JSON bắt đầu giống như: + +```JSON +{ + "openapi": "3.1.0", + "info": { + "title": "FastAPI", + "version": "0.1.0" + }, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + + + +... +``` + +#### OpenAPI dùng để làm gì? + +Cấu trúc OpenAPI là sức mạnh của tài liệu tương tác. + +Và có hàng tá các bản thay thế, tất cả đều dựa trên OpenAPI. Bạn có thể dễ dàng thêm bất kì bản thay thế bào cho ứng dụng của bạn được xây dựng với **FastAPI**. + +Bạn cũng có thể sử dụng nó để sinh code tự động, với các client giao viết qua API của bạn. Ví dụ, frontend, mobile hoặc các ứng dụng IoT. + +## Tóm lại, từng bước một + +### Bước 1: import `FastAPI` + +```Python hl_lines="1" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +`FastAPI` là một Python class cung cấp tất cả chức năng cho API của bạn. + +!!! note "Chi tiết kĩ thuật" + `FastAPI` là một class kế thừa trực tiếp `Starlette`. + + Bạn cũng có thể sử dụng tất cả Starlette chức năng với `FastAPI`. + +### Bước 2: Tạo một `FastAPI` "instance" + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Biến `app` này là một "instance" của class `FastAPI`. + +Đây sẽ là điểm cốt lõi để tạo ra tất cả API của bạn. + +`app` này chính là điều được nhắc tới bởi `uvicorn` trong câu lệnh: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Nếu bạn tạo ứng dụng của bạn giống như: + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial002.py!} +``` + +Và đặt nó trong một tệp tin `main.py`, sau đó bạn sẽ gọi `uvicorn` giống như: + +
+ +```console +$ uvicorn main:my_awesome_api --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +### Bước 3: tạo một *đường dẫn toán tử* + +#### Đường dẫn + +"Đường dẫn" ở đây được nhắc tới là phần cuối cùng của URL bắt đầu từ `/`. + +Do đó, trong một URL nhìn giống như: + +``` +https://example.com/items/foo +``` + +...đường dẫn sẽ là: + +``` +/items/foo +``` + +!!! info + Một đường dẫn cũng là một cách gọi chung cho một "endpoint" hoặc một "route". + +Trong khi xây dựng một API, "đường dẫn" là các chính để phân tách "mối quan hệ" và "tài nguyên". + +#### Toán tử (Operation) + +"Toán tử" ở đây được nhắc tới là một trong các "phương thức" HTTP. + +Một trong những: + +* `POST` +* `GET` +* `PUT` +* `DELETE` + +...và một trong những cái còn lại: + +* `OPTIONS` +* `HEAD` +* `PATCH` +* `TRACE` + +Trong giao thức HTTP, bạn có thể giao tiếp trong mỗi đường dẫn sử dụng một (hoặc nhiều) trong các "phương thức này". + +--- + +Khi xây dựng các API, bạn thường sử dụng cụ thể các phương thức HTTP này để thực hiện một hành động cụ thể. + +Thông thường, bạn sử dụng + +* `POST`: để tạo dữ liệu. +* `GET`: để đọc dữ liệu. +* `PUT`: để cập nhật dữ liệu. +* `DELETE`: để xóa dữ liệu. + +Do đó, trong OpenAPI, mỗi phương thức HTTP được gọi là một "toán tử (operation)". + +Chúng ta cũng sẽ gọi chúng là "**các toán tử**". + +#### Định nghĩa moojt *decorator cho đường dẫn toán tử* + +```Python hl_lines="6" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +`@app.get("/")` nói **FastAPI** rằng hàm bên dưới có trách nhiệm xử lí request tới: + +* đường dẫn `/` +* sử dụng một toán tửget + +!!! info Thông tin về "`@decorator`" + Cú pháp `@something` trong Python được gọi là một "decorator". + + Bạn đặt nó trên một hàm. Giống như một chiếc mũ xinh xắn (Tôi ddonas đó là lí do mà thuật ngữ này ra đời). + + Một "decorator" lấy một hàm bên dưới và thực hiện một vài thứ với nó. + + Trong trường hợp của chúng ta, decorator này nói **FastAPI** rằng hàm bên dưới ứng với **đường dẫn** `/` và một **toán tử** `get`. + + Nó là một "**decorator đường dẫn toán tử**". + +Bạn cũng có thể sử dụng với các toán tử khác: + +* `@app.post()` +* `@app.put()` +* `@app.delete()` + +Và nhiều hơn với các toán tử còn lại: + +* `@app.options()` +* `@app.head()` +* `@app.patch()` +* `@app.trace()` + +!!! tip + Bạn thoải mái sử dụng mỗi toán tử (phương thức HTTP) như bạn mơ ước. + + **FastAPI** không bắt buộc bất kì ý nghĩa cụ thể nào. + + Thông tin ở đây được biểu thị như là một chỉ dẫn, không phải là một yêu cầu bắt buộc. + + Ví dụ, khi sử dụng GraphQL bạn thông thường thực hiện tất cả các hành động chỉ bằng việc sử dụng các toán tử `POST`. + +### Step 4: Định nghĩa **hàm cho đường dẫn toán tử** + +Đây là "**hàm cho đường dẫn toán tử**": + +* **đường dẫn**: là `/`. +* **toán tử**: là `get`. +* **hàm**: là hàm bên dưới "decorator" (bên dưới `@app.get("/")`). + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Đây là một hàm Python. + +Nó sẽ được gọi bởi **FastAPI** bất cứ khi nào nó nhận một request tới URL "`/`" sử dụng một toán tử `GET`. + +Trong trường hợp này, nó là một hàm `async`. + +--- + +Bạn cũng có thể định nghĩa nó như là một hàm thông thường thay cho `async def`: + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial003.py!} +``` + +!!! note + Nếu bạn không biết sự khác nhau, kiểm tra [Async: *"Trong khi vội vàng?"*](../async.md#in-a-hurry){.internal-link target=_blank}. + +### Bước 5: Nội dung trả về + +```Python hl_lines="8" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Bạn có thể trả về một `dict`, `list`, một trong những giá trị đơn như `str`, `int`,... + +Bạn cũng có thể trả về Pydantic model (bạn sẽ thấy nhiều hơn về nó sau). + +Có nhiều object và model khác nhau sẽ được tự động chuyển đổi sang JSON (bao gồm cả ORM,...). Thử sử dụng loại ưa thích của bạn, nó có khả năng cao đã được hỗ trợ. + +## Tóm lại + +* Import `FastAPI`. +* Tạo một `app` instance. +* Viết một **decorator cho đường dẫn toán tử** (giống như `@app.get("/")`). +* Viết một **hàm cho đường dẫn toán tử** (giống như `def root(): ...` ở trên). +* Chạy server trong môi trường phát triển (giống như `uvicorn main:app --reload`). diff --git a/docs/vi/docs/tutorial/index.md b/docs/vi/docs/tutorial/index.md new file mode 100644 index 000000000..e8a93fe40 --- /dev/null +++ b/docs/vi/docs/tutorial/index.md @@ -0,0 +1,80 @@ +# Hướng dẫn sử dụng + +Hướng dẫn này cho bạn thấy từng bước cách sử dụng **FastAPI** đa số các tính năng của nó. + +Mỗi phần được xây dựng từ những phần trước đó, nhưng nó được cấu trúc thành các chủ đề riêng biệt, do đó bạn có thể xem trực tiếp từng phần cụ thể bất kì để giải quyết những API cụ thể mà bạn cần. + +Nó cũng được xây dựng để làm việc như một tham chiếu trong tương lai. + +Do đó bạn có thể quay lại và tìm chính xác những gì bạn cần. + +## Chạy mã + +Tất cả các code block có thể được sao chép và sử dụng trực tiếp (chúng thực chất là các tệp tin Python đã được kiểm thử). + +Để chạy bất kì ví dụ nào, sao chép code tới tệp tin `main.py`, và bắt đầu `uvicorn` với: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +**Khuyến khích** bạn viết hoặc sao chép code, sửa và chạy nó ở local. + +Sử dụng nó trong trình soạn thảo của bạn thực sự cho bạn thấy những lợi ích của FastAPI, thấy được cách bạn viết code ít hơn, tất cả đều được type check, autocompletion,... + +--- + +## Cài đặt FastAPI + +Bước đầu tiên là cài đặt FastAPI. + +Với hướng dẫn này, bạn có thể muốn cài đặt nó với tất cả các phụ thuộc và tính năng tùy chọn: + +
+ +```console +$ pip install "fastapi[all]" + +---> 100% +``` + +
+ +...dó cũng bao gồm `uvicorn`, bạn có thể sử dụng như một server để chạy code của bạn. + +!!! note + Bạn cũng có thể cài đặt nó từng phần. + + Đây là những gì bạn có thể sẽ làm một lần duy nhất bạn muốn triển khai ứng dụng của bạn lên production: + + ``` + pip install fastapi + ``` + + Cũng cài đặt `uvicorn` để làm việc như một server: + + ``` + pip install "uvicorn[standard]" + ``` + + Và tương tự với từng phụ thuộc tùy chọn mà bạn muốn sử dụng. + +## Hướng dẫn nâng cao + +Cũng có một **Hướng dẫn nâng cao** mà bạn có thể đọc nó sau **Hướng dẫn sử dụng**. + +**Hướng dẫn sử dụng nâng cao**, xây dựng dựa trên cái này, sử dụng các khái niệm tương tự, và dạy bạn những tính năng mở rộng. + +Nhưng bạn nên đọc **Hướng dẫn sử dụng** đầu tiên (những gì bạn đang đọc). + +Nó được thiết kế do đó bạn có thể xây dựng một ứng dụng hoàn chỉnh chỉ với **Hướng dẫn sử dụng**, và sau đó mở rộng nó theo các cách khác nhau, phụ thuộc vào những gì bạn cần, sử dụng một vài ý tưởng bổ sung từ **Hướng dẫn sử dụng nâng cao**. From e6c4785959609097631fa37f393cd9f977377dfa Mon Sep 17 00:00:00 2001 From: Rostyslav Date: Sat, 2 Sep 2023 18:48:03 +0300 Subject: [PATCH 31/54] =?UTF-8?q?=F0=9F=8C=90=20Add=20Ukrainian=20translat?= =?UTF-8?q?ion=20for=20`docs/uk/docs/python-types.md`=20(#10080)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/uk/docs/python-types.md | 448 +++++++++++++++++++++++++++++++++++ 1 file changed, 448 insertions(+) create mode 100644 docs/uk/docs/python-types.md diff --git a/docs/uk/docs/python-types.md b/docs/uk/docs/python-types.md new file mode 100644 index 000000000..f792e83a8 --- /dev/null +++ b/docs/uk/docs/python-types.md @@ -0,0 +1,448 @@ +# Вступ до типів Python + +Python підтримує додаткові "підказки типу" ("type hints") (також звані "анотаціями типу" ("type annotations")). + +Ці **"type hints"** є спеціальним синтаксисом, що дозволяє оголошувати тип змінної. + +За допомогою оголошення типів для ваших змінних, редактори та інструменти можуть надати вам кращу підтримку. + +Це просто **швидкий посібник / нагадування** про анотації типів у Python. Він покриває лише мінімум, необхідний щоб використовувати їх з **FastAPI**... що насправді дуже мало. + +**FastAPI** повністю базується на цих анотаціях типів, вони дають йому багато переваг. + +Але навіть якщо ви ніколи не використаєте **FastAPI**, вам буде корисно дізнатись трохи про них. + +!!! note + Якщо ви експерт у Python і ви вже знаєте усе про анотації типів - перейдіть до наступного розділу. + +## Мотивація + +Давайте почнемо з простого прикладу: + +```Python +{!../../../docs_src/python_types/tutorial001.py!} +``` + +Виклик цієї програми виводить: + +``` +John Doe +``` + +Функція виконує наступне: + +* Бере `first_name` та `last_name`. +* Конвертує кожну літеру кожного слова у верхній регістр за допомогою `title()`. +* Конкатенує їх разом із пробілом по середині. + +```Python hl_lines="2" +{!../../../docs_src/python_types/tutorial001.py!} +``` + +### Редагуйте це + +Це дуже проста програма. + +Але тепер уявіть, що ви писали це з нуля. + +У певний момент ви розпочали б визначення функції, у вас були б готові параметри... + +Але тоді вам потрібно викликати "той метод, який переводить першу літеру у верхній регістр". + +Це буде `upper`? Чи `uppercase`? `first_uppercase`? `capitalize`? + +Тоді ви спробуєте давнього друга програміста - автозаповнення редактора коду. + +Ви надрукуєте перший параметр функції, `first_name`, тоді крапку (`.`), а тоді натиснете `Ctrl+Space`, щоб запустити автозаповнення. + +Але, на жаль, ви не отримаєте нічого корисного: + + + +### Додайте типи + +Давайте змінимо один рядок з попередньої версії. + +Ми змінимо саме цей фрагмент, параметри функції, з: + +```Python + first_name, last_name +``` + +на: + +```Python + first_name: str, last_name: str +``` + +Ось і все. + +Це "type hints": + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial002.py!} +``` + +Це не те саме, що оголошення значень за замовчуванням, як це було б з: + +```Python + first_name="john", last_name="doe" +``` + +Це зовсім інше. + +Ми використовуємо двокрапку (`:`), не дорівнює (`=`). + +І додавання анотації типу зазвичай не змінює того, що сталось би без них. + +Але тепер, уявіть що ви посеред процесу створення функції, але з анотаціями типів. + +В цей же момент, ви спробуєте викликати автозаповнення з допомогою `Ctrl+Space` і побачите: + + + +Разом з цим, ви можете прокручувати, переглядати опції, допоки ви не знайдете одну, що звучить схоже: + + + +## Більше мотивації + +Перевірте цю функцію, вона вже має анотацію типу: + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial003.py!} +``` + +Оскільки редактор знає типи змінних, ви не тільки отримаєте автозаповнення, ви також отримаєте перевірку помилок: + + + +Тепер ви знаєте, щоб виправити це, вам потрібно перетворити `age` у строку з допомогою `str(age)`: + +```Python hl_lines="2" +{!../../../docs_src/python_types/tutorial004.py!} +``` + +## Оголошення типів + +Щойно ви побачили основне місце для оголошення анотацій типу. Як параметри функції. + +Це також основне місце, де ви б їх використовували у **FastAPI**. + +### Прості типи + +Ви можете оголошувати усі стандартні типи у Python, не тільки `str`. + +Ви можете використовувати, наприклад: + +* `int` +* `float` +* `bool` +* `bytes` + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial005.py!} +``` + +### Generic-типи з параметрами типів + +Існують деякі структури даних, які можуть містити інші значення, наприклад `dict`, `list`, `set` та `tuple`. І внутрішні значення також можуть мати свій тип. + +Ці типи, які мають внутрішні типи, називаються "**generic**" типами. І оголосити їх можна навіть із внутрішніми типами. + +Щоб оголосити ці типи та внутрішні типи, ви можете використовувати стандартний модуль Python `typing`. Він існує спеціально для підтримки анотацій типів. + +#### Новіші версії Python + +Синтаксис із використанням `typing` **сумісний** з усіма версіями, від Python 3.6 до останніх, включаючи Python 3.9, Python 3.10 тощо. + +У міру розвитку Python **новіші версії** мають покращену підтримку анотацій типів і в багатьох випадках вам навіть не потрібно буде імпортувати та використовувати модуль `typing` для оголошення анотацій типу. + +Якщо ви можете вибрати новішу версію Python для свого проекту, ви зможете скористатися цією додатковою простотою. Дивіться кілька прикладів нижче. + +#### List (список) + +Наприклад, давайте визначимо змінну, яка буде `list` із `str`. + +=== "Python 3.6 і вище" + + З модуля `typing`, імпортуємо `List` (з великої літери `L`): + + ``` Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial006.py!} + ``` + + Оголосимо змінну з тим самим синтаксисом двокрапки (`:`). + + Як тип вкажемо `List`, який ви імпортували з `typing`. + + Оскільки список є типом, який містить деякі внутрішні типи, ви поміщаєте їх у квадратні дужки: + + ```Python hl_lines="4" + {!> ../../../docs_src/python_types/tutorial006.py!} + ``` + +=== "Python 3.9 і вище" + + Оголосимо змінну з тим самим синтаксисом двокрапки (`:`). + + Як тип вкажемо `list`. + + Оскільки список є типом, який містить деякі внутрішні типи, ви поміщаєте їх у квадратні дужки: + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial006_py39.py!} + ``` + +!!! info + Ці внутрішні типи в квадратних дужках називаються "параметрами типу". + + У цьому випадку, `str` це параметр типу переданий у `List` (або `list` у Python 3.9 і вище). + +Це означає: "змінна `items` це `list`, і кожен з елементів у цьому списку - `str`". + +!!! tip + Якщо ви використовуєте Python 3.9 і вище, вам не потрібно імпортувати `List` з `typing`, ви можете використовувати натомість тип `list`. + +Зробивши це, ваш редактор може надати підтримку навіть під час обробки елементів зі списку: + + + +Без типів цього майже неможливо досягти. + +Зверніть увагу, що змінна `item` є одним із елементів у списку `items`. + +І все ж редактор знає, що це `str`, і надає підтримку для цього. + +#### Tuple and Set (кортеж та набір) + +Ви повинні зробити те ж саме, щоб оголосити `tuple` і `set`: + +=== "Python 3.6 і вище" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial007.py!} + ``` + +=== "Python 3.9 і вище" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial007_py39.py!} + ``` + +Це означає: + +* Змінна `items_t` це `tuple` з 3 елементами, `int`, ще `int`, та `str`. +* Змінна `items_s` це `set`, і кожен його елемент типу `bytes`. + +#### Dict (словник) + +Щоб оголосити `dict`, вам потрібно передати 2 параметри типу, розділені комами. + +Перший параметр типу для ключа у `dict`. + +Другий параметр типу для значення у `dict`: + +=== "Python 3.6 і вище" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial008.py!} + ``` + +=== "Python 3.9 і вище" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial008_py39.py!} + ``` + +Це означає: + +* Змінна `prices` це `dict`: + * Ключі цього `dict` типу `str` (наприклад, назва кожного елементу). + * Значення цього `dict` типу `float` (наприклад, ціна кожного елементу). + +#### Union (об'єднання) + +Ви можете оголосити, що змінна може бути будь-яким із **кількох типів**, наприклад, `int` або `str`. + +У Python 3.6 і вище (включаючи Python 3.10) ви можете використовувати тип `Union` з `typing` і вставляти в квадратні дужки можливі типи, які можна прийняти. + +У Python 3.10 також є **альтернативний синтаксис**, у якому ви можете розділити можливі типи за допомогою вертикальної смуги (`|`). + +=== "Python 3.6 і вище" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial008b.py!} + ``` + +=== "Python 3.10 і вище" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial008b_py310.py!} + ``` + +В обох випадках це означає, що `item` може бути `int` або `str`. + +#### Possibly `None` (Optional) + +Ви можете оголосити, що значення може мати тип, наприклад `str`, але також може бути `None`. + +У Python 3.6 і вище (включаючи Python 3.10) ви можете оголосити його, імпортувавши та використовуючи `Optional` з модуля `typing`. + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial009.py!} +``` + +Використання `Optional[str]` замість просто `str` дозволить редактору допомогти вам виявити помилки, коли ви могли б вважати, що значенням завжди є `str`, хоча насправді воно також може бути `None`. + +`Optional[Something]` насправді є скороченням для `Union[Something, None]`, вони еквівалентні. + +Це також означає, що в Python 3.10 ви можете використовувати `Something | None`: + +=== "Python 3.6 і вище" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial009.py!} + ``` + +=== "Python 3.6 і вище - альтернатива" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial009b.py!} + ``` + +=== "Python 3.10 і вище" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial009_py310.py!} + ``` + +#### Generic типи + +Ці типи, які приймають параметри типу у квадратних дужках, називаються **Generic types** or **Generics**, наприклад: + +=== "Python 3.6 і вище" + + * `List` + * `Tuple` + * `Set` + * `Dict` + * `Union` + * `Optional` + * ...та інші. + +=== "Python 3.9 і вище" + + Ви можете використовувати ті самі вбудовані типи, як generic (з квадратними дужками та типами всередині): + + * `list` + * `tuple` + * `set` + * `dict` + + І те саме, що й у Python 3.6, із модуля `typing`: + + * `Union` + * `Optional` + * ...та інші. + +=== "Python 3.10 і вище" + + Ви можете використовувати ті самі вбудовані типи, як generic (з квадратними дужками та типами всередині): + + * `list` + * `tuple` + * `set` + * `dict` + + І те саме, що й у Python 3.6, із модуля `typing`: + + * `Union` + * `Optional` (так само як у Python 3.6) + * ...та інші. + + У Python 3.10, як альтернатива використанню `Union` та `Optional`, ви можете використовувати вертикальну смугу (`|`) щоб оголосити об'єднання типів. + +### Класи як типи + +Ви також можете оголосити клас як тип змінної. + +Скажімо, у вас є клас `Person` з імʼям: + +```Python hl_lines="1-3" +{!../../../docs_src/python_types/tutorial010.py!} +``` + +Потім ви можете оголосити змінну типу `Person`: + +```Python hl_lines="6" +{!../../../docs_src/python_types/tutorial010.py!} +``` + +І знову ж таки, ви отримуєте всю підтримку редактора: + + + +## Pydantic моделі + +Pydantic це бібліотека Python для валідації даних. + +Ви оголошуєте «форму» даних як класи з атрибутами. + +І кожен атрибут має тип. + +Потім ви створюєте екземпляр цього класу з деякими значеннями, і він перевірить ці значення, перетворить їх у відповідний тип (якщо є потреба) і надасть вам об’єкт з усіма даними. + +І ви отримуєте всю підтримку редактора з цим отриманим об’єктом. + +Приклад з документації Pydantic: + +=== "Python 3.6 і вище" + + ```Python + {!> ../../../docs_src/python_types/tutorial011.py!} + ``` + +=== "Python 3.9 і вище" + + ```Python + {!> ../../../docs_src/python_types/tutorial011_py39.py!} + ``` + +=== "Python 3.10 і вище" + + ```Python + {!> ../../../docs_src/python_types/tutorial011_py310.py!} + ``` + +!!! info + Щоб дізнатись більше про Pydantic, перегляньте його документацію. + +**FastAPI** повністю базується на Pydantic. + +Ви побачите набагато більше цього всього на практиці в [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}. + +## Анотації типів у **FastAPI** + +**FastAPI** використовує ці підказки для виконання кількох речей. + +З **FastAPI** ви оголошуєте параметри з підказками типу, і отримуєте: + +* **Підтримку редактора**. +* **Перевірку типів**. + +...і **FastAPI** використовує ті самі оголошення для: + +* **Визначення вимог**: з параметрів шляху запиту, параметрів запиту, заголовків, тіл, залежностей тощо. +* **Перетворення даних**: із запиту в необхідний тип. +* **Перевірка даних**: що надходять від кожного запиту: + * Генерування **автоматичних помилок**, що повертаються клієнту, коли дані недійсні. +* **Документування** API за допомогою OpenAPI: + * який потім використовується для автоматичної інтерактивної документації користувальницьких інтерфейсів. + +Все це може здатися абстрактним. Не хвилюйтеся. Ви побачите все це в дії в [Туторіал - Посібник користувача](tutorial/index.md){.internal-link target=_blank}. + +Важливо те, що за допомогою стандартних типів Python в одному місці (замість того, щоб додавати більше класів, декораторів тощо), **FastAPI** зробить багато роботи за вас. + +!!! info + Якщо ви вже пройшли весь навчальний посібник і повернулися, щоб дізнатися більше про типи, ось хороший ресурс "шпаргалка" від `mypy`. From 1866abffc1485bd09971d3c6f4a98fcfe4d96b0a Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 15:49:31 +0000 Subject: [PATCH 32/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 8af275623..44143af63 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix typo in `docs/en/docs/tutorial/handling-errors.md`. PR [#10170](https://github.com/tiangolo/fastapi/pull/10170) by [@poupapaa](https://github.com/poupapaa). * ✏️ Fix typos in comment in `fastapi/applications.py`. PR [#10045](https://github.com/tiangolo/fastapi/pull/10045) by [@AhsanSheraz](https://github.com/AhsanSheraz). * ✏️ Fix typo in `docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#10172](https://github.com/tiangolo/fastapi/pull/10172) by [@ragul-kachiappan](https://github.com/ragul-kachiappan). * 🌐 Add Ukrainian translation for `docs/uk/docs/alternatives.md`. PR [#10060](https://github.com/tiangolo/fastapi/pull/10060) by [@whysage](https://github.com/whysage). From 28bf4abf1fd81a6a930cca415604ebfa90898727 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 15:50:11 +0000 Subject: [PATCH 33/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 44143af63..57fea97ef 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Vietnamese translations for `docs/vi/docs/tutorial/first-steps.md` and `docs/vi/docs/tutorial/index.md`. PR [#10088](https://github.com/tiangolo/fastapi/pull/10088) by [@magiskboy](https://github.com/magiskboy). * ✏️ Fix typo in `docs/en/docs/tutorial/handling-errors.md`. PR [#10170](https://github.com/tiangolo/fastapi/pull/10170) by [@poupapaa](https://github.com/poupapaa). * ✏️ Fix typos in comment in `fastapi/applications.py`. PR [#10045](https://github.com/tiangolo/fastapi/pull/10045) by [@AhsanSheraz](https://github.com/AhsanSheraz). * ✏️ Fix typo in `docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#10172](https://github.com/tiangolo/fastapi/pull/10172) by [@ragul-kachiappan](https://github.com/ragul-kachiappan). From 7fe952f52255ebc2eef151fa9bb6c3a6f9d30909 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 15:54:22 +0000 Subject: [PATCH 34/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 57fea97ef..7861a35ab 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Ukrainian translation for `docs/uk/docs/python-types.md`. PR [#10080](https://github.com/tiangolo/fastapi/pull/10080) by [@rostik1410](https://github.com/rostik1410). * 🌐 Add Vietnamese translations for `docs/vi/docs/tutorial/first-steps.md` and `docs/vi/docs/tutorial/index.md`. PR [#10088](https://github.com/tiangolo/fastapi/pull/10088) by [@magiskboy](https://github.com/magiskboy). * ✏️ Fix typo in `docs/en/docs/tutorial/handling-errors.md`. PR [#10170](https://github.com/tiangolo/fastapi/pull/10170) by [@poupapaa](https://github.com/poupapaa). * ✏️ Fix typos in comment in `fastapi/applications.py`. PR [#10045](https://github.com/tiangolo/fastapi/pull/10045) by [@AhsanSheraz](https://github.com/AhsanSheraz). From 0ea23e2a8de9aad5c675f02f3ec54b9dd756a877 Mon Sep 17 00:00:00 2001 From: Hasnat Sajid <86589885+hasnatsajid@users.noreply.github.com> Date: Sat, 2 Sep 2023 20:55:41 +0500 Subject: [PATCH 35/54] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20link=20to=20Py?= =?UTF-8?q?dantic=20docs=20in=20`docs/en/docs/tutorial/extra-data-types.md?= =?UTF-8?q?`=20(#10155)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/tutorial/extra-data-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/extra-data-types.md b/docs/en/docs/tutorial/extra-data-types.md index 7d6ffbc78..b34ccd26f 100644 --- a/docs/en/docs/tutorial/extra-data-types.md +++ b/docs/en/docs/tutorial/extra-data-types.md @@ -49,7 +49,7 @@ Here are some of the additional data types you can use: * `Decimal`: * Standard Python `Decimal`. * In requests and responses, handled the same as a `float`. -* You can check all the valid pydantic data types here: Pydantic data types. +* You can check all the valid pydantic data types here: Pydantic data types. ## Example From 0242ca756670e66aeb534054c9251176f08876bd Mon Sep 17 00:00:00 2001 From: Rahul Salgare Date: Sat, 2 Sep 2023 21:26:35 +0530 Subject: [PATCH 36/54] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20Pydantic=20exa?= =?UTF-8?q?mples=20in=20tutorial=20for=20Python=20types=20(#9961)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs_src/python_types/tutorial011.py | 2 +- docs_src/python_types/tutorial011_py310.py | 2 +- docs_src/python_types/tutorial011_py39.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs_src/python_types/tutorial011.py b/docs_src/python_types/tutorial011.py index c8634cbff..297a84db6 100644 --- a/docs_src/python_types/tutorial011.py +++ b/docs_src/python_types/tutorial011.py @@ -6,7 +6,7 @@ from pydantic import BaseModel class User(BaseModel): id: int - name = "John Doe" + name: str = "John Doe" signup_ts: Union[datetime, None] = None friends: List[int] = [] diff --git a/docs_src/python_types/tutorial011_py310.py b/docs_src/python_types/tutorial011_py310.py index 7f173880f..842760c60 100644 --- a/docs_src/python_types/tutorial011_py310.py +++ b/docs_src/python_types/tutorial011_py310.py @@ -5,7 +5,7 @@ from pydantic import BaseModel class User(BaseModel): id: int - name = "John Doe" + name: str = "John Doe" signup_ts: datetime | None = None friends: list[int] = [] diff --git a/docs_src/python_types/tutorial011_py39.py b/docs_src/python_types/tutorial011_py39.py index 468496f51..4eb40b405 100644 --- a/docs_src/python_types/tutorial011_py39.py +++ b/docs_src/python_types/tutorial011_py39.py @@ -6,7 +6,7 @@ from pydantic import BaseModel class User(BaseModel): id: int - name = "John Doe" + name: str = "John Doe" signup_ts: Union[datetime, None] = None friends: list[int] = [] From aa43afa4c0aeba4615d3fde9ac96abf7a1a2e08a Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 16:00:21 +0000 Subject: [PATCH 37/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 7861a35ab..c540d2426 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix link to Pydantic docs in `docs/en/docs/tutorial/extra-data-types.md`. PR [#10155](https://github.com/tiangolo/fastapi/pull/10155) by [@hasnatsajid](https://github.com/hasnatsajid). * 🌐 Add Ukrainian translation for `docs/uk/docs/python-types.md`. PR [#10080](https://github.com/tiangolo/fastapi/pull/10080) by [@rostik1410](https://github.com/rostik1410). * 🌐 Add Vietnamese translations for `docs/vi/docs/tutorial/first-steps.md` and `docs/vi/docs/tutorial/index.md`. PR [#10088](https://github.com/tiangolo/fastapi/pull/10088) by [@magiskboy](https://github.com/magiskboy). * ✏️ Fix typo in `docs/en/docs/tutorial/handling-errors.md`. PR [#10170](https://github.com/tiangolo/fastapi/pull/10170) by [@poupapaa](https://github.com/poupapaa). From 34028290f5386011f4638ea4e36f1619d60b9b0c Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 16:03:22 +0000 Subject: [PATCH 38/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c540d2426..622f6ddc5 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix Pydantic examples in tutorial for Python types. PR [#9961](https://github.com/tiangolo/fastapi/pull/9961) by [@rahulsalgare](https://github.com/rahulsalgare). * ✏️ Fix link to Pydantic docs in `docs/en/docs/tutorial/extra-data-types.md`. PR [#10155](https://github.com/tiangolo/fastapi/pull/10155) by [@hasnatsajid](https://github.com/hasnatsajid). * 🌐 Add Ukrainian translation for `docs/uk/docs/python-types.md`. PR [#10080](https://github.com/tiangolo/fastapi/pull/10080) by [@rostik1410](https://github.com/rostik1410). * 🌐 Add Vietnamese translations for `docs/vi/docs/tutorial/first-steps.md` and `docs/vi/docs/tutorial/index.md`. PR [#10088](https://github.com/tiangolo/fastapi/pull/10088) by [@magiskboy](https://github.com/magiskboy). From 1711c1e95f3eec71c9d29050c9901137117b54aa Mon Sep 17 00:00:00 2001 From: Olaoluwa Afolabi Date: Sat, 2 Sep 2023 17:12:44 +0100 Subject: [PATCH 39/54] =?UTF-8?q?=F0=9F=8C=90=20Add=20Yoruba=20translation?= =?UTF-8?q?=20for=20`docs/yo/docs/index.md`=20(#10033)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/en/mkdocs.yml | 3 + docs/yo/docs/index.md | 470 ++++++++++++++++++++++++++++++++++++++++++ docs/yo/mkdocs.yml | 1 + 3 files changed, 474 insertions(+) create mode 100644 docs/yo/docs/index.md create mode 100644 docs/yo/mkdocs.yml diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index c56e4c942..ba1ac7924 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -72,6 +72,7 @@ nav: - uk: /uk/ - ur: /ur/ - vi: /vi/ + - yo: /yo/ - zh: /zh/ - features.md - fastapi-people.md @@ -261,6 +262,8 @@ extra: name: ur - link: /vi/ name: vi - Tiếng Việt + - link: /yo/ + name: yo - Yorùbá - link: /zh/ name: zh - 汉语 extra_css: diff --git a/docs/yo/docs/index.md b/docs/yo/docs/index.md new file mode 100644 index 000000000..ca75a6b13 --- /dev/null +++ b/docs/yo/docs/index.md @@ -0,0 +1,470 @@ +

+ FastAPI +

+

+ Ìlànà wẹ́ẹ́bù FastAPI, iṣẹ́ gíga, ó rọrùn láti kọ̀, o yára láti kóòdù, ó sì ṣetán fún iṣelọpọ ní lílo +

+

+ + Test + + + Coverage + + + Package version + + + Supported Python versions + +

+ +--- + +**Àkọsílẹ̀**: https://fastapi.tiangolo.com + +**Orisun Kóòdù**: https://github.com/tiangolo/fastapi + +--- + +FastAPI jẹ́ ìgbàlódé, tí ó yára (iṣẹ-giga), ìlànà wẹ́ẹ́bù fún kikọ àwọn API pẹ̀lú Python 3.7+ èyí tí ó da lori àwọn ìtọ́kasí àmì irúfẹ́ Python. + +Àwọn ẹya pàtàkì ni: + +* **Ó yára**: Iṣẹ tí ó ga púpọ̀, tí ó wa ni ibamu pẹ̀lú **NodeJS** àti **Go** (ọpẹ si Starlette àti Pydantic). [Ọkan nínú àwọn ìlànà Python ti o yára jùlọ ti o wa](#performance). +* **Ó yára láti kóòdù**: O mu iyara pọ si láti kọ àwọn ẹya tuntun kóòdù nipasẹ "Igba ìdá ọgọ́rùn-ún" (i.e. 200%) si "ọ̀ọ́dúrún ìdá ọgọ́rùn-ún" (i.e. 300%). +* **Àìtọ́ kékeré**: O n din aṣiṣe ku bi ọgbon ìdá ọgọ́rùn-ún (i.e. 40%) ti eda eniyan (oṣiṣẹ kóòdù) fa. * +* **Ọgbọ́n àti ìmọ̀**: Atilẹyin olootu nla. Ìparí nibi gbogbo. Àkókò díẹ̀ nipa wíwá ibi tí ìṣòro kóòdù wà. +* **Irọrun**: A kọ kí ó le rọrun láti lo àti láti kọ ẹkọ nínú rè. Ó máa fún ọ ní àkókò díẹ̀ látı ka àkọsílẹ. +* **Ó kúkurú ní kikọ**: Ó dín àtúnkọ àti àtúntò kóòdù kù. Ìkéde àṣàyàn kọ̀ọ̀kan nínú rẹ̀ ní ọ̀pọ̀lọpọ̀ àwọn ìlò. O ṣe iranlọwọ láti má ṣe ní ọ̀pọ̀lọpọ̀ àṣìṣe. +* **Ó lágbára**: Ó ń ṣe àgbéjáde kóòdù tí ó ṣetán fún ìṣelọ́pọ̀. Pẹ̀lú àkọsílẹ̀ tí ó máa ṣàlàyé ara rẹ̀ fún ẹ ní ìbáṣepọ̀ aládàáṣiṣẹ́ pẹ̀lú rè. +* **Ajohunše/Ìtọ́kasí**: Ó da lori (àti ibamu ni kikun pẹ̀lú) àwọn ìmọ ajohunše/ìtọ́kasí fún àwọn API: OpenAPI (èyí tí a mọ tẹlẹ si Swagger) àti JSON Schema. + +* iṣiro yi da lori àwọn idanwo tí ẹgbẹ ìdàgbàsókè FastAPI ṣe, nígbàtí wọn kọ àwọn ohun elo iṣelọpọ kóòdù pẹ̀lú rẹ. + +## Àwọn onígbọ̀wọ́ + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + + + +Àwọn onígbọ̀wọ́ míràn + +## Àwọn ero àti èsì + +"_[...] Mò ń lo **FastAPI** púpọ̀ ní lẹ́nu àìpẹ́ yìí. [...] Mo n gbero láti lo o pẹ̀lú àwọn ẹgbẹ mi fún gbogbo iṣẹ **ML wa ni Microsoft**. Diẹ nínú wọn ni afikun ti ifilelẹ àwọn ẹya ara ti ọja **Windows** wa pẹ̀lú àwọn ti **Office**._" + +
Kabir Khan - Microsoft (ref)
+ +--- + +"_A gba àwọn ohun èlò ìwé afọwọkọ **FastAPI** tí kò yí padà láti ṣẹ̀dá olùpín **REST** tí a lè béèrè lọ́wọ́ rẹ̀ láti gba **àsọtẹ́lẹ̀**. [fún Ludwig]_" + +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
+ +--- + +"_**Netflix** ni inudidun láti kede itusilẹ orisun kóòdù ti ìlànà iṣọkan **iṣakoso Ìṣòro** wa: **Ìfiránṣẹ́**! [a kọ pẹ̀lú **FastAPI**]_" + +
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
+ +--- + +"_Inú mi dùn púpọ̀ nípa **FastAPI**. Ó mú inú ẹnì dùn púpọ̀!_" + +
Brian Okken - Python Bytes podcast host (ref)
+ +--- + +"_Ní tòótọ́, ohun tí o kọ dára ó sì tún dán. Ní ọ̀pọ̀lọpọ̀ ọ̀nà, ohun tí mo fẹ́ kí **Hug** jẹ́ nìyẹn - ó wúni lórí gan-an láti rí ẹnìkan tí ó kọ́ nǹkan bí èyí._" + +
Timothy Crosley - Hug creator (ref)
+ +--- + +"_Ti o ba n wa láti kọ ọkan **ìlànà igbalode** fún kikọ àwọn REST API, ṣayẹwo **FastAPI** [...] Ó yára, ó rọrùn láti lò, ó sì rọrùn láti kọ́[...]_" + +"_A ti yipada si **FastAPI** fún **APIs** wa [...] Mo lérò pé wà á fẹ́ràn rẹ̀ [...]_" + +
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +"_Ti ẹnikẹni ba n wa láti kọ iṣelọpọ API pẹ̀lú Python, èmi yóò ṣe'dúró fún **FastAPI**. Ó jẹ́ ohun tí **àgbékalẹ̀ rẹ̀ lẹ́wà**, **ó rọrùn láti lò** àti wipe ó ni **ìwọ̀n gíga**, o tí dí **bọtini paati** nínú alakọkọ API ìdàgbàsókè kikọ fún wa, àti pe o ni ipa lori adaṣiṣẹ àti àwọn iṣẹ gẹ́gẹ́ bíi Onímọ̀-ẹ̀rọ TAC tí órí Íńtánẹ́ẹ̀tì_" + +
Deon Pillsbury - Cisco (ref)
+ +--- + +## **Typer**, FastAPI ti CLIs + + + +Ti o ba n kọ ohun èlò CLI láti ṣeé lọ nínú ohun èlò lori ebute kọmputa dipo API, ṣayẹwo **Typer**. + +**Typer** jẹ́ àbúrò ìyá FastAPI kékeré. Àti pé wọ́n kọ́ láti jẹ́ **FastAPI ti CLIs**. ⌨️ 🚀 + +## Èròjà + +Python 3.7+ + +FastAPI dúró lórí àwọn èjìká tí àwọn òmíràn: + +* Starlette fún àwọn ẹ̀yà ayélujára. +* Pydantic fún àwọn ẹ̀yà àkójọf'áyẹ̀wò. + +## Fifi sórí ẹrọ + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+Iwọ yóò tún nílò olupin ASGI, fún iṣelọpọ bii Uvicorn tabi Hypercorn. + +
+ +```console +$ pip install "uvicorn[standard]" + +---> 100% +``` + +
+ +## Àpẹẹrẹ + +### Ṣẹ̀dá rẹ̀ + +* Ṣẹ̀dá fáìlì `main.py (èyí tíí ṣe, akọkọ.py)` pẹ̀lú: + +```Python +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} +``` + +
+Tàbí lò async def... + +Tí kóòdù rẹ̀ bá ń lò `async` / `await`, lò `async def`: + +```Python hl_lines="9 14" +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} +``` + +**Akiyesi**: + +Tí o kò bá mọ̀, ṣàyẹ̀wò ibi tí a ti ní _"In a hurry?"_ (i.e. _"Ní kíákíá?"_) nípa `async` and `await` nínú àkọsílẹ̀. + +
+ +### Mu ṣiṣẹ + +Mú olupin ṣiṣẹ pẹ̀lú: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+Nipa aṣẹ kóòdù náà uvicorn main:app --reload... + +Àṣẹ `uvicorn main:app` ń tọ́ka sí: + +* `main`: fáìlì náà 'main.py' (Python "module"). +* `app` jẹ object( i.e. nǹkan) tí a ṣẹ̀dá nínú `main.py` pẹ̀lú ilà `app = FastAPI()`. +* `--reload`: èyí yóò jẹ́ ki olupin tún bẹ̀rẹ̀ lẹ́hìn àwọn àyípadà kóòdù. Jọ̀wọ́, ṣe èyí fún ìdàgbàsókè kóòdù nìkan, má ṣe é ṣe lori àgbéjáde kóòdù tabi fún iṣelọpọ kóòdù. + + +
+ +### Ṣayẹwo rẹ + +Ṣii aṣàwákiri kọ̀ǹpútà rẹ ni http://127.0.0.1:8000/items/5?q=somequery. + +Ìwọ yóò sì rí ìdáhùn JSON bíi: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +O tí ṣẹ̀dá API èyí tí yóò: + +* Gbà àwọn ìbéèrè HTTP ni àwọn _ipa ọ̀nà_ `/` àti `/items/{item_id}`. +* Èyí tí àwọn _ipa ọ̀nà_ (i.e. _paths_) méjèèjì gbà àwọn iṣẹ `GET` (a tun mọ si _àwọn ọna_ HTTP). +* Èyí tí _ipa ọ̀nà_ (i.e. _paths_) `/items/{item_id}` ní _àwọn ohun-ini ipa ọ̀nà_ tí ó yẹ kí ó jẹ́ `int` i.e. `ÒǸKÀ`. +* Èyí tí _ipa ọ̀nà_ (i.e. _paths_) `/items/{item_id}` ní àṣàyàn `str` _àwọn ohun-ini_ (i.e. _query parameter_) `q`. + +### Ìbáṣepọ̀ àkọsílẹ̀ API + +Ní báyìí, lọ sí http://127.0.0.1:8000/docs. + +Lẹ́yìn náà, iwọ yóò rí ìdáhùn àkọsílẹ̀ API tí ó jẹ́ ìbáṣepọ̀ alaifọwọyi/aládàáṣiṣẹ́ (tí a pèṣè nípaṣẹ̀ Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Ìdàkejì àkọsílẹ̀ API + +Ní báyìí, lọ sí http://127.0.0.1:8000/redoc. + +Wà á rí àwọn àkọsílẹ̀ aládàáṣiṣẹ́ mìíràn (tí a pese nipasẹ ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Àpẹẹrẹ ìgbésókè mìíràn + +Ní báyìí ṣe àtúnṣe fáìlì `main.py` láti gba kókó èsì láti inú ìbéèrè `PUT`. + +Ní báyìí, ṣe ìkéde kókó èsì API nínú kóòdù rẹ nipa lílo àwọn ìtọ́kasí àmì irúfẹ́ Python, ọpẹ́ pàtàkìsi sí Pydantic. + +```Python hl_lines="4 9-12 25-27" +from typing import Union + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Union[bool, None] = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} +``` + +Olupin yóò tún ṣe àtúnṣe laifọwọyi/aládàáṣiṣẹ́ (nítorí wípé ó se àfikún `-reload` si àṣẹ kóòdù `uvicorn` lókè). + +### Ìbáṣepọ̀ ìgbésókè àkọsílẹ̀ API + +Ní báyìí, lọ sí http://127.0.0.1:8000/docs. + +* Ìbáṣepọ̀ àkọsílẹ̀ API yóò ṣe imudojuiwọn àkọsílẹ̀ API laifọwọyi, pẹ̀lú kókó èsì ìdáhùn API tuntun: + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Tẹ bọtini "Gbiyanju rẹ" i.e. "Try it out", yóò gbà ọ́ láàyè láti jẹ́ kí ó tẹ́ àlàyé tí ó nílò kí ó le sọ̀rọ̀ tààrà pẹ̀lú API: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) + +* Lẹhinna tẹ bọtini "Ṣiṣe" i.e. "Execute", olùmúlò (i.e. user interface) yóò sọrọ pẹ̀lú API rẹ, yóò ṣe afiranṣẹ àwọn èròjà, pàápàá jùlọ yóò gba àwọn àbájáde yóò si ṣafihan wọn loju ìbòjú: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) + +### Ìdàkejì ìgbésókè àkọsílẹ̀ API + +Ní báyìí, lọ sí http://127.0.0.1:8000/redoc. + +* Ìdàkejì àkọsílẹ̀ API yóò ṣ'afihan ìbéèrè èròjà/pàrámítà tuntun àti kókó èsì ti API: + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### Àtúnyẹ̀wò + +Ni akopọ, ìwọ yóò kéde ni **kete** àwọn iru èròjà/pàrámítà, kókó èsì API, abbl (i.e. àti bẹbẹ lọ), bi àwọn èròjà iṣẹ. + +O ṣe ìyẹn pẹ̀lú irúfẹ́ àmì ìtọ́kasí ìgbàlódé Python. + +O ò nílò láti kọ́ síńtáàsì tuntun, ìlànà tàbí ọ̀wọ́ kíláàsì kan pàtó, abbl (i.e. àti bẹbẹ lọ). + +Ìtọ́kasí **Python 3.7+** + +Fún àpẹẹrẹ, fún `int`: + +```Python +item_id: int +``` + +tàbí fún àwòṣe `Item` tí ó nira díẹ̀ síi: + +```Python +item: Item +``` + +... àti pẹ̀lú ìkéde kan ṣoṣo yẹn ìwọ yóò gbà: + +* Atilẹyin olootu, pẹ̀lú: + * Pipari. + * Àyẹ̀wò irúfẹ́ àmì ìtọ́kasí. +* Ìfọwọ́sí àkójọf'áyẹ̀wò (i.e. data): + * Aṣiṣe alaifọwọyi/aládàáṣiṣẹ́ àti aṣiṣe ti ó hàn kedere nígbàtí àwọn àkójọf'áyẹ̀wò (i.e. data) kò wulo tabi tí kò fẹsẹ̀ múlẹ̀. + * Ìfọwọ́sí fún ohun elo JSON tí ó jìn gan-an. +* Ìyípadà tí input àkójọf'áyẹ̀wò: tí ó wà láti nẹtiwọọki si àkójọf'áyẹ̀wò àti irúfẹ́ àmì ìtọ́kasí Python. Ó ń ka láti: + * JSON. + * èròjà ọ̀nà tí ò gbé gbà. + * èròjà ìbéèrè. + * Àwọn Kúkì + * Àwọn Àkọlé + * Àwọn Fọọmu + * Àwọn Fáìlì +* Ìyípadà èsì àkójọf'áyẹ̀wò: yíyípadà láti àkójọf'áyẹ̀wò àti irúfẹ́ àmì ìtọ́kasí Python si nẹtiwọọki (gẹ́gẹ́ bí JSON): + * Yí irúfẹ́ àmì ìtọ́kasí padà (`str`, `int`, `float`, `bool`, `list`, abbl i.e. àti bèbè ló). + * Àwọn ohun èlò `datetime`. + * Àwọn ohun èlò `UUID`. + * Àwọn awoṣẹ́ ibi ìpamọ́ àkójọf'áyẹ̀wò. + * ...àti ọ̀pọ̀lọpọ̀ díẹ̀ síi. +* Ìbáṣepọ̀ àkọsílẹ̀ API aládàáṣiṣẹ́, pẹ̀lú ìdàkejì àgbékalẹ̀-àwọn-olùmúlò (i.e user interfaces) méjì: + * Àgbékalẹ̀-olùmúlò Swagger. + * ReDoc. + +--- + +Nisinsin yi, tí ó padà sí àpẹẹrẹ ti tẹ́lẹ̀, **FastAPI** yóò: + +* Fọwọ́ sí i pé `item_id` wà nínú ọ̀nà ìbéèrè HTTP fún `GET` àti `PUT`. +* Fọwọ́ sí i pé `item_id` jẹ́ irúfẹ́ àmì ìtọ́kasí `int` fún ìbéèrè HTTP `GET` àti `PUT`. + * Tí kìí bá ṣe bẹ, oníbàárà yóò ríi àṣìṣe tí ó wúlò, kedere. +* Ṣàyẹ̀wò bóyá ìbéèrè àṣàyàn pàrámítà kan wà tí orúkọ rẹ̀ ń jẹ́ `q` (gẹ́gẹ́ bíi `http://127.0.0.1:8000/items/foo?q=somequery`) fún ìbéèrè HTTP `GET`. + * Bí wọ́n ṣe kéde pàrámítà `q` pẹ̀lú `= None`, ó jẹ́ àṣàyàn (i.e optional). + * Láìsí `None` yóò nílò (gẹ́gẹ́ bí kókó èsì ìbéèrè HTTP ṣe wà pẹ̀lú `PUT`). +* Fún àwọn ìbéèrè HTTP `PUT` sí `/items/{item_id}`, kà kókó èsì ìbéèrè HTTP gẹ́gẹ́ bí JSON: + * Ṣàyẹ̀wò pé ó ní àbùdá tí ó nílò èyí tíí ṣe `name` i.e. `orúkọ` tí ó yẹ kí ó jẹ́ `str`. + * Ṣàyẹ̀wò pé ó ní àbùdá tí ó nílò èyí tíí ṣe `price` i.e. `iye` tí ó gbọ́dọ̀ jẹ́ `float`. + * Ṣàyẹ̀wò pé ó ní àbùdá àṣàyàn `is_offer`, tí ó yẹ kí ó jẹ́ `bool`, tí ó bá wà níbẹ̀. + * Gbogbo èyí yóò tún ṣiṣẹ́ fún àwọn ohun èlò JSON tí ó jìn gidi gan-an. +* Yìí padà láti àti sí JSON lai fi ọwọ́ yi. +* Ṣe àkọsílẹ̀ ohun gbogbo pẹ̀lú OpenAPI, èyí tí yóò wà ní lílo nípaṣẹ̀: + * Àwọn ètò àkọsílẹ̀ ìbáṣepọ̀. + * Aládàáṣiṣẹ́ oníbárà èlètò tíí ṣẹ̀dá kóòdù, fún ọ̀pọ̀lọpọ̀ àwọn èdè. +* Pese àkọsílẹ̀ òní ìbáṣepọ̀ ti àwọn àgbékalẹ̀ ayélujára méjì tààrà. + +--- + +A ń ṣẹ̀ṣẹ̀ ń mú ẹyẹ bọ́ làpò ní, ṣùgbọ́n ó ti ni òye bí gbogbo rẹ̀ ṣe ń ṣiṣẹ́. + +Gbiyanju láti yí ìlà padà pẹ̀lú: + +```Python + return {"item_name": item.name, "item_id": item_id} +``` + +...láti: + +```Python + ... "item_name": item.name ... +``` + +...ṣí: + +```Python + ... "item_price": item.price ... +``` + +.. kí o sì wo bí olóòtú rẹ yóò ṣe parí àwọn àbùdá náà fúnra rẹ̀, yóò sì mọ irúfẹ́ wọn: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +Fún àpẹẹrẹ pípé síi pẹ̀lú àwọn àbùdá mìíràn, wo Ìdánilẹ́kọ̀ọ́ - Ìtọ́sọ́nà Olùmúlò. + +**Itaniji gẹ́gẹ́ bí isọ'ye**: ìdánilẹ́kọ̀ọ́ - itọsọna olùmúlò pẹ̀lú: + +* Ìkéde àṣàyàn **pàrámítà** láti àwọn oriṣiriṣi ibòmíràn gẹ́gẹ́ bíi: àwọn **àkọlé èsì API**, **kúkì**, **ààyè fọọmu**, àti **fáìlì**. +* Bíi ó ṣe lé ṣètò **àwọn ìdíwọ́ ìfọwọ́sí** bí `maximum_length` tàbí `regex`. +* Ó lágbára púpọ̀ ó sì rọrùn láti lo ètò **Àfikún Ìgbẹ́kẹ̀lé Kóòdù**. +* Ààbò àti ìfọwọ́sowọ́pọ̀, pẹ̀lú àtìlẹ́yìn fún **OAuth2** pẹ̀lú **àmì JWT** àti **HTTP Ipilẹ ìfọwọ́sowọ́pọ̀**. +* Àwọn ìlànà ìlọsíwájú (ṣùgbọ́n tí ó rọrùn bákan náà) fún ìkéde **àwọn àwòṣe JSON tó jinlẹ̀** (ọpẹ́ pàtàkìsi sí Pydantic). +* Iṣọpọ **GraphQL** pẹ̀lú Strawberry àti àwọn ohun èlò ìwé kóòdù afọwọkọ mìíràn tí kò yí padà. +* Ọpọlọpọ àwọn àfikún àwọn ẹ̀yà (ọpẹ́ pàtàkìsi sí Starlette) bí: + * **WebSockets** + * àwọn ìdánwò tí ó rọrùn púpọ̀ lórí HTTPX àti `pytest` + * **CORS** + * **Cookie Sessions** + * ...àti síwájú síi. + +## Ìṣesí + +Àwọn àlá TechEmpower fi hàn pé **FastAPI** ń ṣiṣẹ́ lábẹ́ Uvicorn gẹ́gẹ́ bí ọ̀kan lára àwọn ìlànà Python tí ó yára jùlọ tí ó wà, ní ìsàlẹ̀ Starlette àti Uvicorn fúnra wọn (tí FastAPI ń lò fúnra rẹ̀). (*) + +Láti ní òye síi nípa rẹ̀, wo abala àwọn Àlá. + +## Àṣàyàn Àwọn Àfikún Ìgbẹ́kẹ̀lé Kóòdù + +Èyí tí Pydantic ń lò: + +* email_validator - fún ifọwọsi ímeèlì. +* pydantic-settings - fún ètò ìsàkóso. +* pydantic-extra-types - fún àfikún oríṣi láti lọ pẹ̀lú Pydantic. + +Èyí tí Starlette ń lò: + +* httpx - Nílò tí ó bá fẹ́ láti lọ `TestClient`. +* jinja2 - Nílò tí ó bá fẹ́ láti lọ iṣeto awoṣe aiyipada. +* python-multipart - Nílò tí ó bá fẹ́ láti ṣe àtìlẹ́yìn fún "àyẹ̀wò" fọọmu, pẹ̀lú `request.form()`. +* itsdangerous - Nílò fún àtìlẹ́yìn `SessionMiddleware`. +* pyyaml - Nílò fún àtìlẹ́yìn Starlette's `SchemaGenerator` (ó ṣe ṣe kí ó má nílò rẹ̀ fún FastAPI). +* ujson - Nílò tí ó bá fẹ́ láti lọ `UJSONResponse`. + +Èyí tí FastAPI / Starlette ń lò: + +* uvicorn - Fún olupin tí yóò sẹ́ àmúyẹ àti tí yóò ṣe ìpèsè fún iṣẹ́ rẹ tàbí ohun èlò rẹ. +* orjson - Nílò tí ó bá fẹ́ láti lọ `ORJSONResponse`. + +Ó lè fi gbogbo àwọn wọ̀nyí sórí ẹrọ pẹ̀lú `pip install "fastapi[all]"`. + +## Iwe-aṣẹ + +Iṣẹ́ yìí ni iwe-aṣẹ lábẹ́ àwọn òfin tí iwe-aṣẹ MIT. diff --git a/docs/yo/mkdocs.yml b/docs/yo/mkdocs.yml new file mode 100644 index 000000000..de18856f4 --- /dev/null +++ b/docs/yo/mkdocs.yml @@ -0,0 +1 @@ +INHERIT: ../en/mkdocs.yml From a6d893fe981f270be660c3e8bceab888d38786c5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 16:16:38 +0000 Subject: [PATCH 40/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 622f6ddc5..21b3be50e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Add Yoruba translation for `docs/yo/docs/index.md`. PR [#10033](https://github.com/tiangolo/fastapi/pull/10033) by [@AfolabiOlaoluwa](https://github.com/AfolabiOlaoluwa). * ✏️ Fix Pydantic examples in tutorial for Python types. PR [#9961](https://github.com/tiangolo/fastapi/pull/9961) by [@rahulsalgare](https://github.com/rahulsalgare). * ✏️ Fix link to Pydantic docs in `docs/en/docs/tutorial/extra-data-types.md`. PR [#10155](https://github.com/tiangolo/fastapi/pull/10155) by [@hasnatsajid](https://github.com/hasnatsajid). * 🌐 Add Ukrainian translation for `docs/uk/docs/python-types.md`. PR [#10080](https://github.com/tiangolo/fastapi/pull/10080) by [@rostik1410](https://github.com/rostik1410). From caf0b688cd7e71da0a207ab5d611a57ce4ac5f13 Mon Sep 17 00:00:00 2001 From: Yusuke Tamura <62091034+tamtam-fitness@users.noreply.github.com> Date: Sun, 3 Sep 2023 01:55:26 +0900 Subject: [PATCH 41/54] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20indent=20forma?= =?UTF-8?q?t=20in=20`docs/en/docs/deployment/server-workers.md`=20(#10066)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/en/docs/deployment/server-workers.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/docs/deployment/server-workers.md b/docs/en/docs/deployment/server-workers.md index 4ccd9d9f6..2df9f3d43 100644 --- a/docs/en/docs/deployment/server-workers.md +++ b/docs/en/docs/deployment/server-workers.md @@ -90,7 +90,9 @@ Let's see what each of those options mean: ``` * So, the colon in `main:app` would be equivalent to the Python `import` part in `from main import app`. + * `--workers`: The number of worker processes to use, each will run a Uvicorn worker, in this case, 4 workers. + * `--worker-class`: The Gunicorn-compatible worker class to use in the worker processes. * Here we pass the class that Gunicorn can import and use with: From 7802454131866a1af7b509702fb6de369f33c71d Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 16:56:04 +0000 Subject: [PATCH 42/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 21b3be50e..624fc736b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix indent format in `docs/en/docs/deployment/server-workers.md`. PR [#10066](https://github.com/tiangolo/fastapi/pull/10066) by [@tamtam-fitness](https://github.com/tamtam-fitness). * 🌐 Add Yoruba translation for `docs/yo/docs/index.md`. PR [#10033](https://github.com/tiangolo/fastapi/pull/10033) by [@AfolabiOlaoluwa](https://github.com/AfolabiOlaoluwa). * ✏️ Fix Pydantic examples in tutorial for Python types. PR [#9961](https://github.com/tiangolo/fastapi/pull/9961) by [@rahulsalgare](https://github.com/rahulsalgare). * ✏️ Fix link to Pydantic docs in `docs/en/docs/tutorial/extra-data-types.md`. PR [#10155](https://github.com/tiangolo/fastapi/pull/10155) by [@hasnatsajid](https://github.com/hasnatsajid). From 23511f1fdf5de1b47575c6d1e305c17a3851fbae Mon Sep 17 00:00:00 2001 From: Alex Rocha <62669972+LecoOliveira@users.noreply.github.com> Date: Sat, 2 Sep 2023 14:01:06 -0300 Subject: [PATCH 43/54] =?UTF-8?q?=F0=9F=8C=90=20Remove=20duplicate=20line?= =?UTF-8?q?=20in=20translation=20for=20`docs/pt/docs/tutorial/path-params.?= =?UTF-8?q?md`=20(#10126)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/pt/docs/tutorial/path-params.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/pt/docs/tutorial/path-params.md b/docs/pt/docs/tutorial/path-params.md index 5de3756ed..cd8c18858 100644 --- a/docs/pt/docs/tutorial/path-params.md +++ b/docs/pt/docs/tutorial/path-params.md @@ -236,7 +236,6 @@ Então, você poderia usar ele com: Com o **FastAPI**, usando as declarações de tipo do Python, você obtém: * Suporte no editor: verificação de erros, e opção de autocompletar, etc. -* Parsing de dados * "Parsing" de dados * Validação de dados * Anotação da API e documentação automática From 7f1dedac2c8f57aa1e976aaa492f5cbd77d25ab1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 17:01:44 +0000 Subject: [PATCH 44/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 624fc736b..54a00d9ed 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🌐 Remove duplicate line in translation for `docs/pt/docs/tutorial/path-params.md`. PR [#10126](https://github.com/tiangolo/fastapi/pull/10126) by [@LecoOliveira](https://github.com/LecoOliveira). * ✏️ Fix indent format in `docs/en/docs/deployment/server-workers.md`. PR [#10066](https://github.com/tiangolo/fastapi/pull/10066) by [@tamtam-fitness](https://github.com/tamtam-fitness). * 🌐 Add Yoruba translation for `docs/yo/docs/index.md`. PR [#10033](https://github.com/tiangolo/fastapi/pull/10033) by [@AfolabiOlaoluwa](https://github.com/AfolabiOlaoluwa). * ✏️ Fix Pydantic examples in tutorial for Python types. PR [#9961](https://github.com/tiangolo/fastapi/pull/9961) by [@rahulsalgare](https://github.com/rahulsalgare). From c502197d7cffc6fe3f310fc2a72dd3148bcaa016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Dorr=C3=ADo=20V=C3=A1zquez?= <64154120+pablodorrio@users.noreply.github.com> Date: Sat, 2 Sep 2023 19:02:26 +0200 Subject: [PATCH 45/54] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20validation=20p?= =?UTF-8?q?arameter=20name=20in=20docs,=20from=20`regex`=20to=20`pattern`?= =?UTF-8?q?=20(#10085)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/tutorial/query-params-str-validations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/docs/tutorial/query-params-str-validations.md b/docs/en/docs/tutorial/query-params-str-validations.md index f87adddcb..5d1c08add 100644 --- a/docs/en/docs/tutorial/query-params-str-validations.md +++ b/docs/en/docs/tutorial/query-params-str-validations.md @@ -932,7 +932,7 @@ Validations specific for strings: * `min_length` * `max_length` -* `regex` +* `pattern` In these examples you saw how to declare validations for `str` values. From e1a1a367a74a64c330e11fb63a870a2c77a29a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 2 Sep 2023 19:03:43 +0200 Subject: [PATCH 46/54] =?UTF-8?q?=F0=9F=93=8C=20Pin=20AnyIO=20to=20<=204.0?= =?UTF-8?q?.0=20to=20handle=20an=20incompatibility=20while=20upgrading=20t?= =?UTF-8?q?o=20Starlette=200.31.1=20(#10194)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 9b7cca9c9..2870b31a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,8 @@ dependencies = [ "starlette>=0.27.0,<0.28.0", "pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0", "typing-extensions>=4.5.0", + # TODO: remove this pin after upgrading Starlette 0.31.1 + "anyio>=3.7.1,<4.0.0", ] dynamic = ["version"] From 8562cae44b18d0f1638bb6d338a85754468fc559 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 17:05:59 +0000 Subject: [PATCH 47/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 54a00d9ed..24dd82085 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📌 Pin AnyIO to < 4.0.0 to handle an incompatibility while upgrading to Starlette 0.31.1. PR [#10194](https://github.com/tiangolo/fastapi/pull/10194) by [@tiangolo](https://github.com/tiangolo). * 🌐 Remove duplicate line in translation for `docs/pt/docs/tutorial/path-params.md`. PR [#10126](https://github.com/tiangolo/fastapi/pull/10126) by [@LecoOliveira](https://github.com/LecoOliveira). * ✏️ Fix indent format in `docs/en/docs/deployment/server-workers.md`. PR [#10066](https://github.com/tiangolo/fastapi/pull/10066) by [@tamtam-fitness](https://github.com/tamtam-fitness). * 🌐 Add Yoruba translation for `docs/yo/docs/index.md`. PR [#10033](https://github.com/tiangolo/fastapi/pull/10033) by [@AfolabiOlaoluwa](https://github.com/AfolabiOlaoluwa). From 118010ad5ebb98f602deee7e69c3bff94aadf16a Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 2 Sep 2023 17:06:22 +0000 Subject: [PATCH 48/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 24dd82085..45d845f25 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✏️ Fix validation parameter name in docs, from `regex` to `pattern`. PR [#10085](https://github.com/tiangolo/fastapi/pull/10085) by [@pablodorrio](https://github.com/pablodorrio). * 📌 Pin AnyIO to < 4.0.0 to handle an incompatibility while upgrading to Starlette 0.31.1. PR [#10194](https://github.com/tiangolo/fastapi/pull/10194) by [@tiangolo](https://github.com/tiangolo). * 🌐 Remove duplicate line in translation for `docs/pt/docs/tutorial/path-params.md`. PR [#10126](https://github.com/tiangolo/fastapi/pull/10126) by [@LecoOliveira](https://github.com/LecoOliveira). * ✏️ Fix indent format in `docs/en/docs/deployment/server-workers.md`. PR [#10066](https://github.com/tiangolo/fastapi/pull/10066) by [@tamtam-fitness](https://github.com/tamtam-fitness). From ce8ee1410ae4ba37744ed818be05e2cc187601e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 2 Sep 2023 19:09:47 +0200 Subject: [PATCH 49/54] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 45d845f25..4f333119c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,25 +2,39 @@ ## Latest Changes -* ✏️ Fix validation parameter name in docs, from `regex` to `pattern`. PR [#10085](https://github.com/tiangolo/fastapi/pull/10085) by [@pablodorrio](https://github.com/pablodorrio). +### Fixes + * 📌 Pin AnyIO to < 4.0.0 to handle an incompatibility while upgrading to Starlette 0.31.1. PR [#10194](https://github.com/tiangolo/fastapi/pull/10194) by [@tiangolo](https://github.com/tiangolo). -* 🌐 Remove duplicate line in translation for `docs/pt/docs/tutorial/path-params.md`. PR [#10126](https://github.com/tiangolo/fastapi/pull/10126) by [@LecoOliveira](https://github.com/LecoOliveira). + +### Docs + +* ✏️ Fix validation parameter name in docs, from `regex` to `pattern`. PR [#10085](https://github.com/tiangolo/fastapi/pull/10085) by [@pablodorrio](https://github.com/pablodorrio). * ✏️ Fix indent format in `docs/en/docs/deployment/server-workers.md`. PR [#10066](https://github.com/tiangolo/fastapi/pull/10066) by [@tamtam-fitness](https://github.com/tamtam-fitness). -* 🌐 Add Yoruba translation for `docs/yo/docs/index.md`. PR [#10033](https://github.com/tiangolo/fastapi/pull/10033) by [@AfolabiOlaoluwa](https://github.com/AfolabiOlaoluwa). * ✏️ Fix Pydantic examples in tutorial for Python types. PR [#9961](https://github.com/tiangolo/fastapi/pull/9961) by [@rahulsalgare](https://github.com/rahulsalgare). * ✏️ Fix link to Pydantic docs in `docs/en/docs/tutorial/extra-data-types.md`. PR [#10155](https://github.com/tiangolo/fastapi/pull/10155) by [@hasnatsajid](https://github.com/hasnatsajid). -* 🌐 Add Ukrainian translation for `docs/uk/docs/python-types.md`. PR [#10080](https://github.com/tiangolo/fastapi/pull/10080) by [@rostik1410](https://github.com/rostik1410). -* 🌐 Add Vietnamese translations for `docs/vi/docs/tutorial/first-steps.md` and `docs/vi/docs/tutorial/index.md`. PR [#10088](https://github.com/tiangolo/fastapi/pull/10088) by [@magiskboy](https://github.com/magiskboy). * ✏️ Fix typo in `docs/en/docs/tutorial/handling-errors.md`. PR [#10170](https://github.com/tiangolo/fastapi/pull/10170) by [@poupapaa](https://github.com/poupapaa). -* ✏️ Fix typos in comment in `fastapi/applications.py`. PR [#10045](https://github.com/tiangolo/fastapi/pull/10045) by [@AhsanSheraz](https://github.com/AhsanSheraz). * ✏️ Fix typo in `docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#10172](https://github.com/tiangolo/fastapi/pull/10172) by [@ragul-kachiappan](https://github.com/ragul-kachiappan). + +### Translations + +* 🌐 Remove duplicate line in translation for `docs/pt/docs/tutorial/path-params.md`. PR [#10126](https://github.com/tiangolo/fastapi/pull/10126) by [@LecoOliveira](https://github.com/LecoOliveira). +* 🌐 Add Yoruba translation for `docs/yo/docs/index.md`. PR [#10033](https://github.com/tiangolo/fastapi/pull/10033) by [@AfolabiOlaoluwa](https://github.com/AfolabiOlaoluwa). +* 🌐 Add Ukrainian translation for `docs/uk/docs/python-types.md`. PR [#10080](https://github.com/tiangolo/fastapi/pull/10080) by [@rostik1410](https://github.com/rostik1410). +* 🌐 Add Vietnamese translations for `docs/vi/docs/tutorial/first-steps.md` and `docs/vi/docs/tutorial/index.md`. PR [#10088](https://github.com/tiangolo/fastapi/pull/10088) by [@magiskboy](https://github.com/magiskboy). * 🌐 Add Ukrainian translation for `docs/uk/docs/alternatives.md`. PR [#10060](https://github.com/tiangolo/fastapi/pull/10060) by [@whysage](https://github.com/whysage). * 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/index.md`. PR [#10079](https://github.com/tiangolo/fastapi/pull/10079) by [@rostik1410](https://github.com/rostik1410). * ✏️ Fix typos in `docs/en/docs/how-to/separate-openapi-schemas.md` and `docs/en/docs/tutorial/schema-extra-example.md`. PR [#10189](https://github.com/tiangolo/fastapi/pull/10189) by [@xzmeng](https://github.com/xzmeng). * 🌐 Add Chinese translation for `docs/zh/docs/advanced/generate-clients.md`. PR [#9883](https://github.com/tiangolo/fastapi/pull/9883) by [@funny-cat-happy](https://github.com/funny-cat-happy). -* 👥 Update FastAPI People. PR [#10186](https://github.com/tiangolo/fastapi/pull/10186) by [@tiangolo](https://github.com/tiangolo). + +### Refactors + +* ✏️ Fix typos in comment in `fastapi/applications.py`. PR [#10045](https://github.com/tiangolo/fastapi/pull/10045) by [@AhsanSheraz](https://github.com/AhsanSheraz). * ✅ Add missing test for OpenAPI examples, it was missing in coverage. PR [#10188](https://github.com/tiangolo/fastapi/pull/10188) by [@tiangolo](https://github.com/tiangolo). +### Internal + +* 👥 Update FastAPI People. PR [#10186](https://github.com/tiangolo/fastapi/pull/10186) by [@tiangolo](https://github.com/tiangolo). + ## 0.103.0 ### Features From bfde8f3ef20dc338bbce8a0ff0f4b441c54d5b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 2 Sep 2023 19:10:19 +0200 Subject: [PATCH 50/54] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.103.?= =?UTF-8?q?1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 4f333119c..f03d54a9a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.103.1 + ### Fixes * 📌 Pin AnyIO to < 4.0.0 to handle an incompatibility while upgrading to Starlette 0.31.1. PR [#10194](https://github.com/tiangolo/fastapi/pull/10194) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index ff8b98d3b..329477e41 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.103.0" +__version__ = "0.103.1" from starlette import status as status From 766dfb5b38a4751c0706b1ef4a73dc276e81572b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 10 Sep 2023 12:18:26 +0200 Subject: [PATCH 51/54] =?UTF-8?q?=F0=9F=94=A7=20Update=20sponsors,=20add?= =?UTF-8?q?=20Bump.sh=20(#10227)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/en/data/sponsors.yml | 3 +++ docs/en/docs/img/sponsors/bump-sh-banner.png | Bin 0 -> 10139 bytes docs/en/docs/img/sponsors/bump-sh.png | Bin 0 -> 18609 bytes docs/en/overrides/main.html | 6 ++++++ 5 files changed, 10 insertions(+) create mode 100755 docs/en/docs/img/sponsors/bump-sh-banner.png create mode 100755 docs/en/docs/img/sponsors/bump-sh.png diff --git a/README.md b/README.md index 266213426..7aa9d4be6 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ The key features are: + diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 0d9597f07..504c373a2 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -11,6 +11,9 @@ gold: - url: https://www.porter.run title: Deploy FastAPI on AWS with a few clicks img: https://fastapi.tiangolo.com/img/sponsors/porter.png + - url: https://bump.sh/fastapi?utm_source=fastapi&utm_medium=referral&utm_campaign=sponsor + title: Automate FastAPI documentation generation with Bump.sh + img: https://fastapi.tiangolo.com/img/sponsors/bump-sh.png silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas diff --git a/docs/en/docs/img/sponsors/bump-sh-banner.png b/docs/en/docs/img/sponsors/bump-sh-banner.png new file mode 100755 index 0000000000000000000000000000000000000000..e75c0facd30acbee9121ae41cce236a99bea3646 GIT binary patch literal 10139 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 JPDHLkV1j@T&F26B literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/sponsors/bump-sh.png b/docs/en/docs/img/sponsors/bump-sh.png new file mode 100755 index 0000000000000000000000000000000000000000..61817e86fa1064e2ea239bb45a504998aa6274c2 GIT binary patch literal 18609 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