From 313bbe802fc9c2d16ff0203d82420f5279b7c45d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 29 Nov 2020 18:32:18 +0100 Subject: [PATCH] =?utf8?q?=E2=9C=A8=20Add=20support=20for=20shared/top-lev?= =?utf8?q?el=20parameters=20(dependencies,=20tags,=20etc)=20(#2434)?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * ✨ Add Default and DefaultPlaceholder data structures to handle defaults and overrides * ✨ Add utils to get values by priority handling DefaultPlaceholders * ✨ Add support for top-level parameters in FastAPI, APIRouter, include_router including: prefix, tags, dependencies, deprecated, include_in_schema, responses, default_response_class, callbacks * ♻️ Update openapi utils to handle DefaultPlaceholder for response_class * 📝 Update bigger-application example code to use top-level params and showcase them in APIRouter, FastAPI, include_router * 📝 Update docs for Bigger Applications, include diagrams, top-level params * 🔥 Simplify code and docs for callbacks as default_response_class is no longer required * 📝 Add docs for top-level dependencies, in FastAPI() * 📝 Add docs reference to top-level dependencies in docs for decorator * ✅ Update/increase tests for Bigger Applications including shared parameters * ✅ Add tests for top-level dependencies in FastAPI() * ✅ Add tests for internal DefaultPlaceholder * ✅ Update/increase tests for callbacks with top-level parameters * ✅ Add LOTS of tests covering branches and cases for shared parameters in top-level FastAPI, path operations, include_router, APIRouter, its path operations, nested include_router, nested APIRouter, and its path operations * 🎨 Format/reorder parameters for consistency in FastAPI, APIRouter, include_router --- docs/en/docs/advanced/openapi-callbacks.md | 9 - .../tutorial/bigger-applications/image01.png | Bin 77899 -> 74516 bytes .../bigger-applications/package.drawio | 43 + .../tutorial/bigger-applications/package.svg | 1 + docs/en/docs/tutorial/bigger-applications.md | 329 +- ...pendencies-in-path-operation-decorators.md | 9 + .../dependencies/global-dependencies.md | 17 + docs/en/mkdocs.yml | 1 + .../bigger_applications/app/dependencies.py | 11 + .../app/internal/__init__.py | 0 .../bigger_applications/app/internal/admin.py | 8 + docs_src/bigger_applications/app/main.py | 25 +- .../bigger_applications/app/routers/items.py | 28 +- .../bigger_applications/app/routers/users.py | 2 +- docs_src/dependencies/tutorial012.py | 25 + docs_src/openapi_callbacks/tutorial001.py | 3 +- fastapi/applications.py | 112 +- fastapi/datastructures.py | 33 +- fastapi/openapi/utils.py | 11 +- fastapi/routing.py | 185 +- fastapi/utils.py | 19 + tests/test_datastructures.py | 15 + .../test_include_router_defaults_overrides.py | 6613 +++++++++++++++++ tests/test_sub_callbacks.py | 70 +- .../test_bigger_applications/test_main.py | 295 +- .../test_dependencies/test_tutorial012.py | 209 + 26 files changed, 7786 insertions(+), 287 deletions(-) create mode 100644 docs/en/docs/img/tutorial/bigger-applications/package.drawio create mode 100644 docs/en/docs/img/tutorial/bigger-applications/package.svg create mode 100644 docs/en/docs/tutorial/dependencies/global-dependencies.md create mode 100644 docs_src/bigger_applications/app/dependencies.py create mode 100644 docs_src/bigger_applications/app/internal/__init__.py create mode 100644 docs_src/bigger_applications/app/internal/admin.py create mode 100644 docs_src/dependencies/tutorial012.py create mode 100644 tests/test_include_router_defaults_overrides.py create mode 100644 tests/test_tutorial/test_dependencies/test_tutorial012.py diff --git a/docs/en/docs/advanced/openapi-callbacks.md b/docs/en/docs/advanced/openapi-callbacks.md index e927aea4db..138c90dd7c 100644 --- a/docs/en/docs/advanced/openapi-callbacks.md +++ b/docs/en/docs/advanced/openapi-callbacks.md @@ -83,15 +83,6 @@ So we are going to use that same knowledge to document how the *external API* sh First create a new `APIRouter` that will contain one or more callbacks. -This router will never be added to an actual `FastAPI` app (i.e. it will never be passed to `app.include_router(...)`). - -Because of that, you need to declare what will be the `default_response_class`, and set it to `JSONResponse`. - -!!! Note "Technical Details" - The `response_class` is normally set by the `FastAPI` app during the call to `app.include_router(some_router)`. - - But as we are never calling `app.include_router(some_router)`, we need to set the `default_response_class` during creation of the `APIRouter`. - ```Python hl_lines="5 26" {!../../../docs_src/openapi_callbacks/tutorial001.py!} ``` diff --git a/docs/en/docs/img/tutorial/bigger-applications/image01.png b/docs/en/docs/img/tutorial/bigger-applications/image01.png index f31195934b6892ef73d1f5da15daca6be7c40ec5..faba6628e765abca6ec4b534989cb9e371648af8 100644 GIT binary patch literal 74516 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

!oRs4f`1QSdT&CZRBc<(He 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¬uADtZqChcp!=1=Qd7*_ntJD9E136wjPd~# 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 literal 77899 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

X-b=bXBX=Qd#9!2SzGqQ0f>?OMSefN+Z^KYZ zGiLT>s@LWPkKMpd5($f_l*SPx;g5Me^=jAMFPOh}ciiTg4C^#v`+RS&hP;kmMV!M> zK08*HpFoUC@jRQv3M4Hc@1!iPcJ7Q z>cagZ7f#^e(Q=~(pjYRPWv^i==16lU_gE)D17v1h7A{23$lU(d7&ADs7H3)S+aP_E z95;?mhTReZV2)zAn5M`Lli5wSGv?jt%MjvP&$E-_(NFI}L%alrrjAw(t%^SSEHOaM z`h#i#{Zroi-Y%?1QWqtso*wh=LH^eqjY}+kr0)CoJH6$5?HePK_iIqQTnz97v*){v zYwtL&Y=g1ctMZ8r!ysfd=!{55v{O4hVG(|A7+Vt9J=KTSi@vQv#O0(dxdGa}=B-yK zuB~is*YbP=javiIsK{64D1Y5)wk}%UK8ylx+v`qvUbG`aw4|<`c^%X5ocbK!69|op z%sD~j^|a2%?7xChPV$ogCW7A?37(Mf&-;BMeRM=HoHFkL4Lqak-rdii4_6s+le1G# zwd)RHNT)A_MQQg3>?!ucK~9-O$zZ3xnYPzwVjujIci{{qlkvVv_kk@k5&TO3ZX%KXB;zctY{}$!9HD#g) zWo5MF11~AAjJSGB`BGSppu)vsw7)Zx6F)LVW9_;(opJ#sDJs}w^~Xq&CZ8?V#OM0^ zca?SpQn61LQ%((9oo2TM@P$G<9$_+x(rME38G8QH*%RRK604(fb1z_}TXO z{Wfw73)GPC^=<5?Kn2Ok1MD)kR=le-gXZBOstIn!?*v=|ApNGQrL$g`bo<%;L$^w2 za1U@jt|zPc>QIPvuZ>P6%nl~Y5&fn>UGMLkdVA7s^I=R7F$vnRe%+)tU$rkHd&_^Q;Zy#bKr+ja&ckC$_W57Azw zyllx$bx1XK0t?^dDo1yW?k7o4g9U9?&uH2GR)l+3J=@xk&Hcct3>G=eGASPKB8}Vm zCf`>Myh*g`n&%x0eLTX|$L|QuRH1oabE6on+AI!}y%4@`fxtc{eGlD}I{8G=#c+5b zhL6A9fqDz5g=^925PYvJ1tkqdRS@G5b_Crzps>BPa-OeY*_Sd0E;Lele48bskBwY~ z<$pzmAGG`0Ka7YkRaUWlllPQr&uT+fdOc!8%*>wOPlyXMF5bB?Q+_=kIuUxHjWD`Z>@RdQ|IJK9IVoWx+L52pS6(@Hq6g2to5^*-T#BxfCGcEs=&$w?C@r1*Hc zB=e5k8>6gkywVwx9uqr6jaC0A7dw{VyGtuQsk0j8-X$0Xdvu$uBwbFz=z*jiFlkGD zu<&j4_nxAkCvpO9sG$!e5-y9VI`-$`IJHb;Axo{?MZIc>z?(9bLZNdD9#22R*QN5d z0A%$`#99m6G0v5b$Fl%DPRP&1a;9C3QnW1iR$Mdt5}6_)g?HaS^Gk}8Mvi4(Xx(fP zQ21D1xIES*^M%v7$?$_wFFU&}(Zr~q2ZkNo7y4x>-`}?lb9P%QS0lp9-;Ab$l60r0 z&`u2>M(c?Niw58kG?>D&kzU@UYvS#YARhImMe087Q#tMDw-S2S-<+&$+ztb}IF22V z%{0b$+X1SCv@2$45_&H1SR=DzO;3s)|f`&&^?M8#LA&)yEmD@cLd`M$4xR6GH<$QyGPo^kF5gZ|)yi6~+FDN2VV%r=8|1yF zH^9Z_wLe)fBlUYXvd8)Uz|3klRtD7TZDV z{Y8;4Rnn>K+JnAl<9wg3@!cabuVDc7J!}}fCObu{fFT}m5oJ=u&ghKMwnnF^L>;N` zWdPr&0n(cXD$A*B%p6T`VJp^9J1gstznxpZt!#{Mav;)6zE@`G6n64?C50yW=^7hi zZE%ro582?1z-x(fmrfvKYT^-Nm#=m;&KsT4D0CzEb1riU}Q>#x$}-Kg5$>Lnq0x7Rl)=O^k4$U5f6wnD?YS0(wVe; z@pyFgN<{0-5{$+j^LEd_=}fg*YK`cKF3V9>vL`w(3U&VAbXG3gTzRer*nafCOF-w! zhf2-h-6Vk;soo~cnm+{d5k0I!JWAzd_}=P_Osfo}TwLfJzizDZH&~_~;e0PETQ=|G z^YYw3(;j{PEQo*KqX~v^M7i`Ne`nyHcx(r|jLhhKcNtT>iS&sc8o=Z+Nhll$U;%&5 z1vh1r^LH4}W3ier6NpAeU4OD$fen~DIq|d^qtZXAkNlnsozS|cuW$8)S{eNiaf$%^ zkgmgMEKefey0Vh;;Kbd*BNTayfNEL;Z7EJx?{$^`Vg@1x9PTjeJ!)v54VPNry<9u+ z6{N*jQa3r`2CLG&s-8P@wuN=Js5EDKcA{!ef_;Oh8|8K#n3_3L&|wqLw|ucG+aiSD zm7Wc78v5M+FK;WYRJdcrT_jZx8QnUj?*~EIClm7+Ay)zX?uZECv_5>bh zj-np%>saHZ2+=U`iRE57w3*5$&*WxiZM1$jxVO3S;*#ih62K8?gDKXneb20&_=V9k z&gPRX*aov_@tKWir8Rs7jZy4NkLAPx3B0*Gy}a4;XyWm0*#`(%?PUQjKAh{S02BXB z7q}M0KR%3#G!aV$CEp{pg~DzTs1!SpWe*CYFI{js<_NjT?l;R<0W1XN!mC>K?2*F0 zH(&I5nfHt^sV=Ho@S#_0CPLNbq`D$-kx&rA>jOXUH9YfzGE8q%<5M)HJRsnm+5;t;UQ~=l6x8QFme2p5_Ik&LrGd2C$q*-9OFsSa=nr6;U7Bf5!UlDV(7c zj(wlAjDKuLvj}-pI*Qd3av=(~Z0zWXtF0Un0}V{oeg|+d>OJ9(bkpD6MjO$0;^7Rm#cf^~YM$fUGrr zo~b&0K0Y`l{ekzae^m_UtIYQ=mygJ&wI6;7gU8`23(K4I>H-E3(q;Gq!N_yS0OxSdPAbx0X69?6oKkoEYjgK1RqK9lVD;eNtGVCxGp(|_$7OpUIg*#29m zr(0~<&NE}nASARpZ^OluWbH3umsm1WYmm%}TZm&gL@Uk%^0|Zqeb^x3*uhN1!t33_mDbF_?n2mFu-1kkx!Sc}caH!p^(iW=Xa#4bJB}wdGVvQF{ z;P5hJmoUQ_VduBeVF@g>S{mzfkQzY|1aGk8pj}3vJ!)BUDfTaG$2KHHL-VcnzPi~T z^(|Dz8sV;un2XEn|KT+Mf-9{)H}T(%5Zioi&u*XX&geADFlvz}<6ZMBEV6{aXF8`w z|3lBpR{7!6Lt9kLKlS=suTO>lQKK5j1pn6AcLHF?i6&zIMr6>JjT1pbFqm+VgN>F` zpy#dXKWLhS>Xu^(|I-%pwZV527}c)^K;PLMRfdEh(C?fEZ1Ec{xzxk{vq;cbL^ajw zkD@6LHxBglP#WlbzO=<)a!0O8lwC7aPHPLi&4H`3;-Dg$llrHJ$GZ#pph@|=>VPmJ z6kHz=3k|JNDg z{#O7dl@3Ih@Alj}SufeSWV;JrlmCm^(3L#V8_F<|pZW4H)W%^0r`|^JP4MBze-^Jz zC9+07H-t+XkQsQ*o7aaTOH|+t9jWMs*>?Y0lHclKS329ef8x4atQSAVvT}%#eKjXt zq2d6E@xcFiTU>awBN%7s3r{3PK>lwYS z!0-DbpYT)NN0$e45O2EI=2TJhwMuBI2Pq)>=wsqBJ-z4?U%FH{cg>cei(50ba8I$X z48PZvjU(6(DysR^>2ZGyim391%s&DgWPNTb^kPSy9!0Z-$RrkNetTxTmZaK%-$XI{ z&TX0_>6mv|s*O&o9qIPgKjTq2e1G&${22YZvWkk7tSl7|&z%9Y|HZbHkFW3f#YKzJ zVOeKARFVBtlEp(?9|H1hEjwQp6#^a_LYM@4)$ZQ;6_`DR9znTsa+u=&{vOxEXIeK2 z%p)ypMS~BoNmNWFequfb+VXrTZoI!4eCy^eKR*;xlNMS;;hADDkRvJiM@B}hMEjrTMuS$N7L zozbIr6J|Stcm5>t`kNk(yUxB}%3w`%{ey~~Vc>b2W(&5X0eK@n#gAQoRIV>}T zTc3a1c74NYqu^TfA#d?S0CH#@fj6HXwb23Pk+nJ=niIbeWBIZ-llkKMD*Hqhwo|L& zjRLAyB&&Ek=+6Cd>NE-CxX{~|)c=YxHb9}Z2=DeIVDarp@oZ19tqL(r=f zTCJOY1fK>#sjiOH;o2?7Y1=Jd&x2d8l%w~o-|s8ZUmUmQV=ZD1x z+mYR|bjZ0=I=6kH?NS3Q0>V_K0g$j{{Ix3X{+Bh#U>b)znJlW+I6}|k1Yaq?b6!iI z6j(5D$CAcR;$^)SNMi1!k`1Zr=+QxsjZI{faXlRqDIa%Z{vjSIZghu|JtPi-de!}{ z`HMxh(=^I^P3w`j;yopbrREhZNdDu-SL34Zmh~#^y?pVqxsV6b<^y&c6Y?P@2DM$5 zo337h*`tEJdV&nPRkk;Gl*cv;*>II>(n@4`T|D5C!$aFKf$j@mHP46i905#Y=vrcG zFH}S2h}MFKvx;`2A_nq@@jn+Aebu+OjQx`ZGL|bXoF_|-7F~gG)1?}xH5-k-k2k*- zU2E9&>Q|FOC?CD|lv*9+G<(3tx=}PB6t?|`H6#0?G8{VGS*#<`GF`)6j2%D3k5%& zR67hw?1#U?3#&uj@cSkBdIqV5lw)&tJ6#*zqI^$@hSq}SDf5DJS{nxIyvJ}rFtj!= z?4bWkR9c933pLd4E3UWz$P@cm8YjO+)=a6!RK2x^bON1YPp|=<wrh4kPTi ztTdSC$Lz)E2S-BbfY&qGKd9?pUqY1h{_Ig4ki1DW4AbRsI&5bo*+N05!-qGM&$VTv zhZQ>?$FP;SH3XW)eOP9s=|Ww$2ig)B_6U2DwK~Ee9^tM^N<-det$%SQeZJ0`l^;zU zEB;U)xOX7v!|uVffra3d3^LOWM74i%GP49lm~L(aVq`cn@IKa0fg_WJKz~!X;TK3J z4ujEF%5}KSL0PCD8tqnUiV_*r4udQ50W+`q}~ z_Gilpq58scHSWfg9a=sR8r9h-3OoXL4Mwz*9^ZUK^1mFzRk^pCRPD&%_|i;U1K-7< z9#|`*HEP22z{sVMbN<9;ZF}=wbx#s7e0bWik>?(K{-jg8;5IJG-Mrd)koXn7b^}X7p&0lsWBsb^qe>tN>##$){(vwGe z-rQh<`-W$}e{@9l-qgk834QURvu_0#$%K9ly`RDZVtw=ckg@eN^J}|xIx{HIWVtT; zby5X<=j2pTE_w$;X|1L(I~F!behgbyN{$>_^i*;8IoH3V9nI#4H zPQbtf^@}^TaZKl$2m;%BPQ|iXHJUNF6WJYE`oDIeq?y*oPqp z0uEb==q%;{LF(_Xd zsaC~8KQ&HhDW;(YjjtPg835vql>^637B^jwc{~DBre%K##dL49!@N$wn_V}qh_#GQ zf3xrEGK+_x5zB^*Z2#;MfjVBPm8t*d>jJ0$9}!AD0KNn@MXH~@)G}8NO%XGT5)bSsPWU+|9Ei1FD)Pbp5#GPas!_{AwjqF|yOW zGQp6)150*U{1zaXJv=;qd+hWXcNtf2>mZKL;TRT8Ntv6|h)*ItQQ!z~YfJJ})cy$!S!FeQYkT-2~O)t zV<+#-GG3^wwaf2u0xr$4_iJyT_=wQjC~=y5PUQr#|Kn#9AE4+yi(LHqmu$pC6m@)_ zZI=S&!v)Kq$rAd6)t!FO`yctNJFR=el_#^phxm@i0H$hW$7$`dG|Awf1j9&%jTyCP zePrJO|DP<;5CxLClca*I;4u|4bKHE|BS}4wfbVxx*B`gR=v2t~!(9;sbURH~Lm} zzgY!nMRpCeoqZFl*}?96{L{%I2jgz1{`jMT-^=jN7qFWuPe=B>KZ$A2 zv8B)4gI*SM-jUb8Q2gsun$&=mh#pr{ba~o!t=HBE+L{EY&@Tx5WIb?MDY&r2QwL5V z7PK){(GemzD4jd_QSC1H5p{?}1G#L_GKczQ6~e10+)kYFT-2MM7CJ3BW0bwBR^vzZ zrg~I#oocZy4nodx#~fZ2_-|R~(Gez;ET9mNm&3bOL@rr+YcT~^%S5AJ=^*<}pI&lY zLuB4$Z7fglXYh}HYRmSE4jWLYr5uKXFhJ41_g^QBu;U51-NE6h#>WoPGj0Q@oetLAO`0!K~eZXO+ zFn*g7g789~`03^hrfrpH`vNXwaUer*)x}O3{;&6CAe}931@Gym%deY7O1L}+w%#&G zse|`;{th(Ea{;sa5tpU&%?;CRh5ObU;On{Np(dyzBg5+&oK0z$s_Vys+eXFT8S!(O@-DOZ@_g2VLtEeI9j zl*$Du;oWny#`Lr&4Z`v6dtT3q_s4yB^C}!(sl|$2-=hGP^YZn9IaR#hs+8_RlEBnF zAet;&N_^H1?#@H6>FMG0fX{{6(ZW5Gf`dpPF8XN4Cm|ELf5K_m{MH|(DrF#L_7=Yo znk5e#J<5}@HF0_w7z?5W84Xov8bd>3q&bdf6LEEt2S^PUc(kKm(xsWx4YeAR1V7gA zyBkQU`?V)9kLPmy67NX4SZ_e+&JQ@NhrCfc%`CefZlr^8A&eOsa)kJtUR>c6km&YD zw8~uRJD!)!WvUo?R8H*T$?!mBQMk8Cs#WDHuC5w-8gnxl z*a@oz$v<_3g(ZPQz7WYz1Q>dXL8p739!<;q&gNiVc5)!E#ki@GYAJQ{Q^$412nvG= zs}K~$lX|wO;O*9}XZchP#Mxm*XXh!U4X5aQ6)2zYmw%k0&AzMl^0FQ;a9^p@oO=%T zm;YMiKMpK(dk-ZOM+I|c-$Jn^BAUEc*|hBP?Lb;q_BdnI9 zCq=FM&nFY)U?sAK=+};zWy;i&ljKB1cPjQ;IX&N&5lQrjM}E>OPk2&0$lsHo3#*hq zYN3bXkdj+y*e;9(ISpY=E#L)77V9MMeofcpu%G}f*94i}E)Uz54=05iaE468s>V_3 zXx@!0z9cHgKd@0Vr9UHq6i#|f^tQ;J*(>m`a4uzpr)}or(CDel^y=eM<2xubg;cQ@ zx(y;WzeEJw?444OC5K$;m1u_-juFIaC-e+op>S!uE8$fwry)+`%B`Y{?>k7RNBK31 zW;OvEbnJJU>qfM%@{l;-3Qxum^&4S&PD=uV?uW$7yJG(lw-3}O_d1^X4$=B{;aK& z3uJ=oBlF8Uk?vmqz+0avfDXJB?U4|ipv7w5 zmnNGl?N!ffofjVsb|~pU5uV3YYs>q=NL~K&81v-kFB0t8dw00zwH`a-`)T4s%gs!5 zpP8?{&#&?amA+ z9uC{c;(NL}@6+LT07H{38hUjHWB=5S z%t?vy@<2WAu}-Mo!5*j}-yDcFlFS13C1K4<886WA@7%7lL&0B8y=C=`*(gx3)Jsn|zIV7QuQ)mX{zIBUy9=>B93W+E6jqb@3%ub@z-)gwOZn_-`=b^|6>H`5f z3#i{LLT!&4|1?>{^xXn@0!`kJdZu66k@g>D+HXFsJ;#pFE_YYGaGwuX)4y}1)96U; zJ3VbqpE}Z@xIN0zby)MaygS|@!m2%bY?|sYkna}-lW?T90rf!$dZj&SNXuS5$jk9= z{O+pgp$wX%7DL?U7rymInfPwQ$pZ<*1JxG3lHZP6&EwT&V z;P=%vN9oz~Hc#K=wX1TJII1BipR;dANXb4mm)>x-ND2fJF8RgRmnQEEFGiD(=nkEr z_fAKUB9cI6PV)4yF}L^r%~m#ADTuZV>HIuy2f{c?I02MwY*f?<&!3g!Fpa|)zmapj z>htU~JDRBwTN$)buOu3~)~GC!h(^0QTn=Ul;kw(%SNm|DuYlL`YLZ3JXbI!c)+veY zV$43Z#SkaEoH^%*mGwho*pj>J8>zkYW}RW-l}Xm7t-@-vIm~ZdDzKvVT77kD1xv3S zoP=Ld(O?mN?hZ0FHrbMtMMV7edR`a%b4ojR*X%=|^$-#nYdxj^p%yX4&z(^_j4$H{smtDu0Q3p+XfSMlm!V9x&Gy#86En?*&b_=2h8h?lteg=+Q!FQGc z7lt*DaxYcn_xp48+6(?D^;Sy!?r=u|v)&HS)?+Erp1vx~4=yF}rjP7$aa8yL=$~Ry zq?5;rf`sWWgK;n;y>EXplC`=gqnEBB4Jk_FN`@rG}Sr)L^3G8OJi@?Ss81B|m_ zlWd)w2cciR)@*lpQwqFwR88nLQSo zqu6{uB;c?#w3hD58xIOmFms)0cq+{`D$tqqJk4Yq{T4VmFS>XO_?%aI+@qBq{(6ue zaQsc3*}OkWA@cR`AzkZ!h->xr_@u9Ah~;@F|2orhKiOg=* zdgh#`*Yf+CF!JvK_0(@#)G=rpZ5Sx()~V%F+nz_@Hl!35PBljbxMIi<7T~V+-&9QtHA5~i!GQM z+#E{(e!oLktn*6)Skhq`p%BGlF|gorprq#%Yl@*T3508LV%UnFaQ9deW=o~8d8_(()RrGQ%>B;2PUrE{dccF z-;P(59Q(YV?jmpI)lVOXi^ewHV`LvP8 z*|ilV(d(Y*y;1lH(dw`Q#>S`UL?tfMbV=xg=C#u0@8l9(#j+oeF4rJI2mC(zRX%8y z?dQzl{sjZ@MO?*l%CK?Ca%S7ZHDOh=(b?S?thIXhkpc zjm?jxi8k;Lg%A zVhm_Gnzoulw?Ws@T!=TU{*y8%)P>f|gr<3L_z=sg{%N}N2updLKnZ8qTGYmuYqPa> zmoZh6_PxjpC;#PHr`#p?+_}ZDws-Yqc67RZ66k_G;WD?^pmeIkKHM4`vDt=j-E6-` z&m!vXW>1?NAgWZ{mGw4Pso`3<-aTIWnx2SMV@I#LwTSAB@O(|cB(Hr8WGtDgHyCaF z8-0d4>Ql>qd;td7PnoES&gq|;Rdo9V-SAcLT}~x&5HJ#3vofHB#SYqho_&3=u@p6r z9PCcKexFUA^(_;17xjyW6esJ8y_sPZwh<@G!+3=%1=kn^6ZNr2W8N zh#pV4m74M=m;O{;_g>`Xr!#*%uO-f_gN2~MkuN-cs~>`&eaRFm2*=yGR|ZF*v0>FL zFI%1Wukr@uF^S#jEcQ{`n>HXd_*cth4|@{dc|;H26gdr$CmL-D2~>Vjm2a!!&jwtQ z;rgjZmJ~yUkswYXDki4H%OxsY@Vfi-f_9MbiEd+`u7sMTNiG54giYDl zJ9*8z;{J@6nM;(!s@va2+|K}uUBxDt8TkRcTbG&jOyJ(Vuv}M_l1#%&<9ltz1#@I& zPgKmvo_cgi9u|TXkMN^aWpS}rjkXKKAVIUtvk{fK3ikerMvr8 zL{-XGvhu~kVXJ|>?_So&gejbXxVyfHd#x6kruBG#gw}WA{jRO=s-vgfd>dcp*as=a z?l)qwC#0})cRe${S^!fbl{p*ZgIu`;_^&R*kslJF(rz}+A4@Oh&lK(sTRF=XQlw;M zDO}Syb1$p)B$p6+CY+PYOjmO=A77+vxZkmQ!@LpR-V^_>EW!djF|Hx?4Oa?hPi?Kn zr!`oKyy`lASKVEv+BUTn{DM2vl07WAqOfxE-g8FVafXxDdFB@IBSAVl-L4Q6b$Y$T z7pck4Lg<2?d~&A+;=i{!I(pE!TuvpX`uB;{xAykpKXcQU6YRwo^(Hmbq zXpe8`__UI}7ji2RM|CiVadkAuipdgL#+q(Vb(7uTvh^H7uUUTG zYbvO~n9>%tqaadcxuO`vgcs_>`NH11ljt0 z(v$S(NF`kXq^(QhZd@*=y|QivJBc>5_lQ2lo!V zT;VD=7VOhIXuNIFvqk>(M=I{-HEA0C@2B@rr!pTgFy6j} z8>%Ps{>n`LyAYw|_-%}C_>UiSfn+>9Fb;IsaHvrMSB@kYzx%p;*A^lnaG}QLLxee- zU0vJX|8zl+4RzG0*PT*c`fVv?2I z%YQzsJC|a%Vx==U0_Ec3!uIX&8a}ArfdQpjFITI%3aNs5O&A9wr8n_~qh#g!dT6!_ z89`0M|G~=O7^~q{Fba)aYS%{Q66BElP6NHudd}{5Qv$9ZdlP@@Fy>bmssxMndTZ{d z!{$>BAcBX8I6SA7`t9IvH08snMyAay#KfMLo(@!!1YBNR5a0YIz^Y$8ANzb1#$Pf2 z0gVpt?~?wH5tFYM{&I5SBxK#;6U_}w>26CT96}bMV+mtG)tT_{WrX6#ROs#)p$cQo*NFSIi*X=$ zFN_+lq2%|(2MB&Tf}OEuKJSGxjdP{i_gTPz7Po~*F-DKuC~pt@Yp)Ix&JY>MbgJf( z`fp5pqyYf3Gct&jRaE?E9|*Z@$k^Coo0@oF&MGT-qT8MjG30cmpKfkVruHGXtp_+% z@o6<8S7UlzL36>Et5;%WLtz*??LuSGfXp@0wcu0q1T@yCKns1pWT{doB&)_;kXf?R zEV+~px9m-RBmTuI_o!a7oRKW2mFwXM_1;a6ln)d(`*V)9hpD=d8mK)Hum=PoXZsA4 zI8f9_3uY67J`I+TE1VB=j|_$ui^oIzZ$50HE#OSn76Hd%xChwX_28RTX$qteQc9g)uPp!W8i$GnAXM&q|pV??#$ zYUjJivaJyW@J?~%ZVgQXc?juj96|HJD9H#QetATeK7RKYEGV< zt1ZkmyQ5bH9nkGux@oBhh@E`8X2N?BurFt3)^Y4QTD}}akk!|dK4ED;SP=*ty9Dm+ zAQ%`5^Sr{YwHh=eArMUDtd`>~(_r;#sF3bDW)tv+u*;4{dnElP*H`PT{`bggrRqCP zTTv#9b(Y?3t96!BJm97+NjbTllF|x3!=t^%85pAJT##51`}taB?K^)#XK_@sak@}Z zjY9EwG$O}I%Z$kebuG~06}pFDdq7-DQpO_)IK|ETy0Co|HQIkDtx|$*V-)9Vo*-b( z9K-cmPhh&5kI5sG5d0W)osRq7&y${*z}|G*TV?PSrotop+_g1SY+kYRFV^1u1_8yu z5!+w>OUgybvZ`XV%;_T*vG9n;rTy)hk~$hYx9jdKKWo0)fpD;aJ0ROmYpl*Qou|mn z_5JL&a;2+x3HR|>y+s4H+lXny(=`%}Imq<54YQ?T+!P!a`2n+>wIdMF@B?LgYOgjL zPa{rR`3=Ti*e@1>3aLb+a(pk_U;cEp{a~q)^*5=Q3`7A4{2p&kWUQdJqV`xc3*EjmgMT!`Dv2Ja?{SLM9R9&JP1W-;4%P)3aVp;3gXrL_PX^h1R| z)zFp3dAB^Ij$moT#*3#s7v{Urm{kZ_Y0x|k@yMD?o>n1!JxefID#6T_(Y1M@kQ1SMy`{)fgRQ0e9eqanX6E?s+r}*^Ev-cb z@n!uB`tL7dejSm|;E8>Ceze!w+gs(gfm%(*w3;fp#jiWm!y#y7O7HguwRc;TI%z>B zLS*^DuQ6*cp%4cK;_oQ?zN%OqSIMFvu|Z=eLD*TNjVV5$A(K1PeA8m+ZauL%*WCY#O|KQ;MONmWm4GO-yBe1?>oyLUHl{vG0tPjxNQ}a^>e^Z7WipX1v7LZKC*uRO9YB)@-70Ir`T;;eg=2i=IIisXiA(% z>Y4GTw5PXDFp*KgMx=f}F~Y|MF}~rrN_S>9<2l;jQGAvFhdFH^E)@%(-A{;+rfoDY zbJ5X0*%ajP`-Sl~czw0qdkX09zv^|w9L2kf2h|^e-*ZruEq}6DkDhjh46K%_%1w&e zZN?3`1jp=o+H5Wo)6@)G%uI`!LT_vzPDi2rm}@{f|FC>vDZAX}+Fi`u^t=dkx?UsQ zx)jV5V8~$`Q_c(U;p&?$a^4$v0WU|fX0l*AB@G?9LpG8h8DEY#x}yP^9y+8uZPpcJ-?64 zFIe$;9LP-iBaB8<*ieXg9CYr=Rf@(xs*nQ9$$y62?zJgcoE>k^_C7a#_pDT4Z5xwfzm1WERqYtUb zZ8v<6rsm)pp~>4whd@-F&Gy3h{bst;Zl_~KO- zXBp6wEs1WU34c7TaeMebP|*0pRL>Ajntxbu4lr2|LYj>(UVc`#Lo0c|-EN=CZ^;y% z8~>|2EpCQ8$$(mPU^ZdEm;MZ|KKwH87ns7zl&<+U@jCv;%4J1oH1wxO&RwSLp1C9W zor)uf@bXXhJDYKo{&94yunO74;7p$TI%i%==574n%!_5?1ovbY!&+KOkY-z>g%yfbx;k z-f_QSE|QS*F7h8w^f2TXx!wv0yTJH=kL6wT7d=JiXLDPI)e-)~5UnGu=e4-kQ~%+2 zpc()!K76p+e`*xp{g+wL|1~)Ow>LG1*-6%!L9 zY5y}>A>SE{!!OZAqU`sisl{kdP{&mkf51^8#{U0`{l5wRRJtx9T9fK=8!6C1m%TZj zeAzuCq3jtFo%h=Oa+>oCz6M6_gV`649};6LIJmVp&UPIeZ*e3zcQR=03JrX)kx81< zybH~-gl@!x^`}d^uZ4Nz@qEU%WEsn))*j&1xMGkz3%=Aqkur{#T%Z46fqSfQ2O9iE+r3zo3~+v7EdZK z+#6|QLPy=DLx44wlwA5m%e(AJ_%Lt(TS`Wclf@+u$`j*YU3cun&x&IYb#{7^N@E06 z;H@6UVz1ZLZ(-N@&OZ+%{S}2@XwIux>PX&4S~er&1M`C@-S(Sx1_ky_|J62y?->jd0VJ$=r*88)e>uW)Ay>2e{ zBm-B?yrXF~7}_MS6Rs=d(`rdVcVkFSia&lh7!GUWx`OG@tI8;I;6QRsn*xs_H@7)w z>LnRWVC|v{X)q1bQxwYc%kvin_7V)4Z_xI5x=y1^vR~3gR*Ii+`SP4@Vp(Ql z^bIG!M5hmweTLe!5CUbh5QxVgk#6lqMnfDBUGhWK3_6BN^JuC*+2S;RBvPByo^bBe z%2=py(@N35;F?=|AsNAJbyzu(s9sOaiO_3^4ZKrL%l71*yRoU7Iy)nMOK-gRW$x^( zOrRvwTM&1Ybi9_``IFl-u-WOp=gD%P>0(iDaNVu;4pdq@MCie&kTD(e-2sMum0;XE ze%J1Cl~c!MeY$qMP-mq^knYaqjAd>u-F!5qi@9;Ro3XM@c&0>6Q0up7^_&uKcoIhT zd0bE%6J~ontNRs&nFhN0xKV!#rnGVTWUUIPFz=Ly-Ou=lJ3G#tBthPn!NT6M`>1n> zXDEaT?eu)tIJs>Mm_;(QJSvp#rg1rxsxiHDA)hwcHRJjJ5o5b0pj%OmXW*EVddXKAycHWLu?6ZlAc_*<%6J-n= z)GBxDU9HXDhy68e1Xv187@3U`?j)XJ_(<10b^5Og7D`hdpZq;MJ%<#^<}{6shi_;v zW=aLvxwA_wuZyurF|bq`Bu5`61R%3Mxrft5ZayfYT<rhrAvFzi$v;` zXXOdUw%h@up^*hE z`F+%owX~%^t?2HkB@^oRDl=TKUWA||Q^nDHNI6izSrNQHi9g0-xY76vr;GdtH@>td{#yNj*Fs@&8 zq3 z{ib<;k-02j4#&QR*A*zgH_;-X1|KWi;POa|o;@A&Bapi7!rz_EYRao4y%CLIdPUu? z0M+1fdd>WKon(Ev5TDvyzsQ|B;ecJ+7cKD@vEt=#pklY zgMmj`&vaj{rq%p&=|CD1sTwx-%^hX48^77_nmO5>Xzt3(A>>*v*0T@6ViQk>01TEa zmiRs@5z!A-e_-?U^z?4X85EzKGl!0uulaB7T4hvRL6&YTKnOH};2u0!kl;@61Pu<2 zJ82|n&=3Ly4KyynCBYl_;G}VP2ri8iq|t3MbI$I}&Ys=b*`NF8o_cla*1fOneqY@h zs3A)s6!FMH_*-*(+hc;iNH>O;W-Z_qZRmWHn!vIk4*59{{)2iELRsk~jHCQCu9H7k zwZLwDy=QbSG$A(%)HeGvYoSk=;nMy)QtCZKA-f1QszHCx6yGe-KZ}#7w`6 zIoGFhV`}uIYPXA~(v4dDX6|Du!W#mGCE$V209us1cjP=XHDvXYOZ!ms@mmaAY#nV2JghX{*(x zIf6*LQ+bIi=vpr}-v*oUuP5TVMJX#zpZVEJi(-$U#DR_ZJ!X4E?=}>yO8c`ty-_6e z)Irp;ak$P=s#q*E%dc&vaR~wfuA!1fAon0af||h<%1(mD@R+VoFQPXR#M02&IEAv> zuR_8#?VzjkvwB_#K+p=rBc)B4PP}C|U~sNCVWHUZukOyG#m{4tad4 zytW{8uXJy#|48(98s3kslYi!%=xjQr-&sb}SE(9p*`@lZt>Vb?{EYa?W=tZ*hvNgn z_{JE+Og^TlXRIg=iym$i*k`+HuR^2Ipe#S<`iV{Km%v~zptqo(vBaz`utk|+<>&o% z=3Yn|I-HqB(V>fbAU5=wes=*47j2?V%5NK09+a0*MPn#R04zOfGw7_uHip>jX5%R! ztlgV5ERcNsn-N9;$B9*CagzxDJJ`#FeS8O*BI5FAlv#X*@?{?uY!-^is>5r_#Q`k& zhu&SpB%76=!p^hm^e|ICp-RhcN2JH=eO(FDy`FHG#8gu&z%4n0Y@X#;+e;DAnj&6y z$E$i0y_|e*DJ=|8-)B7S+{Cm8`cuqTG_l^FYswiag56tEZQDw9~blX__g#o9PI4uQTfXwDG|ETbo-j zZcHZm!qDDLrSy6!QyXgNo-gA^6}wAFUxe%KklyQp!~Sg7#pV;0$(mAS3&f-RVmwXc z&hZ!g_Gww?5B1qax&3T5=aHke4t=gW4HXGFaN=?(TDtkFnKHp3u7GQMSa^F|_8PpP^bq07+>}G?$CgH}4tx z`KcV(+0ava&#T~6FAraAZ0m)e;V;BjnwXi?no^IIJ_i35@xh^Ivf6cTybnA3m<>l0 z#t)8URkl?!WX)C-iWic!nbX?x#8UB%pQjg;dL=ny(Aj}RL)&`B=WP*6C!p0GZwV`- zH)5BI9weKS*n94Ce@|%WmA&?68xb~|lCv*VojnSY9!?dBp6YRWt=aQyZ4aJC8_HP+ zW*8m(EnTuZ;J3>SwFQDYIx3IdjW8?T*6-HCw}`MsvHvnKe)!;3$T#(7VOc=X&!Isk zu17IR40a4X36^EFpDuRd3qihceT2hcZw@I|-kTgHSG`})ib0TRDi~guPL7gcdCB}d z(GvG|y|-S{ohr3ZDba#HBQMyFe_PWUibyh7T%_~i%-~5qMOk|xmXZ7~~CD}haRDTn!qw9a`E9&B71c*)H&v7#q&%-4+w@uxf<`=>I^~6jpm+_Cg z&$Oq{d>)9o`guWN8{u=e-QnA&(mmJ7A%h~W1(vEeMl(z57!a>RSWgm2BUvs{?1#i0 z*fAl~wXJ5Vda&`W_rW_0dQF<;M{#?%5+lTk(3{tr_mP2%IraslVPHe zy_In9SIU1D+D$_sIi;60Gw7>uSpRNyaetJPXA%9jniu8jLt<{QGfMMZHyS?7us2uB z^r`yk*2p(;Kx%&T&o2V4ru(yzYY&`rDP2f!hD4%QDY~_q>U(2p@IFLY@OoUlYvOU| zgm=U%+RcS11KCPwUs_cjLYA9^?H+6=d&PC@t(+k$>HwJ3^gT|0!F#Mx?b)_o=v^JM5c5pl|x}!)#oErFDCjfBQ-wK)xaR9* z(A$t2NpZPZ&=cPJG6SR1+M8m(R|#J`3BO^p+^ZT9^*ir~nARn3F^4&-Mj464`nMip z)Z?a%v9o4+4!i>04HdoOxct1(AjQW$g8$M*_vq58WieJ-Umus?GaXaDg9N>CGmQ7$ z$+r~k4B;b`tbSWj=gpf(8BL)B*sq0(4Gcz=1j-M?6YEa1&UGcx1E-BjTLo|__#?Pl zuVYcr9+caTF%41N=c}vkA%?buH!g|T75qRRImZQ+kq1u5}jVo z(MYfd_C6G+sm|POSvN1+hzi$N7mDrMm3LhK@J%Fm(m~s@V7NgBb0w-Fpig8fbF?_1 z4>S6y`67Bg5sgd+;ZSZ*oFjs>AWljCYg^v>Ie_cpmcPLF$8dcrYvkMBfK>2mgfLxT zFS*>JyNJx#=J68HdhC3~eU1|=h$pPj4W4c|!4Q>1L|=#4SZ4qEwXcqd(N);OyS_pb zwBqPbarW^bY51IcU%16|h6i0zJe)1#hwph>&0A7L;IXESj1|EqupykV?;sj2njn zLDNZ;SlgeVVSiTx-lDqR+k^hnicOc&CVk23&X{>s!LW1wm5b*NI;y(>fj)_SUD{I~e3wX}pU9YejM~6G@oy@1UFr~WZFk%GLUra7%#twDf3Z1SM*uzPLsfTn9-)4l!&ku{`CT3b!JgC*5O^FQus-LtE9fLx zWrtGK{#fbb``_f#k;p$+Z?wUIqXn2fY}ElfJ0Ee@CQp`PXaxkV6O!qOFKglJb;MzB z0~o4p5S7$NRp%6$4??Il2m@Xtd0e^AXvtPTt4|E|gB6>Znh~xRgG6ILp^jkO9P^&2 zrmOwNvs)za+s-rx9-^=iOr(LSzH{%uwb+e&R5~)~yE%5sAF$`!{3e{Q`Gy-=!)|VB^@!Vn#>!BiH*$O{ zp!kqSPK-B*Ly;nhhdCs8B3n1EK1}h>H>2D7l#x-0n8oTOM3vXmk|Ij*$|Kj$Kb7k0 zo%R^3XeCR!$3YXMx&%(3C;pMOsN;!_Z4Zr#-BIO^J#tw|QHER};oTndhLw23W?VC_ zSyr{9&4!KOTN+%Q!87l4Nu%(ETmdAmVZ7J(@V522cK}c=qd5uZJyZ3;4_x!%-zJcM&K_KY>*@K`9qz@SckuF!8M-f-+hO(O?qTF{$6yy$H0 zI}Tof9eUu3Sr{ry=>%lS*ogrblGB@XLu6d`Ds$+?l=CTTh&pdW(2GiDD2qh!@btl4uLdC3F0{xcP0+qVdsj#e@(zVi7s=M&BH%p$Yk-^6I$#AU8 zQ#c8BqMUAn1uFn&W9UZK!(_J(n{uKV4&vZtX6{LdhYcige@u03Nv4wtCiO!?x~iVo z*x0kH-E;GlT0z%2cy}bZAiBQraJA#oSD?i8aM+jo_a{UD&-wm&&iDInZ=PGpT%9y{ zSv5w1bELiFlcZ!LSw0ls)D=a~l{j<%hp8~`W4i8Srg~P?3Uv?Kon(YxYzS&_MF;=@;`QC(e6NiGwRvl{E#;5zYu=}DjV3$| z2URz0Sn109VbR!6B8C3&Ekij8?r8VFOeE zK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/en/docs/img/tutorial/bigger-applications/package.svg b/docs/en/docs/img/tutorial/bigger-applications/package.svg new file mode 100644 index 0000000000..a9cec926a8 --- /dev/null +++ b/docs/en/docs/img/tutorial/bigger-applications/package.svg @@ -0,0 +1 @@ +
Package app
app/__init__.py
Package app...
Module app.main
app/main.py
Module app.main...
Module app.dependencies
app/dependencies.py
Module app.dependencies...
Subpackage app.internal
app/internal/__init__.py
Subpackage app.internal...
Module app.internal.admin
app/internal/admin.py
Module app.internal.admin...
Subpackage app.routers
app/routers/__init__.py
Subpackage app.routers...
Module app.routers.items
app/routers/items.py
Module app.routers.items...
Module app.routers.users
app/routers/users.py
Module app.routers.users...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/en/docs/tutorial/bigger-applications.md b/docs/en/docs/tutorial/bigger-applications.md index ab151f8f32..2796d7fb19 100644 --- a/docs/en/docs/tutorial/bigger-applications.md +++ b/docs/en/docs/tutorial/bigger-applications.md @@ -16,14 +16,18 @@ Let's say you have a file structure like this: ├── app │   ├── __init__.py │   ├── main.py +│   ├── dependencies.py │   └── routers +│   │ ├── __init__.py +│   │ ├── items.py +│   │ └── users.py +│   └── internal │   ├── __init__.py -│   ├── items.py -│   └── users.py +│   └── admin.py ``` !!! tip - There are two `__init__.py` files: one in each directory or subdirectory. + There are several `__init__.py` files: one in each directory or subdirectory. This is what allows importing code from one file into another. @@ -33,18 +37,33 @@ Let's say you have a file structure like this: from app.routers import items ``` -* The `app` directory contains everything. -* This `app` directory has an empty file `app/__init__.py`. - * So, the `app` directory is a "Python package" (a collection of "Python modules"). -* The `app` directory also has a `app/main.py` file. - * As it is inside a Python package directory (because there's a file `__init__.py`), it is a "module" of that package: `app.main`. -* There's a subdirectory `app/routers/`. -* The subdirectory `app/routers` also has an empty file `__init__.py`. - * So, it is a "Python subpackage". -* The file `app/routers/items.py` is beside the `app/routers/__init__.py`. - * So, it's a submodule: `app.routers.items`. -* The file `app/routers/users.py` is beside the `app/routers/__init__.py`. - * So, it's a submodule: `app.routers.users`. +* The `app` directory contains everything. And it has an empty file `app/__init__.py`, so it is a "Python package" (a collection of "Python modules"): `app`. +* It contains an `app/main.py` file. As it is inside a Python package (a directory with a file `__init__.py`), it is a "module" of that package: `app.main`. +* There's also an `app/dependencies.py` file, just like `app/main.py`, it is a "module": `app.dependencies`. +* There's a subdirectory `app/routers/` with another file `__init__.py`, so it's a "Python subpackage": `app.routers`. +* The file `app/routers/items.py` is inside a package, `app/routers/`, so, it's a submodule: `app.routers.items`. +* The same with `app/routers/users.py`, it's another submodule: `app.routers.users`. +* There's also a subdirectory `app/internal/` with another file `__init__.py`, so it's another "Python subpackage": `app.internal`. +* And the file `app/internal/admin.py` is another submodule: `app.internal.admin`. + + + +The same file structure with comments: + +``` +. +├── app # "app" is a Python package +│   ├── __init__.py # this file makes "app" a "Python package" +│   ├── main.py # "main" module, e.g. import app.main +│   ├── dependencies.py # "dependencies" module, e.g. import app.dependencies +│   └── routers # "routers" is a "Python subpackage" +│   │ ├── __init__.py # makes "routers" a "Python subpackage" +│   │ ├── items.py # "items" submodule, e.g. import app.routers.items +│   │ └── users.py # "users" submodule, e.g. import app.routers.users +│   └── internal # "internal" is a "Python subpackage" +│   ├── __init__.py # makes "internal" a "Python subpackage" +│   └── admin.py # "admin" submodule, e.g. import app.internal.admin +``` ## `APIRouter` @@ -78,16 +97,33 @@ You can think of `APIRouter` as a "mini `FastAPI`" class. All the same options are supported. -All the same parameters, responses, dependencies, tags, etc. +All the same `parameters`, `responses`, `dependencies`, `tags`, etc. !!! tip In this example, the variable is called `router`, but you can name it however you want. -We are going to include this `APIRouter` in the main `FastAPI` app, but first, let's add another `APIRouter`. +We are going to include this `APIRouter` in the main `FastAPI` app, but first, let's check the dependencies and another `APIRouter`. + +## Dependencies + +We see that we are going to need some dependencies used in several places of the application. + +So we put them in their own `dependencies` module (`app/dependencies.py`). + +We will now use a simple dependency to read a custom `X-Token` header: + +```Python hl_lines="1 4-6" +{!../../../docs_src/bigger_applications/app/dependencies.py!} +``` + +!!! tip + We are using an invented header to simplify this example. + + But in real cases you will get better results using the integrated [Security utilities](./security/index.md){.internal-link target=_blank}. ## Another module with `APIRouter` -Let's say you also have the endpoints dedicated to handling "Items" from your application in the module at `app/routers/items.py`. +Let's say you also have the endpoints dedicated to handling "items" from your application in the module at `app/routers/items.py`. You have *path operations* for: @@ -96,24 +132,148 @@ You have *path operations* for: It's all the same structure as with `app/routers/users.py`. -But let's say that this time we are more lazy. +But we want to be smarter and simplify the code a bit. + +We know all the *path operations* in this module have the same: + +* Path `prefix`: `/items`. +* `tags`: (just one tag: `items`). +* Extra `responses`. +* `dependencies`: they all need that `X-Token` dependency we created. + +So, instead of adding all that to each *path operation*, we can add it to the `APIRouter`. + +```Python hl_lines="5-10 16 21" +{!../../../docs_src/bigger_applications/app/routers/items.py!} +``` + +As the path of each *path operation* has to start with `/`, like in: + +```Python hl_lines="1" +@router.get("/{item_id}") +async def read_item(item_id: str): + ... +``` + +...the prefix must not include a final `/`. + +So, the prefix in this case is `/items`. + +We can also add a list of `tags` and extra `responses` that will be applied to all the *path operations* included in this router. + +And we can add a list of `dependencies` that will be added to all the *path operations* in the router and will be executed/solved for each request made to them. -And we don't want to have to explicitly type `/items/` and `tags=["items"]` in every *path operation* (we will be able to do it later): +!!! tip + Note that, much like [dependencies in *path operation decorators*](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, no value will be passed to your *path operation function*. + +The end result is that the item paths are now: + +* `/items/` +* `/items/{item_id}` + +...as we intended. + +* They will be marked with a list of tags that contain a single string `"items"`. + * These "tags" are especially useful for the automatic interactive documentation systems (using OpenAPI). +* All of them will include the predefined `responses`. +* All these *path operations* will have the list of `dependencies` evaluated/executed before them. + * If you also declare dependencies in a specific *path operation*, **they will be executed too**. + * The router dependencies are executed first, then the [`dependencies` in the decorator](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, and then the normal parameter dependencies. + * You can also add [`Security` dependencies with `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}. + +!!! tip + Having `dependencies` in the `APIRouter` can be used, for example, to require authentication for a whole group of *path operations*. Even if the dependencies are not added individually to each one of them. + +!!! check + The `prefix`, `tags`, `responses`, and `dependencies` parameters are (as in many other cases) just a feature from **FastAPI** to help you avoid code duplication. + +### Import the dependencies + +This codes lives in the module `app.routers.items`, the file `app/routers/items.py`. -```Python hl_lines="6 11" +And we need to get the dependency function from the module `app.dependencies`, the file `app/dependencies.py`. + +So we use a relative import with `..` for the dependencies: + +```Python hl_lines="3" {!../../../docs_src/bigger_applications/app/routers/items.py!} ``` +#### How relative imports work + +!!! tip + If you know perfectly how imports work, continue to the next section below. + +A single dot `.`, like in: + +```Python +from .dependencies import get_token_header +``` + +would mean: + +* Starting in the same package that this module (the file `app/routers/items.py`) lives in (the directory `app/routers/`)... +* find the module `dependencies` (an imaginary file at `app/routers/dependencies.py`)... +* and from it, import the function `get_token_header`. + +But that file doesn't exist, our dependencies are in a file at `app/dependencies.py`. + +Remember how our app/file structure looks like: + + + +--- + +The two dots `..`, like in: + +```Python +from ..dependencies import get_token_header +``` + +mean: + +* Starting in the same package that this module (the file `app/routers/items.py`) lives in (the directory `app/routers/`)... +* go to the parent package (the directory `app/`)... +* and in there, find the module `dependencies` (the file at `app/routers/dependencies.py`)... +* and from it, import the function `get_token_header`. + +That works correctly! 🎉 + +--- + +The same way, if we had used three dots `...`, like in: + +```Python +from ...dependencies import get_token_header +``` + +that would mean: + +* Starting in the same package that this module (the file `app/routers/items.py`) lives in (the directory `app/routers/`)... +* go to the parent package (the directory `app/`)... +* then go to the parent of that package (there's no parent package, `app` is the top level 😱)... +* and in there, find the module `dependencies` (the file at `app/routers/dependencies.py`)... +* and from it, import the function `get_token_header`. + +That would refer to some package above `app/`, with its own file `__init__.py`, etc. But we don't have that. So, that would throw an error in our example. 🚨 + +But now you know how it works, so you can use relative imports in your own apps no matter how complex they are. 🤓 + ### Add some custom `tags`, `responses`, and `dependencies` -We are not adding the prefix `/items/` nor the `tags=["items"]` to add them later. +We are not adding the prefix `/items` nor the `tags=["items"]` to each *path operation* because we added them to the `APIRouter`. -But we can add custom `tags` and `responses` that will be applied to a specific *path operation*: +But we can still add _more_ `tags` that will be applied to a specific *path operation*, and also some extra `responses` specific to that *path operation*: -```Python hl_lines="18-19" +```Python hl_lines="30-31" {!../../../docs_src/bigger_applications/app/routers/items.py!} ``` +!!! tip + This last path operation will have the combination of tags: `["items", "custom"]`. + + And it will also have both responses in the documentation, one for `404` and one for `403`. + ## The main `FastAPI` Now, let's see the module at `app/main.py`. @@ -122,25 +282,27 @@ Here's where you import and use the class `FastAPI`. This will be the main file in your application that ties everything together. +And as most of your logic will now live in its own specific module, the main file will be quite simple. + ### Import `FastAPI` -You import and create a `FastAPI` class as normally: +You import and create a `FastAPI` class as normally. -```Python hl_lines="1 5" +And we can even declare [global dependencies](dependencies/global-dependencies.md){.internal-link target=_blank} that will be combined with the dependencies for each `APIRouter`: + +```Python hl_lines="1 3 7" {!../../../docs_src/bigger_applications/app/main.py!} ``` ### Import the `APIRouter` -But this time we are not adding *path operations* directly with the `FastAPI` `app`. - -We import the other submodules that have `APIRouter`s: +Now we import the other submodules that have `APIRouter`s: -```Python hl_lines="3" +```Python hl_lines="5" {!../../../docs_src/bigger_applications/app/main.py!} ``` -As the file `app/routers/items.py` is part of the same Python package, we can import it using "dot notation". +As the files `app/routers/users.py` and `app/routers/items.py` are submodules that are part of the same Python package `app`, we can use a single dot `.` to import them using "relative imports". ### How the importing works @@ -156,7 +318,9 @@ Means: * look for the subpackage `routers` (the directory at `app/routers/`)... * and from it, import the submodule `items` (the file at `app/routers/items.py`) and `users` (the file at `app/routers/users.py`)... -The module `items` will have a variable `router` (`items.router`). This is the same one we created in the file `app/routers/items.py`. It's an `APIRouter`. The same for the module `users`. +The module `items` will have a variable `router` (`items.router`). This is the same one we created in the file `app/routers/items.py`, it's an `APIRouter` object. + +And then we do the same for the module `users`. We could also import them like: @@ -165,9 +329,17 @@ from app.routers import items, users ``` !!! info - The first version is a "relative import". + The first version is a "relative import": + + ```Python + from .routers import items, users + ``` + + The second version is an "absolute import": - The second version is an "absolute import". + ```Python + from app.routers import items, users + ``` To learn more about Python Packages and Modules, read
the official Python documentation about Modules. @@ -188,22 +360,24 @@ The `router` from `users` would overwrite the one from `items` and we wouldn't b So, to be able to use both of them in the same file, we import the submodules directly: -```Python hl_lines="3" +```Python hl_lines="4" {!../../../docs_src/bigger_applications/app/main.py!} ``` -### Include an `APIRouter` +### Include the `APIRouter`s for `users` and `items` -Now, let's include the `router` from the submodule `users`: +Now, let's include the `router`s from the submodules `users` and `items`: -```Python hl_lines="13" +```Python hl_lines="10-11" {!../../../docs_src/bigger_applications/app/main.py!} ``` !!! info `users.router` contains the `APIRouter` inside of the file `app/routers/users.py`. -With `app.include_router()` we can add an `APIRouter` to the main `FastAPI` application. + And `items.router` contains the `APIRouter` inside of the file `app/routers/items.py`. + +With `app.include_router()` we can add each `APIRouter` to the main `FastAPI` application. It will include all the routes from that router as part of it. @@ -217,67 +391,52 @@ It will include all the routes from that router as part of it. This will take microseconds and will only happen at startup. - So it won't affect performance. + So it won't affect performance. ⚡ -### Include an `APIRouter` with a `prefix`, `tags`, `responses`, and `dependencies` +### Include an `APIRouter` with a custom `prefix`, `tags`, `responses`, and `dependencies` -Now, let's include the router from the `items` submodule. +Now, let's imagine your organization gave you the `app/internal/admin.py` file. -But, remember that we were lazy and didn't add `/items/` nor `tags` to all the *path operations*? +It contains an `APIRouter` with some admin *path operations* that your organization shares between several projects. -We can add a prefix to all the *path operations* using the parameter `prefix` of `app.include_router()`. +For this example it will be super simple. But let's say that because it is shared with other projects in the organization, we cannot modify it and add a `prefix`, `dependencies`, `tags`, etc. directly to the `APIRouter`: -As the path of each *path operation* has to start with `/`, like in: - -```Python hl_lines="1" -@router.get("/{item_id}") -async def read_item(item_id: str): - ... +```Python hl_lines="3" +{!../../../docs_src/bigger_applications/app/internal/admin.py!} ``` -...the prefix must not include a final `/`. - -So, the prefix in this case would be `/items`. - -We can also add a list of `tags` that will be applied to all the *path operations* included in this router. +But we still want to set a custom `prefix` when including the `APIRouter` so that all its *path operations* start with `/admin`, we want to secure it with the `dependencies` we already have for this project, and we want to include `tags` and `responses`. -And we can add predefined `responses` that will be included in all the *path operations* too. +We can declare all that without having to modify the original `APIRouter` by passing those parameters to `app.include_router()`: -And we can add a list of `dependencies` that will be added to all the *path operations* in the router and will be executed/solved for each request made to them. Note that, much like dependencies in *path operation decorators*, no value will be passed to your *path operation function*. - -```Python hl_lines="8-10 14-20" +```Python hl_lines="14-17" {!../../../docs_src/bigger_applications/app/main.py!} ``` -The end result is that the item paths are now: +That way, the original `APIRouter` will keep unmodified, so we can still share that same `app/internal/admin.py` file with other projects in the organization. -* `/items/` -* `/items/{item_id}` +The result is that in our app, each of the *path operations* from the `admin` module will have: -...as we intended. +* The prefix `/admin`. +* The tag `admin`. +* The dependency `get_token_header`. +* The response `418`. 🍵 -* They will be marked with a list of tags that contain a single string `"items"`. -* The *path operation* that declared a `"custom"` tag will have both tags, `items` and `custom`. - * These "tags" are especially useful for the automatic interactive documentation systems (using OpenAPI). -* All of them will include the predefined `responses`. -* The *path operation* that declared a custom `403` response will have both the predefined responses (`404`) and the `403` declared in it directly. -* All these *path operations* will have the list of `dependencies` evaluated/executed before them. - * If you also declare dependencies in a specific *path operation*, **they will be executed too**. - * The router dependencies are executed first, then the [`dependencies` in the decorator](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, and then the normal parameter dependencies. - * You can also add [`Security` dependencies with `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}. +But that will only affect that `APIRouter` in our app, not in any other code that uses it. -!!! tip - Having `dependencies` in a decorator can be used, for example, to require authentication for a whole group of *path operations*. Even if the dependencies are not added individually to each one of them. +So, for example, other projects could use the same `APIRouter` with a different authentication method. -!!! check - The `prefix`, `tags`, `responses` and `dependencies` parameters are (as in many other cases) just a feature from **FastAPI** to help you avoid code duplication. +### Include a *path operation* -!!! tip - You could also add *path operations* directly, for example with: `@app.get(...)`. +We can also add *path operations* directly to the `FastAPI` app. + +Here we do it... just to show that we can 🤷: - Apart from `app.include_router()`, in the same **FastAPI** app. +```Python hl_lines="21-23" +{!../../../docs_src/bigger_applications/app/main.py!} +``` - It would still work the same. +and it will work correctly, together with all the other *path operations* added with `app.include_router()`. !!! info "Very Technical Details" **Note**: this is a very technical detail that you probably can **just skip**. @@ -317,3 +476,13 @@ You can also use `.include_router()` multiple times with the *same* router using This could be useful, for example, to expose the same API under different prefixes, e.g. `/api/v1` and `/api/latest`. This is an advanced usage that you might not really need, but it's there in case you do. + +## Include an `APIRouter` in another + +The same way you can include an `APIRouter` in a `FastAPI` application, you can include an `APIRouter` in another `APIRouter` using: + +```Python +router.include_router(other_router) +``` + +Make sure you do it before including `router` in the `FastAPI` app, so that the *path operations* from `other_router` are also included. 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 a52dbdfbe3..a1bbcc6c70 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 @@ -27,6 +27,11 @@ These dependencies will be executed/solved the same way normal dependencies. But It might also help avoid confusion for new developers that see an unused parameter in your code and could think it's unnecessary. +!!! info + In this example we use invented custom headers `X-Key` and `X-Token`. + + But in real cases, when implementing security, you would get more benefits from using the integrated [Security utilities (the next chapter)](../security/index.md){.internal-link target=_blank}. + ## Dependencies errors and return values You can use the same dependency *functions* you use normally. @@ -60,3 +65,7 @@ So, you can re-use a normal dependency (that returns a value) you already use so ## Dependencies for a group of *path operations* Later, when reading about how to structure bigger applications ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}), possibly with multiple files, you will learn how to declare a single `dependencies` parameter for a group of *path operations*. + +## Global Dependencies + +Next we will see how to add dependencies to the whole `FastAPI` application, so that they apply to each *path operation*. diff --git a/docs/en/docs/tutorial/dependencies/global-dependencies.md b/docs/en/docs/tutorial/dependencies/global-dependencies.md new file mode 100644 index 0000000000..bcd61d52b0 --- /dev/null +++ b/docs/en/docs/tutorial/dependencies/global-dependencies.md @@ -0,0 +1,17 @@ +# Global Dependencies + +For some types of applications you might want to add dependencies to the whole application. + +Similar to the way you can [add `dependencies` to the *path operation decorators*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, you can add them to the `FastAPI` application. + +In that case, they will be applied to all the *path operations* in the application: + +```Python hl_lines="15" +{!../../../docs_src/dependencies/tutorial012.py!} +``` + +And all the ideas in the section about [adding `dependencies` to the *path operation decorators*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} still apply, but in this case, to all of the *path operations* in the app. + +## Dependencies for groups of *path operations* + +Later, when reading about how to structure bigger applications ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}), possibly with multiple files, you will learn how to declare a single `dependencies` parameter for a group of *path operations*. diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 2ab06113b0..0f4a60070b 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -81,6 +81,7 @@ nav: - tutorial/dependencies/classes-as-dependencies.md - tutorial/dependencies/sub-dependencies.md - tutorial/dependencies/dependencies-in-path-operation-decorators.md + - tutorial/dependencies/global-dependencies.md - tutorial/dependencies/dependencies-with-yield.md - Security: - tutorial/security/index.md diff --git a/docs_src/bigger_applications/app/dependencies.py b/docs_src/bigger_applications/app/dependencies.py new file mode 100644 index 0000000000..267b0d3a8e --- /dev/null +++ b/docs_src/bigger_applications/app/dependencies.py @@ -0,0 +1,11 @@ +from fastapi import Header, HTTPException + + +async def get_token_header(x_token: str = Header(...)): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def get_query_token(token: str): + if token != "jessica": + raise HTTPException(status_code=400, detail="No Jessica token provided") diff --git a/docs_src/bigger_applications/app/internal/__init__.py b/docs_src/bigger_applications/app/internal/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs_src/bigger_applications/app/internal/admin.py b/docs_src/bigger_applications/app/internal/admin.py new file mode 100644 index 0000000000..99d3da86b9 --- /dev/null +++ b/docs_src/bigger_applications/app/internal/admin.py @@ -0,0 +1,8 @@ +from fastapi import APIRouter + +router = APIRouter() + + +@router.post("/") +async def update_admin(): + return {"message": "Admin getting schwifty"} diff --git a/docs_src/bigger_applications/app/main.py b/docs_src/bigger_applications/app/main.py index fdff13947b..ae544a3aac 100644 --- a/docs_src/bigger_applications/app/main.py +++ b/docs_src/bigger_applications/app/main.py @@ -1,20 +1,23 @@ -from fastapi import Depends, FastAPI, Header, HTTPException +from fastapi import Depends, FastAPI +from .dependencies import get_query_token, get_token_header +from .internal import admin from .routers import items, users -app = FastAPI() - - -async def get_token_header(x_token: str = Header(...)): - if x_token != "fake-super-secret-token": - raise HTTPException(status_code=400, detail="X-Token header invalid") +app = FastAPI(dependencies=[Depends(get_query_token)]) app.include_router(users.router) +app.include_router(items.router) app.include_router( - items.router, - prefix="/items", - tags=["items"], + admin.router, + prefix="/admin", + tags=["admin"], dependencies=[Depends(get_token_header)], - responses={404: {"description": "Not found"}}, + responses={418: {"description": "I'm a teapot"}}, ) + + +@app.get("/") +async def root(): + return {"message": "Hello Bigger Applications!"} diff --git a/docs_src/bigger_applications/app/routers/items.py b/docs_src/bigger_applications/app/routers/items.py index de5d9b645b..bde9ff4d55 100644 --- a/docs_src/bigger_applications/app/routers/items.py +++ b/docs_src/bigger_applications/app/routers/items.py @@ -1,16 +1,28 @@ -from fastapi import APIRouter, HTTPException +from fastapi import APIRouter, Depends, HTTPException -router = APIRouter() +from ..dependencies import get_token_header + +router = APIRouter( + prefix="/items", + tags=["items"], + dependencies=[Depends(get_token_header)], + responses={404: {"description": "Not found"}}, +) + + +fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}} @router.get("/") async def read_items(): - return [{"name": "Item Foo"}, {"name": "item Bar"}] + return fake_items_db @router.get("/{item_id}") async def read_item(item_id: str): - return {"name": "Fake Specific Item", "item_id": item_id} + if item_id not in fake_items_db: + raise HTTPException(status_code=404, detail="Item not found") + return {"name": fake_items_db[item_id]["name"], "item_id": item_id} @router.put( @@ -19,6 +31,8 @@ async def read_item(item_id: str): responses={403: {"description": "Operation forbidden"}}, ) async def update_item(item_id: str): - if item_id != "foo": - raise HTTPException(status_code=403, detail="You can only update the item: foo") - return {"item_id": item_id, "name": "The Fighters"} + if item_id != "plumbus": + raise HTTPException( + status_code=403, detail="You can only update the item: plumbus" + ) + return {"item_id": item_id, "name": "The great Plumbus"} diff --git a/docs_src/bigger_applications/app/routers/users.py b/docs_src/bigger_applications/app/routers/users.py index e88b20cd1b..39b3d7e7cf 100644 --- a/docs_src/bigger_applications/app/routers/users.py +++ b/docs_src/bigger_applications/app/routers/users.py @@ -5,7 +5,7 @@ router = APIRouter() @router.get("/users/", tags=["users"]) async def read_users(): - return [{"username": "Foo"}, {"username": "Bar"}] + return [{"username": "Rick"}, {"username": "Morty"}] @router.get("/users/me", tags=["users"]) diff --git a/docs_src/dependencies/tutorial012.py b/docs_src/dependencies/tutorial012.py new file mode 100644 index 0000000000..8f8868a559 --- /dev/null +++ b/docs_src/dependencies/tutorial012.py @@ -0,0 +1,25 @@ +from fastapi import Depends, FastAPI, Header, HTTPException + + +async def verify_token(x_token: str = Header(...)): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def verify_key(x_key: str = Header(...)): + if x_key != "fake-super-secret-key": + raise HTTPException(status_code=400, detail="X-Key header invalid") + return x_key + + +app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)]) + + +@app.get("/items/") +async def read_items(): + return [{"item": "Portal Gun"}, {"item": "Plumbus"}] + + +@app.get("/users/") +async def read_users(): + return [{"username": "Rick"}, {"username": "Morty"}] diff --git a/docs_src/openapi_callbacks/tutorial001.py b/docs_src/openapi_callbacks/tutorial001.py index dea7e89b43..f04fec4d7b 100644 --- a/docs_src/openapi_callbacks/tutorial001.py +++ b/docs_src/openapi_callbacks/tutorial001.py @@ -1,7 +1,6 @@ from typing import Optional from fastapi import APIRouter, FastAPI -from fastapi.responses import JSONResponse from pydantic import BaseModel, HttpUrl app = FastAPI() @@ -23,7 +22,7 @@ class InvoiceEventReceived(BaseModel): ok: bool -invoices_callback_router = APIRouter(default_response_class=JSONResponse) +invoices_callback_router = APIRouter() @invoices_callback_router.post( diff --git a/fastapi/applications.py b/fastapi/applications.py index 24a242a4eb..519dc74aeb 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -2,6 +2,7 @@ from typing import Any, Callable, Dict, List, Optional, Sequence, Type, Union from fastapi import routing from fastapi.concurrency import AsyncExitStack +from fastapi.datastructures import Default, DefaultPlaceholder from fastapi.encoders import DictIntStrAny, SetIntStr from fastapi.exception_handlers import ( http_exception_handler, @@ -38,7 +39,8 @@ class FastAPI(Starlette): openapi_url: Optional[str] = "/openapi.json", openapi_tags: Optional[List[Dict[str, Any]]] = None, servers: Optional[List[Dict[str, Union[str, Any]]]] = None, - default_response_class: Type[Response] = JSONResponse, + dependencies: Optional[Sequence[Depends]] = None, + default_response_class: Type[Response] = Default(JSONResponse), docs_url: Optional[str] = "/docs", redoc_url: Optional[str] = "/redoc", swagger_ui_oauth2_redirect_url: Optional[str] = "/docs/oauth2-redirect", @@ -52,16 +54,25 @@ class FastAPI(Starlette): openapi_prefix: str = "", root_path: str = "", root_path_in_servers: bool = True, + responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, + callbacks: Optional[List[routing.APIRoute]] = None, + deprecated: bool = None, + include_in_schema: bool = True, **extra: Any, ) -> None: - self.default_response_class = default_response_class self._debug = debug self.state = State() self.router: routing.APIRouter = routing.APIRouter( - routes, + routes=routes, dependency_overrides_provider=self, on_startup=on_startup, on_shutdown=on_shutdown, + default_response_class=default_response_class, + dependencies=dependencies, + callbacks=callbacks, + deprecated=deprecated, + include_in_schema=include_in_schema, + responses=responses, ) self.exception_handlers = ( {} if exception_handlers is None else dict(exception_handlers) @@ -203,7 +214,9 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Union[Type[Response], DefaultPlaceholder] = Default( + JSONResponse + ), name: Optional[str] = None, ) -> None: self.router.add_api_route( @@ -211,12 +224,12 @@ class FastAPI(Starlette): endpoint=endpoint, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=methods, operation_id=operation_id, @@ -227,7 +240,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, ) @@ -253,7 +266,7 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, ) -> Callable: def decorator(func: Callable) -> Callable: @@ -262,12 +275,12 @@ class FastAPI(Starlette): func, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=methods, operation_id=operation_id, @@ -278,7 +291,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, ) return func @@ -305,16 +318,21 @@ class FastAPI(Starlette): tags: Optional[List[str]] = None, dependencies: Optional[Sequence[Depends]] = None, responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - default_response_class: Optional[Type[Response]] = None, + deprecated: bool = None, + include_in_schema: bool = True, + default_response_class: Type[Response] = Default(JSONResponse), + callbacks: Optional[List[routing.APIRoute]] = None, ) -> None: self.router.include_router( router, prefix=prefix, tags=tags, dependencies=dependencies, - responses=responses or {}, - default_response_class=default_response_class - or self.default_response_class, + responses=responses, + deprecated=deprecated, + include_in_schema=include_in_schema, + default_response_class=default_response_class, + callbacks=callbacks, ) def get( @@ -338,7 +356,7 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[routing.APIRoute]] = None, ) -> Callable: @@ -346,12 +364,12 @@ class FastAPI(Starlette): path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, operation_id=operation_id, response_model_include=response_model_include, @@ -361,7 +379,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -387,7 +405,7 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[routing.APIRoute]] = None, ) -> Callable: @@ -395,12 +413,12 @@ class FastAPI(Starlette): path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, operation_id=operation_id, response_model_include=response_model_include, @@ -410,7 +428,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -436,7 +454,7 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[routing.APIRoute]] = None, ) -> Callable: @@ -444,12 +462,12 @@ class FastAPI(Starlette): path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, operation_id=operation_id, response_model_include=response_model_include, @@ -459,7 +477,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -485,7 +503,7 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[routing.APIRoute]] = None, ) -> Callable: @@ -493,12 +511,12 @@ class FastAPI(Starlette): path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, response_model_include=response_model_include, response_model_exclude=response_model_exclude, @@ -508,7 +526,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -534,7 +552,7 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[routing.APIRoute]] = None, ) -> Callable: @@ -542,12 +560,12 @@ class FastAPI(Starlette): path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, operation_id=operation_id, response_model_include=response_model_include, @@ -557,7 +575,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -583,7 +601,7 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[routing.APIRoute]] = None, ) -> Callable: @@ -591,12 +609,12 @@ class FastAPI(Starlette): path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, operation_id=operation_id, response_model_include=response_model_include, @@ -606,7 +624,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -632,7 +650,7 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[routing.APIRoute]] = None, ) -> Callable: @@ -640,12 +658,12 @@ class FastAPI(Starlette): path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, operation_id=operation_id, response_model_include=response_model_include, @@ -655,7 +673,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -681,7 +699,7 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[routing.APIRoute]] = None, ) -> Callable: @@ -689,12 +707,12 @@ class FastAPI(Starlette): path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, operation_id=operation_id, response_model_include=response_model_include, @@ -704,7 +722,7 @@ class FastAPI(Starlette): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py index 1ee9900148..1fe8ebdadc 100644 --- a/fastapi/datastructures.py +++ b/fastapi/datastructures.py @@ -1,4 +1,4 @@ -from typing import Any, Callable, Iterable, Type +from typing import Any, Callable, Iterable, Type, TypeVar from starlette.datastructures import UploadFile as StarletteUploadFile @@ -13,3 +13,34 @@ class UploadFile(StarletteUploadFile): if not isinstance(v, StarletteUploadFile): raise ValueError(f"Expected UploadFile, received: {type(v)}") return v + + +class DefaultPlaceholder: + """ + You shouldn't use this class directly. + + It's used internally to recognize when a default value has been overwritten, even + if the overriden default value was truthy. + """ + + def __init__(self, value: Any): + self.value = value + + def __bool__(self) -> bool: + return bool(self.value) + + def __eq__(self, o: object) -> bool: + return isinstance(o, DefaultPlaceholder) and o.value == self.value + + +DefaultType = TypeVar("DefaultType") + + +def Default(value: DefaultType) -> DefaultType: + """ + You shouldn't use this function directly. + + It's used internally to recognize when a default value has been overwritten, even + if the overriden default value was truthy. + """ + return DefaultPlaceholder(value) # type: ignore diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index cd1b1baad0..5547cce4f7 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -3,6 +3,7 @@ from enum import Enum from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast from fastapi import routing +from fastapi.datastructures import DefaultPlaceholder from fastapi.dependencies.models import Dependant from fastapi.dependencies.utils import get_flat_dependant, get_flat_params from fastapi.encoders import jsonable_encoder @@ -159,8 +160,12 @@ def get_openapi_path( security_schemes: Dict[str, Any] = {} definitions: Dict[str, Any] = {} assert route.methods is not None, "Methods must be a list" - assert route.response_class, "A response class is needed to generate OpenAPI" - route_response_media_type: Optional[str] = route.response_class.media_type + if isinstance(route.response_class, DefaultPlaceholder): + current_response_class: Type[routing.Response] = route.response_class.value + else: + current_response_class = route.response_class + assert current_response_class, "A response class is needed to generate OpenAPI" + route_response_media_type: Optional[str] = current_response_class.media_type if route.include_in_schema: for method in route.methods: operation = get_openapi_operation_metadata(route=route, method=method) @@ -205,7 +210,7 @@ def get_openapi_path( and route.status_code not in STATUS_CODES_WITH_NO_BODY ): response_schema = {"type": "string"} - if lenient_issubclass(route.response_class, JSONResponse): + if lenient_issubclass(current_response_class, JSONResponse): if route.response_field: response_schema, _, _ = field_schema( route.response_field, diff --git a/fastapi/routing.py b/fastapi/routing.py index e455f81c95..53f35a4a5c 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -5,6 +5,7 @@ import json from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Type, Union from fastapi import params +from fastapi.datastructures import Default, DefaultPlaceholder from fastapi.dependencies.models import Dependant from fastapi.dependencies.utils import ( get_body_field, @@ -19,6 +20,7 @@ from fastapi.utils import ( create_cloned_field, create_response_field, generate_operation_id_for_path, + get_value_or_default, ) from pydantic import BaseModel from pydantic.error_wrappers import ErrorWrapper, ValidationError @@ -139,7 +141,7 @@ def get_request_handler( dependant: Dependant, body_field: Optional[ModelField] = None, status_code: int = 200, - response_class: Type[Response] = JSONResponse, + response_class: Union[Type[Response], DefaultPlaceholder] = Default(JSONResponse), response_field: Optional[ModelField] = None, response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None, response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None, @@ -152,6 +154,10 @@ def get_request_handler( assert dependant.call is not None, "dependant.call must be a function" is_coroutine = asyncio.iscoroutinefunction(dependant.call) is_body_form = body_field and isinstance(body_field.field_info, params.Form) + if isinstance(response_class, DefaultPlaceholder): + actual_response_class: Type[Response] = response_class.value + else: + actual_response_class = response_class async def app(request: Request) -> Response: try: @@ -198,7 +204,7 @@ def get_request_handler( exclude_none=response_model_exclude_none, is_coroutine=is_coroutine, ) - response = response_class( + response = actual_response_class( content=response_data, status_code=status_code, background=background_tasks, @@ -277,7 +283,9 @@ class APIRoute(routing.Route): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Union[Type[Response], DefaultPlaceholder] = Default( + JSONResponse + ), dependency_overrides_provider: Optional[Any] = None, callbacks: Optional[List["APIRoute"]] = None, ) -> None: @@ -372,7 +380,7 @@ class APIRoute(routing.Route): dependant=self.dependant, body_field=self.body_field, status_code=self.status_code, - response_class=self.response_class or JSONResponse, + response_class=self.response_class, response_field=self.secure_cloned_response_field, response_model_include=self.response_model_include, response_model_exclude=self.response_model_exclude, @@ -387,14 +395,22 @@ class APIRoute(routing.Route): class APIRouter(routing.Router): def __init__( self, + *, + prefix: str = "", + tags: Optional[List[str]] = None, + dependencies: Optional[Sequence[params.Depends]] = None, + default_response_class: Type[Response] = Default(JSONResponse), + responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, + callbacks: Optional[List[APIRoute]] = None, routes: Optional[List[routing.BaseRoute]] = None, redirect_slashes: bool = True, default: Optional[ASGIApp] = None, dependency_overrides_provider: Optional[Any] = None, route_class: Type[APIRoute] = APIRoute, - default_response_class: Optional[Type[Response]] = None, on_startup: Optional[Sequence[Callable]] = None, on_shutdown: Optional[Sequence[Callable]] = None, + deprecated: bool = None, + include_in_schema: bool = True, ) -> None: super().__init__( routes=routes, @@ -403,6 +419,18 @@ class APIRouter(routing.Router): on_startup=on_startup, on_shutdown=on_shutdown, ) + if prefix: + assert prefix.startswith("/"), "A path prefix must start with '/'" + assert not prefix.endswith( + "/" + ), "A path prefix must not end with '/', as the routes will start with '/'" + self.prefix = prefix + self.tags: List[str] = tags or [] + self.dependencies = list(dependencies or []) or [] + self.deprecated = deprecated + self.include_in_schema = include_in_schema + self.responses = responses or {} + self.callbacks = callbacks or [] self.dependency_overrides_provider = dependency_overrides_provider self.route_class = route_class self.default_response_class = default_response_class @@ -430,24 +458,40 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Union[Type[Response], DefaultPlaceholder] = Default( + JSONResponse + ), name: Optional[str] = None, route_class_override: Optional[Type[APIRoute]] = None, callbacks: Optional[List[APIRoute]] = None, ) -> None: route_class = route_class_override or self.route_class + responses = responses or {} + combined_responses = {**self.responses, **responses} + current_response_class = get_value_or_default( + response_class, self.default_response_class + ) + current_tags = self.tags.copy() + if tags: + current_tags.extend(tags) + current_dependencies = self.dependencies.copy() + if dependencies: + current_dependencies.extend(dependencies) + current_callbacks = self.callbacks.copy() + if callbacks: + current_callbacks.extend(callbacks) route = route_class( - path, + self.prefix + path, endpoint=endpoint, response_model=response_model, status_code=status_code, - tags=tags or [], - dependencies=dependencies, + tags=current_tags, + dependencies=current_dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, - deprecated=deprecated, + responses=combined_responses, + deprecated=deprecated or self.deprecated, methods=methods, operation_id=operation_id, response_model_include=response_model_include, @@ -456,11 +500,11 @@ class APIRouter(routing.Router): response_model_exclude_unset=response_model_exclude_unset, response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, - include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + include_in_schema=include_in_schema and self.include_in_schema, + response_class=current_response_class, name=name, dependency_overrides_provider=self.dependency_overrides_provider, - callbacks=callbacks, + callbacks=current_callbacks, ) self.routes.append(route) @@ -486,7 +530,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[APIRoute]] = None, ) -> Callable: @@ -496,12 +540,12 @@ class APIRouter(routing.Router): func, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=methods, operation_id=operation_id, @@ -512,7 +556,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -545,8 +589,11 @@ class APIRouter(routing.Router): prefix: str = "", tags: Optional[List[str]] = None, dependencies: Optional[Sequence[params.Depends]] = None, + default_response_class: Type[Response] = Default(JSONResponse), responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - default_response_class: Optional[Type[Response]] = None, + callbacks: Optional[List[APIRoute]] = None, + deprecated: bool = None, + include_in_schema: bool = True, ) -> None: if prefix: assert prefix.startswith("/"), "A path prefix must start with '/'" @@ -566,19 +613,39 @@ class APIRouter(routing.Router): for route in router.routes: if isinstance(route, APIRoute): combined_responses = {**responses, **route.responses} + use_response_class = get_value_or_default( + route.response_class, + router.default_response_class, + default_response_class, + self.default_response_class, + ) + current_tags = [] + if tags: + current_tags.extend(tags) + if route.tags: + current_tags.extend(route.tags) + current_dependencies: List[params.Depends] = [] + if dependencies: + current_dependencies.extend(dependencies) + if route.dependencies: + current_dependencies.extend(route.dependencies) + current_callbacks = [] + if callbacks: + current_callbacks.extend(callbacks) + if route.callbacks: + current_callbacks.extend(route.callbacks) self.add_api_route( prefix + route.path, route.endpoint, response_model=route.response_model, status_code=route.status_code, - tags=(route.tags or []) + (tags or []), - dependencies=list(dependencies or []) - + list(route.dependencies or []), + tags=current_tags, + dependencies=current_dependencies, summary=route.summary, description=route.description, response_description=route.response_description, responses=combined_responses, - deprecated=route.deprecated, + deprecated=route.deprecated or deprecated or self.deprecated, methods=route.methods, operation_id=route.operation_id, response_model_include=route.response_model_include, @@ -587,11 +654,13 @@ class APIRouter(routing.Router): response_model_exclude_unset=route.response_model_exclude_unset, response_model_exclude_defaults=route.response_model_exclude_defaults, response_model_exclude_none=route.response_model_exclude_none, - include_in_schema=route.include_in_schema, - response_class=route.response_class or default_response_class, + include_in_schema=route.include_in_schema + and self.include_in_schema + and include_in_schema, + response_class=use_response_class, name=route.name, route_class_override=type(route), - callbacks=route.callbacks, + callbacks=current_callbacks, ) elif isinstance(route, routing.Route): self.add_route( @@ -635,7 +704,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[APIRoute]] = None, ) -> Callable: @@ -643,12 +712,12 @@ class APIRouter(routing.Router): path=path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=["GET"], operation_id=operation_id, @@ -659,7 +728,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -685,7 +754,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[APIRoute]] = None, ) -> Callable: @@ -693,12 +762,12 @@ class APIRouter(routing.Router): path=path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=["PUT"], operation_id=operation_id, @@ -709,7 +778,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -735,7 +804,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[APIRoute]] = None, ) -> Callable: @@ -743,12 +812,12 @@ class APIRouter(routing.Router): path=path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=["POST"], operation_id=operation_id, @@ -759,7 +828,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -785,7 +854,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[APIRoute]] = None, ) -> Callable: @@ -793,12 +862,12 @@ class APIRouter(routing.Router): path=path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=["DELETE"], operation_id=operation_id, @@ -809,7 +878,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -835,7 +904,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[APIRoute]] = None, ) -> Callable: @@ -843,12 +912,12 @@ class APIRouter(routing.Router): path=path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=["OPTIONS"], operation_id=operation_id, @@ -859,7 +928,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -885,7 +954,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[APIRoute]] = None, ) -> Callable: @@ -893,12 +962,12 @@ class APIRouter(routing.Router): path=path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=["HEAD"], operation_id=operation_id, @@ -909,7 +978,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -935,7 +1004,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[APIRoute]] = None, ) -> Callable: @@ -943,12 +1012,12 @@ class APIRouter(routing.Router): path=path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=["PATCH"], operation_id=operation_id, @@ -959,7 +1028,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) @@ -985,7 +1054,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Optional[Type[Response]] = None, + response_class: Type[Response] = Default(JSONResponse), name: Optional[str] = None, callbacks: Optional[List[APIRoute]] = None, ) -> Callable: @@ -994,12 +1063,12 @@ class APIRouter(routing.Router): path=path, response_model=response_model, status_code=status_code, - tags=tags or [], + tags=tags, dependencies=dependencies, summary=summary, description=description, response_description=response_description, - responses=responses or {}, + responses=responses, deprecated=deprecated, methods=["TRACE"], operation_id=operation_id, @@ -1010,7 +1079,7 @@ class APIRouter(routing.Router): response_model_exclude_defaults=response_model_exclude_defaults, response_model_exclude_none=response_model_exclude_none, include_in_schema=include_in_schema, - response_class=response_class or self.default_response_class, + response_class=response_class, name=name, callbacks=callbacks, ) diff --git a/fastapi/utils.py b/fastapi/utils.py index d5ace92400..058956e329 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -5,6 +5,7 @@ from enum import Enum from typing import Any, Dict, Optional, Set, Type, Union, cast import fastapi +from fastapi.datastructures import DefaultPlaceholder, DefaultType from fastapi.openapi.constants import REF_PREFIX from pydantic import BaseConfig, BaseModel, create_model from pydantic.class_validators import Validator @@ -136,3 +137,21 @@ def deep_dict_update(main_dict: dict, update_dict: dict) -> None: deep_dict_update(main_dict[key], update_dict[key]) else: main_dict[key] = update_dict[key] + + +def get_value_or_default( + first_item: Union[DefaultPlaceholder, DefaultType], + *extra_items: Union[DefaultPlaceholder, DefaultType], +) -> Union[DefaultPlaceholder, DefaultType]: + """ + Pass items or `DefaultPlaceholder`s by descending priority. + + The first one to _not_ be a `DefaultPlaceholder` will be returned. + + Otherwise, the first item (a `DefaultPlaceholder`) will be returned. + """ + items = (first_item,) + extra_items + for item in items: + if not isinstance(item, DefaultPlaceholder): + return item + return first_item diff --git a/tests/test_datastructures.py b/tests/test_datastructures.py index 27c6d30b6f..43f1a116cb 100644 --- a/tests/test_datastructures.py +++ b/tests/test_datastructures.py @@ -1,7 +1,22 @@ import pytest from fastapi import UploadFile +from fastapi.datastructures import Default def test_upload_file_invalid(): with pytest.raises(ValueError): UploadFile.validate("not a Starlette UploadFile") + + +def test_default_placeholder_equals(): + placeholder_1 = Default("a") + placeholder_2 = Default("a") + assert placeholder_1 == placeholder_2 + assert placeholder_1.value == placeholder_2.value + + +def test_default_placeholder_bool(): + placeholder_a = Default("a") + placeholder_b = Default("") + assert placeholder_a + assert not placeholder_b diff --git a/tests/test_include_router_defaults_overrides.py b/tests/test_include_router_defaults_overrides.py new file mode 100644 index 0000000000..ecfa0b2fad --- /dev/null +++ b/tests/test_include_router_defaults_overrides.py @@ -0,0 +1,6613 @@ +import pytest +from fastapi import APIRouter, Depends, FastAPI, Response +from fastapi.responses import JSONResponse +from fastapi.testclient import TestClient + + +class ResponseLevel0(JSONResponse): + media_type = "application/x-level-0" + + +class ResponseLevel1(JSONResponse): + media_type = "application/x-level-1" + + +class ResponseLevel2(JSONResponse): + media_type = "application/x-level-2" + + +class ResponseLevel3(JSONResponse): + media_type = "application/x-level-3" + + +class ResponseLevel4(JSONResponse): + media_type = "application/x-level-4" + + +class ResponseLevel5(JSONResponse): + media_type = "application/x-level-5" + + +async def dep0(response: Response): + response.headers["x-level0"] = "True" + + +async def dep1(response: Response): + response.headers["x-level1"] = "True" + + +async def dep2(response: Response): + response.headers["x-level2"] = "True" + + +async def dep3(response: Response): + response.headers["x-level3"] = "True" + + +async def dep4(response: Response): + response.headers["x-level4"] = "True" + + +async def dep5(response: Response): + response.headers["x-level5"] = "True" + + +callback_router0 = APIRouter() + + +@callback_router0.get("/") +async def callback0(level0: str): + pass # pragma: nocover + + +callback_router1 = APIRouter() + + +@callback_router1.get("/") +async def callback1(level1: str): + pass # pragma: nocover + + +callback_router2 = APIRouter() + + +@callback_router2.get("/") +async def callback2(level2: str): + pass # pragma: nocover + + +callback_router3 = APIRouter() + + +@callback_router3.get("/") +async def callback3(level3: str): + pass # pragma: nocover + + +callback_router4 = APIRouter() + + +@callback_router4.get("/") +async def callback4(level4: str): + pass # pragma: nocover + + +callback_router5 = APIRouter() + + +@callback_router5.get("/") +async def callback5(level5: str): + pass # pragma: nocover + + +app = FastAPI( + dependencies=[Depends(dep0)], + responses={ + 400: {"description": "Client error level 0"}, + 500: {"description": "Server error level 0"}, + }, + default_response_class=ResponseLevel0, + callbacks=callback_router0.routes, +) + +router2_override = APIRouter( + prefix="/level2", + tags=["level2a", "level2b"], + dependencies=[Depends(dep2)], + responses={ + 402: {"description": "Client error level 2"}, + 502: {"description": "Server error level 2"}, + }, + default_response_class=ResponseLevel2, + callbacks=callback_router2.routes, + deprecated=True, +) +router2_default = APIRouter() +router4_override = APIRouter( + prefix="/level4", + tags=["level4a", "level4b"], + dependencies=[Depends(dep4)], + responses={ + 404: {"description": "Client error level 4"}, + 504: {"description": "Server error level 4"}, + }, + default_response_class=ResponseLevel4, + callbacks=callback_router4.routes, + deprecated=True, +) +router4_default = APIRouter() + + +@app.get( + "/override1", + tags=["path1a", "path1b"], + responses={ + 401: {"description": "Client error level 1"}, + 501: {"description": "Server error level 1"}, + }, + deprecated=True, + callbacks=callback_router1.routes, + dependencies=[Depends(dep1)], + response_class=ResponseLevel1, +) +async def path1_override(level1: str): + return level1 + + +@app.get("/default1") +async def path1_default(level1: str): + return level1 + + +@router2_override.get( + "/override3", + tags=["path3a", "path3b"], + responses={ + 403: {"description": "Client error level 3"}, + 503: {"description": "Server error level 3"}, + }, + deprecated=True, + callbacks=callback_router3.routes, + dependencies=[Depends(dep3)], + response_class=ResponseLevel3, +) +async def path3_override_router2_override(level3: str): + return level3 + + +@router2_override.get("/default3",) +async def path3_default_router2_override(level3: str): + return level3 + + +@router2_default.get( + "/override3", + tags=["path3a", "path3b"], + responses={ + 403: {"description": "Client error level 3"}, + 503: {"description": "Server error level 3"}, + }, + deprecated=True, + callbacks=callback_router3.routes, + dependencies=[Depends(dep3)], + response_class=ResponseLevel3, +) +async def path3_override_router2_default(level3: str): + return level3 + + +@router2_default.get("/default3") +async def path3_default_router2_default(level3: str): + return level3 + + +@router4_override.get( + "/override5", + tags=["path5a", "path5b"], + responses={ + 405: {"description": "Client error level 5"}, + 505: {"description": "Server error level 5"}, + }, + deprecated=True, + callbacks=callback_router5.routes, + dependencies=[Depends(dep5)], + response_class=ResponseLevel5, +) +async def path5_override_router4_override(level5: str): + return level5 + + +@router4_override.get("/default5",) +async def path5_default_router4_override(level5: str): + return level5 + + +@router4_default.get( + "/override5", + tags=["path5a", "path5b"], + responses={ + 405: {"description": "Client error level 5"}, + 505: {"description": "Server error level 5"}, + }, + deprecated=True, + callbacks=callback_router5.routes, + dependencies=[Depends(dep5)], + response_class=ResponseLevel5, +) +async def path5_override_router4_default(level5: str): + return level5 + + +@router4_default.get("/default5",) +async def path5_default_router4_default(level5: str): + return level5 + + +router2_override.include_router( + router4_override, + prefix="/level3", + tags=["level3a", "level3b"], + dependencies=[Depends(dep3)], + responses={ + 403: {"description": "Client error level 3"}, + 503: {"description": "Server error level 3"}, + }, + default_response_class=ResponseLevel3, + callbacks=callback_router3.routes, +) + +router2_override.include_router( + router4_default, + prefix="/level3", + tags=["level3a", "level3b"], + dependencies=[Depends(dep3)], + responses={ + 403: {"description": "Client error level 3"}, + 503: {"description": "Server error level 3"}, + }, + default_response_class=ResponseLevel3, + callbacks=callback_router3.routes, +) + +router2_override.include_router(router4_override) + +router2_override.include_router(router4_default) + +router2_default.include_router( + router4_override, + prefix="/level3", + tags=["level3a", "level3b"], + dependencies=[Depends(dep3)], + responses={ + 403: {"description": "Client error level 3"}, + 503: {"description": "Server error level 3"}, + }, + default_response_class=ResponseLevel3, + callbacks=callback_router3.routes, +) + +router2_default.include_router( + router4_default, + prefix="/level3", + tags=["level3a", "level3b"], + dependencies=[Depends(dep3)], + responses={ + 403: {"description": "Client error level 3"}, + 503: {"description": "Server error level 3"}, + }, + default_response_class=ResponseLevel3, + callbacks=callback_router3.routes, +) + +router2_default.include_router(router4_override) + +router2_default.include_router(router4_default) + + +app.include_router( + router2_override, + prefix="/level1", + tags=["level1a", "level1b"], + dependencies=[Depends(dep1)], + responses={ + 401: {"description": "Client error level 1"}, + 501: {"description": "Server error level 1"}, + }, + default_response_class=ResponseLevel1, + callbacks=callback_router1.routes, +) + +app.include_router( + router2_default, + prefix="/level1", + tags=["level1a", "level1b"], + dependencies=[Depends(dep1)], + responses={ + 401: {"description": "Client error level 1"}, + 501: {"description": "Server error level 1"}, + }, + default_response_class=ResponseLevel1, + callbacks=callback_router1.routes, +) + +app.include_router(router2_override) + +app.include_router(router2_default) + +client = TestClient(app) + + +def test_openapi(): + client = TestClient(app) + response = client.get("/openapi.json") + assert response.json() == openapi_schema + + +def test_level1_override(): + response = client.get("/override1?level1=foo") + assert response.json() == "foo" + assert response.headers["content-type"] == "application/x-level-1" + assert "x-level0" in response.headers + assert "x-level1" in response.headers + assert "x-level2" not in response.headers + assert "x-level3" not in response.headers + assert "x-level4" not in response.headers + assert "x-level5" not in response.headers + + +def test_level1_default(): + response = client.get("/default1?level1=foo") + assert response.json() == "foo" + assert response.headers["content-type"] == "application/x-level-0" + assert "x-level0" in response.headers + assert "x-level1" not in response.headers + assert "x-level2" not in response.headers + assert "x-level3" not in response.headers + assert "x-level4" not in response.headers + assert "x-level5" not in response.headers + + +@pytest.mark.parametrize("override1", [True, False]) +@pytest.mark.parametrize("override2", [True, False]) +@pytest.mark.parametrize("override3", [True, False]) +def test_paths_level3(override1, override2, override3): + url = "" + content_type_level = "0" + if override1: + url += "/level1" + content_type_level = "1" + if override2: + url += "/level2" + content_type_level = "2" + if override3: + url += "/override3" + content_type_level = "3" + else: + url += "/default3" + url += "?level3=foo" + response = client.get(url) + assert response.json() == "foo" + assert ( + response.headers["content-type"] == f"application/x-level-{content_type_level}" + ) + assert "x-level0" in response.headers + assert not override1 or "x-level1" in response.headers + assert not override2 or "x-level2" in response.headers + assert not override3 or "x-level3" in response.headers + + +@pytest.mark.parametrize("override1", [True, False]) +@pytest.mark.parametrize("override2", [True, False]) +@pytest.mark.parametrize("override3", [True, False]) +@pytest.mark.parametrize("override4", [True, False]) +@pytest.mark.parametrize("override5", [True, False]) +def test_paths_level5(override1, override2, override3, override4, override5): + url = "" + content_type_level = "0" + if override1: + url += "/level1" + content_type_level = "1" + if override2: + url += "/level2" + content_type_level = "2" + if override3: + url += "/level3" + content_type_level = "3" + if override4: + url += "/level4" + content_type_level = "4" + if override5: + url += "/override5" + content_type_level = "5" + else: + url += "/default5" + url += "?level5=foo" + response = client.get(url) + assert response.json() == "foo" + assert ( + response.headers["content-type"] == f"application/x-level-{content_type_level}" + ) + assert "x-level0" in response.headers + assert not override1 or "x-level1" in response.headers + assert not override2 or "x-level2" in response.headers + assert not override3 or "x-level3" in response.headers + assert not override4 or "x-level4" in response.headers + assert not override5 or "x-level5" in response.headers + + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/override1": { + "get": { + "tags": ["path1a", "path1b"], + "summary": "Path1 Override", + "operationId": "path1_override_override1_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level1", "type": "string"}, + "name": "level1", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-1": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/default1": { + "get": { + "summary": "Path1 Default", + "operationId": "path1_default_default1_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level1", "type": "string"}, + "name": "level1", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-0": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + } + }, + } + }, + "/level1/level2/override3": { + "get": { + "tags": [ + "level1a", + "level1b", + "level2a", + "level2b", + "path3a", + "path3b", + ], + "summary": "Path3 Override Router2 Override", + "operationId": "path3_override_router2_override_level1_level2_override3_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level3", "type": "string"}, + "name": "level3", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-3": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level2/default3": { + "get": { + "tags": ["level1a", "level1b", "level2a", "level2b"], + "summary": "Path3 Default Router2 Override", + "operationId": "path3_default_router2_override_level1_level2_default3_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level3", "type": "string"}, + "name": "level3", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-2": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level2/level3/level4/override5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level2a", + "level2b", + "level3a", + "level3b", + "level4a", + "level4b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Override", + "operationId": "path5_override_router4_override_level1_level2_level3_level4_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "404": {"description": "Client error level 4"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + "504": {"description": "Server error level 4"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level2/level3/level4/default5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level2a", + "level2b", + "level3a", + "level3b", + "level4a", + "level4b", + ], + "summary": "Path5 Default Router4 Override", + "operationId": "path5_default_router4_override_level1_level2_level3_level4_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-4": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "404": {"description": "Client error level 4"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + "504": {"description": "Server error level 4"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level2/level3/override5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level2a", + "level2b", + "level3a", + "level3b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Default", + "operationId": "path5_override_router4_default_level1_level2_level3_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level2/level3/default5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level2a", + "level2b", + "level3a", + "level3b", + ], + "summary": "Path5 Default Router4 Default", + "operationId": "path5_default_router4_default_level1_level2_level3_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-3": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level2/level4/override5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level2a", + "level2b", + "level4a", + "level4b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Override", + "operationId": "path5_override_router4_override_level1_level2_level4_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "404": {"description": "Client error level 4"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + "504": {"description": "Server error level 4"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level2/level4/default5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level2a", + "level2b", + "level4a", + "level4b", + ], + "summary": "Path5 Default Router4 Override", + "operationId": "path5_default_router4_override_level1_level2_level4_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-4": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "404": {"description": "Client error level 4"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + "504": {"description": "Server error level 4"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level2/override5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level2a", + "level2b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Default", + "operationId": "path5_override_router4_default_level1_level2_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level2/default5": { + "get": { + "tags": ["level1a", "level1b", "level2a", "level2b"], + "summary": "Path5 Default Router4 Default", + "operationId": "path5_default_router4_default_level1_level2_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-2": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "402": {"description": "Client error level 2"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "502": {"description": "Server error level 2"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/override3": { + "get": { + "tags": ["level1a", "level1b", "path3a", "path3b"], + "summary": "Path3 Override Router2 Default", + "operationId": "path3_override_router2_default_level1_override3_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level3", "type": "string"}, + "name": "level3", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-3": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "403": {"description": "Client error level 3"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "503": {"description": "Server error level 3"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/default3": { + "get": { + "tags": ["level1a", "level1b"], + "summary": "Path3 Default Router2 Default", + "operationId": "path3_default_router2_default_level1_default3_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level3", "type": "string"}, + "name": "level3", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-1": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + } + }, + "/level1/level3/level4/override5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level3a", + "level3b", + "level4a", + "level4b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Override", + "operationId": "path5_override_router4_override_level1_level3_level4_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "403": {"description": "Client error level 3"}, + "404": {"description": "Client error level 4"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "503": {"description": "Server error level 3"}, + "504": {"description": "Server error level 4"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level3/level4/default5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level3a", + "level3b", + "level4a", + "level4b", + ], + "summary": "Path5 Default Router4 Override", + "operationId": "path5_default_router4_override_level1_level3_level4_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-4": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "403": {"description": "Client error level 3"}, + "404": {"description": "Client error level 4"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "503": {"description": "Server error level 3"}, + "504": {"description": "Server error level 4"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level3/override5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level3a", + "level3b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Default", + "operationId": "path5_override_router4_default_level1_level3_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "403": {"description": "Client error level 3"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "503": {"description": "Server error level 3"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level3/default5": { + "get": { + "tags": ["level1a", "level1b", "level3a", "level3b"], + "summary": "Path5 Default Router4 Default", + "operationId": "path5_default_router4_default_level1_level3_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-3": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "403": {"description": "Client error level 3"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "503": {"description": "Server error level 3"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + } + }, + "/level1/level4/override5": { + "get": { + "tags": [ + "level1a", + "level1b", + "level4a", + "level4b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Override", + "operationId": "path5_override_router4_override_level1_level4_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "404": {"description": "Client error level 4"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "504": {"description": "Server error level 4"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/level4/default5": { + "get": { + "tags": ["level1a", "level1b", "level4a", "level4b"], + "summary": "Path5 Default Router4 Override", + "operationId": "path5_default_router4_override_level1_level4_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-4": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "404": {"description": "Client error level 4"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "504": {"description": "Server error level 4"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/override5": { + "get": { + "tags": ["level1a", "level1b", "path5a", "path5b"], + "summary": "Path5 Override Router4 Default", + "operationId": "path5_override_router4_default_level1_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level1/default5": { + "get": { + "tags": ["level1a", "level1b"], + "summary": "Path5 Default Router4 Default", + "operationId": "path5_default_router4_default_level1_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-1": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "401": {"description": "Client error level 1"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "501": {"description": "Server error level 1"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback1": { + "/": { + "get": { + "summary": "Callback1", + "operationId": "callback1__get", + "parameters": [ + { + "name": "level1", + "in": "query", + "required": True, + "schema": {"title": "Level1", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + } + }, + "/level2/override3": { + "get": { + "tags": ["level2a", "level2b", "path3a", "path3b"], + "summary": "Path3 Override Router2 Override", + "operationId": "path3_override_router2_override_level2_override3_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level3", "type": "string"}, + "name": "level3", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-3": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level2/default3": { + "get": { + "tags": ["level2a", "level2b"], + "summary": "Path3 Default Router2 Override", + "operationId": "path3_default_router2_override_level2_default3_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level3", "type": "string"}, + "name": "level3", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-2": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level2/level3/level4/override5": { + "get": { + "tags": [ + "level2a", + "level2b", + "level3a", + "level3b", + "level4a", + "level4b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Override", + "operationId": "path5_override_router4_override_level2_level3_level4_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "404": {"description": "Client error level 4"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + "504": {"description": "Server error level 4"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level2/level3/level4/default5": { + "get": { + "tags": [ + "level2a", + "level2b", + "level3a", + "level3b", + "level4a", + "level4b", + ], + "summary": "Path5 Default Router4 Override", + "operationId": "path5_default_router4_override_level2_level3_level4_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-4": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "404": {"description": "Client error level 4"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + "504": {"description": "Server error level 4"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level2/level3/override5": { + "get": { + "tags": [ + "level2a", + "level2b", + "level3a", + "level3b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Default", + "operationId": "path5_override_router4_default_level2_level3_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level2/level3/default5": { + "get": { + "tags": ["level2a", "level2b", "level3a", "level3b"], + "summary": "Path5 Default Router4 Default", + "operationId": "path5_default_router4_default_level2_level3_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-3": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "403": {"description": "Client error level 3"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + "503": {"description": "Server error level 3"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level2/level4/override5": { + "get": { + "tags": [ + "level2a", + "level2b", + "level4a", + "level4b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Override", + "operationId": "path5_override_router4_override_level2_level4_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "404": {"description": "Client error level 4"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + "504": {"description": "Server error level 4"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level2/level4/default5": { + "get": { + "tags": ["level2a", "level2b", "level4a", "level4b"], + "summary": "Path5 Default Router4 Override", + "operationId": "path5_default_router4_override_level2_level4_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-4": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "404": {"description": "Client error level 4"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + "504": {"description": "Server error level 4"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level2/override5": { + "get": { + "tags": ["level2a", "level2b", "path5a", "path5b"], + "summary": "Path5 Override Router4 Default", + "operationId": "path5_override_router4_default_level2_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level2/default5": { + "get": { + "tags": ["level2a", "level2b"], + "summary": "Path5 Default Router4 Default", + "operationId": "path5_default_router4_default_level2_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-2": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "402": {"description": "Client error level 2"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "502": {"description": "Server error level 2"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback2": { + "/": { + "get": { + "summary": "Callback2", + "operationId": "callback2__get", + "parameters": [ + { + "name": "level2", + "in": "query", + "required": True, + "schema": {"title": "Level2", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/override3": { + "get": { + "tags": ["path3a", "path3b"], + "summary": "Path3 Override Router2 Default", + "operationId": "path3_override_router2_default_override3_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level3", "type": "string"}, + "name": "level3", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-3": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "403": {"description": "Client error level 3"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "503": {"description": "Server error level 3"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/default3": { + "get": { + "summary": "Path3 Default Router2 Default", + "operationId": "path3_default_router2_default_default3_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level3", "type": "string"}, + "name": "level3", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-0": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + } + }, + } + }, + "/level3/level4/override5": { + "get": { + "tags": [ + "level3a", + "level3b", + "level4a", + "level4b", + "path5a", + "path5b", + ], + "summary": "Path5 Override Router4 Override", + "operationId": "path5_override_router4_override_level3_level4_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "403": {"description": "Client error level 3"}, + "404": {"description": "Client error level 4"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "503": {"description": "Server error level 3"}, + "504": {"description": "Server error level 4"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level3/level4/default5": { + "get": { + "tags": ["level3a", "level3b", "level4a", "level4b"], + "summary": "Path5 Default Router4 Override", + "operationId": "path5_default_router4_override_level3_level4_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-4": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "403": {"description": "Client error level 3"}, + "404": {"description": "Client error level 4"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "503": {"description": "Server error level 3"}, + "504": {"description": "Server error level 4"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level3/override5": { + "get": { + "tags": ["level3a", "level3b", "path5a", "path5b"], + "summary": "Path5 Override Router4 Default", + "operationId": "path5_override_router4_default_level3_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "403": {"description": "Client error level 3"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "503": {"description": "Server error level 3"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level3/default5": { + "get": { + "tags": ["level3a", "level3b"], + "summary": "Path5 Default Router4 Default", + "operationId": "path5_default_router4_default_level3_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-3": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "403": {"description": "Client error level 3"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "503": {"description": "Server error level 3"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback3": { + "/": { + "get": { + "summary": "Callback3", + "operationId": "callback3__get", + "parameters": [ + { + "name": "level3", + "in": "query", + "required": True, + "schema": {"title": "Level3", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + } + }, + "/level4/override5": { + "get": { + "tags": ["level4a", "level4b", "path5a", "path5b"], + "summary": "Path5 Override Router4 Override", + "operationId": "path5_override_router4_override_level4_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "404": {"description": "Client error level 4"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "504": {"description": "Server error level 4"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/level4/default5": { + "get": { + "tags": ["level4a", "level4b"], + "summary": "Path5 Default Router4 Override", + "operationId": "path5_default_router4_override_level4_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-4": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "404": {"description": "Client error level 4"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "504": {"description": "Server error level 4"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback4": { + "/": { + "get": { + "summary": "Callback4", + "operationId": "callback4__get", + "parameters": [ + { + "name": "level4", + "in": "query", + "required": True, + "schema": {"title": "Level4", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/override5": { + "get": { + "tags": ["path5a", "path5b"], + "summary": "Path5 Override Router4 Default", + "operationId": "path5_override_router4_default_override5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-5": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "405": {"description": "Client error level 5"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + "505": {"description": "Server error level 5"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "callback5": { + "/": { + "get": { + "summary": "Callback5", + "operationId": "callback5__get", + "parameters": [ + { + "name": "level5", + "in": "query", + "required": True, + "schema": {"title": "Level5", "type": "string"}, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + }, + "deprecated": True, + } + }, + "/default5": { + "get": { + "summary": "Path5 Default Router4 Default", + "operationId": "path5_default_router4_default_default5_get", + "parameters": [ + { + "required": True, + "schema": {"title": "Level5", "type": "string"}, + "name": "level5", + "in": "query", + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/x-level-0": {"schema": {}}}, + }, + "400": {"description": "Client error level 0"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + "500": {"description": "Server error level 0"}, + }, + "callbacks": { + "callback0": { + "/": { + "get": { + "summary": "Callback0", + "operationId": "callback0__get", + "parameters": [ + { + "name": "level0", + "in": "query", + "required": True, + "schema": {"title": "Level0", "type": "string"}, + } + ], + "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"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} diff --git a/tests/test_sub_callbacks.py b/tests/test_sub_callbacks.py index dc0e3424a9..40ca1475d1 100644 --- a/tests/test_sub_callbacks.py +++ b/tests/test_sub_callbacks.py @@ -1,7 +1,6 @@ from typing import Optional from fastapi import APIRouter, FastAPI -from fastapi.responses import JSONResponse from fastapi.testclient import TestClient from pydantic import BaseModel, HttpUrl @@ -24,14 +23,27 @@ class InvoiceEventReceived(BaseModel): ok: bool -invoices_callback_router = APIRouter(default_response_class=JSONResponse) +invoices_callback_router = APIRouter() @invoices_callback_router.post( "{$callback_url}/invoices/{$request.body.id}", response_model=InvoiceEventReceived, ) def invoice_notification(body: InvoiceEvent): - pass + pass # pragma: nocover + + +class Event(BaseModel): + name: str + total: float + + +events_callback_router = APIRouter() + + +@events_callback_router.get("{$callback_url}/events/{$request.body.title}") +def event_callback(event: Event): + pass # pragma: nocover subrouter = APIRouter() @@ -58,7 +70,7 @@ def create_invoice(invoice: Invoice, callback_url: Optional[HttpUrl] = None): return {"msg": "Invoice received"} -app.include_router(subrouter) +app.include_router(subrouter, callbacks=events_callback_router.routes) client = TestClient(app) @@ -110,6 +122,40 @@ openapi_schema = { }, }, "callbacks": { + "event_callback": { + "{$callback_url}/events/{$request.body.title}": { + "get": { + "summary": "Event Callback", + "operationId": "event_callback__callback_url__events___request_body_title__get", + "requestBody": { + "required": True, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Event" + } + } + }, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, "invoice_notification": { "{$callback_url}/invoices/{$request.body.id}": { "post": { @@ -149,13 +195,22 @@ openapi_schema = { }, } } - } + }, }, } } }, "components": { "schemas": { + "Event": { + "title": "Event", + "required": ["name", "total"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "total": {"title": "Total", "type": "number"}, + }, + }, "HTTPValidationError": { "title": "HTTPValidationError", "type": "object", @@ -225,8 +280,3 @@ def test_get(): ) assert response.status_code == 200, response.text assert response.json() == {"msg": "Invoice received"} - - -def test_dummy_callback(): - # Just for coverage - invoice_notification({}) diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py index 5a5ad1b84b..3670e25cfd 100644 --- a/tests/test_tutorial/test_bigger_applications/test_main.py +++ b/tests/test_tutorial/test_bigger_applications/test_main.py @@ -11,32 +11,48 @@ openapi_schema = { "paths": { "/users/": { "get": { + "tags": ["users"], + "summary": "Read Users", + "operationId": "read_users_users__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Token", "type": "string"}, + "name": "token", + "in": "query", + } + ], "responses": { "200": { "description": "Successful Response", "content": {"application/json": {"schema": {}}}, - } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, }, - "tags": ["users"], - "summary": "Read Users", - "operationId": "read_users_users__get", } }, "/users/me": { "get": { - "responses": { - "200": { - "description": "Successful Response", - "content": {"application/json": {"schema": {}}}, - } - }, "tags": ["users"], "summary": "Read User Me", "operationId": "read_user_me_users_me_get", - } - }, - "/users/{username}": { - "get": { + "parameters": [ + { + "required": True, + "schema": {"title": "Token", "type": "string"}, + "name": "token", + "in": "query", + } + ], "responses": { "200": { "description": "Successful Response", @@ -53,6 +69,10 @@ openapi_schema = { }, }, }, + } + }, + "/users/{username}": { + "get": { "tags": ["users"], "summary": "Read User", "operationId": "read_user_users__username__get", @@ -62,14 +82,15 @@ openapi_schema = { "schema": {"title": "Username", "type": "string"}, "name": "username", "in": "path", - } + }, + { + "required": True, + "schema": {"title": "Token", "type": "string"}, + "name": "token", + "in": "query", + }, ], - } - }, - "/items/": { - "get": { "responses": { - "404": {"description": "Not found"}, "200": { "description": "Successful Response", "content": {"application/json": {"schema": {}}}, @@ -85,27 +106,33 @@ openapi_schema = { }, }, }, + } + }, + "/items/": { + "get": { "tags": ["items"], "summary": "Read Items", "operationId": "read_items_items__get", "parameters": [ + { + "required": True, + "schema": {"title": "Token", "type": "string"}, + "name": "token", + "in": "query", + }, { "required": True, "schema": {"title": "X-Token", "type": "string"}, "name": "x-token", "in": "header", - } + }, ], - } - }, - "/items/{item_id}": { - "get": { "responses": { - "404": {"description": "Not found"}, "200": { "description": "Successful Response", "content": {"application/json": {"schema": {}}}, }, + "404": {"description": "Not found"}, "422": { "description": "Validation Error", "content": { @@ -117,6 +144,10 @@ openapi_schema = { }, }, }, + } + }, + "/items/{item_id}": { + "get": { "tags": ["items"], "summary": "Read Item", "operationId": "read_item_items__item_id__get", @@ -127,6 +158,12 @@ openapi_schema = { "name": "item_id", "in": "path", }, + { + "required": True, + "schema": {"title": "Token", "type": "string"}, + "name": "token", + "in": "query", + }, { "required": True, "schema": {"title": "X-Token", "type": "string"}, @@ -134,15 +171,12 @@ openapi_schema = { "in": "header", }, ], - }, - "put": { "responses": { - "404": {"description": "Not found"}, - "403": {"description": "Operation forbidden"}, "200": { "description": "Successful Response", "content": {"application/json": {"schema": {}}}, }, + "404": {"description": "Not found"}, "422": { "description": "Validation Error", "content": { @@ -154,7 +188,9 @@ openapi_schema = { }, }, }, - "tags": ["custom", "items"], + }, + "put": { + "tags": ["items", "custom"], "summary": "Update Item", "operationId": "update_item_items__item_id__put", "parameters": [ @@ -164,6 +200,12 @@ openapi_schema = { "name": "item_id", "in": "path", }, + { + "required": True, + "schema": {"title": "Token", "type": "string"}, + "name": "token", + "in": "query", + }, { "required": True, "schema": {"title": "X-Token", "type": "string"}, @@ -171,11 +213,108 @@ openapi_schema = { "in": "header", }, ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "404": {"description": "Not found"}, + "403": {"description": "Operation forbidden"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, }, }, + "/admin/": { + "post": { + "tags": ["admin"], + "summary": "Update Admin", + "operationId": "update_admin_admin__post", + "parameters": [ + { + "required": True, + "schema": {"title": "Token", "type": "string"}, + "name": "token", + "in": "query", + }, + { + "required": True, + "schema": {"title": "X-Token", "type": "string"}, + "name": "x-token", + "in": "header", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "418": {"description": "I'm a teapot"}, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/": { + "get": { + "summary": "Root", + "operationId": "root__get", + "parameters": [ + { + "required": True, + "schema": {"title": "Token", "type": "string"}, + "name": "token", + "in": "query", + } + ], + "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"}, + } + }, + }, "ValidationError": { "title": "ValidationError", "required": ["loc", "msg", "type"], @@ -190,49 +329,64 @@ openapi_schema = { "type": {"title": "Error Type", "type": "string"}, }, }, - "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": "#/components/schemas/ValidationError"}, - } - }, - }, } }, } +no_jessica = { + "detail": [ + { + "loc": ["query", "token"], + "msg": "field required", + "type": "value_error.missing", + }, + ] +} + + @pytest.mark.parametrize( "path,expected_status,expected_response,headers", [ - ("/users", 200, [{"username": "Foo"}, {"username": "Bar"}], {}), - ("/users/foo", 200, {"username": "foo"}, {}), - ("/users/me", 200, {"username": "fakecurrentuser"}, {}), ( - "/items", + "/users?token=jessica", + 200, + [{"username": "Rick"}, {"username": "Morty"}], + {}, + ), + ("/users", 422, no_jessica, {}), + ("/users/foo?token=jessica", 200, {"username": "foo"}, {}), + ("/users/foo", 422, no_jessica, {}), + ("/users/me?token=jessica", 200, {"username": "fakecurrentuser"}, {}), + ("/users/me", 422, no_jessica, {}), + ( + "/items?token=jessica", 200, - [{"name": "Item Foo"}, {"name": "item Bar"}], + {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}, {"X-Token": "fake-super-secret-token"}, ), + ("/items", 422, no_jessica, {"X-Token": "fake-super-secret-token"}), ( - "/items/bar", + "/items/plumbus?token=jessica", 200, - {"name": "Fake Specific Item", "item_id": "bar"}, + {"name": "Plumbus", "item_id": "plumbus"}, {"X-Token": "fake-super-secret-token"}, ), - ("/items", 400, {"detail": "X-Token header invalid"}, {"X-Token": "invalid"}), + ("/items/plumbus", 422, no_jessica, {"X-Token": "fake-super-secret-token"}), ( - "/items/bar", + "/items?token=jessica", 400, {"detail": "X-Token header invalid"}, {"X-Token": "invalid"}, ), ( - "/items", + "/items/bar?token=jessica", + 400, + {"detail": "X-Token header invalid"}, + {"X-Token": "invalid"}, + ), + ( + "/items?token=jessica", 422, { "detail": [ @@ -246,7 +400,7 @@ openapi_schema = { {}, ), ( - "/items/bar", + "/items/plumbus?token=jessica", 422, { "detail": [ @@ -259,6 +413,8 @@ openapi_schema = { }, {}, ), + ("/?token=jessica", 200, {"message": "Hello Bigger Applications!"}, {}), + ("/", 422, no_jessica, {}), ("/openapi.json", 200, openapi_schema, {}), ], ) @@ -273,11 +429,16 @@ def test_put_no_header(): assert response.status_code == 422, response.text assert response.json() == { "detail": [ + { + "loc": ["query", "token"], + "msg": "field required", + "type": "value_error.missing", + }, { "loc": ["header", "x-token"], "msg": "field required", "type": "value_error.missing", - } + }, ] } @@ -289,12 +450,30 @@ def test_put_invalid_header(): def test_put(): - response = client.put("/items/foo", headers={"X-Token": "fake-super-secret-token"}) + response = client.put( + "/items/plumbus?token=jessica", headers={"X-Token": "fake-super-secret-token"} + ) assert response.status_code == 200, response.text - assert response.json() == {"item_id": "foo", "name": "The Fighters"} + assert response.json() == {"item_id": "plumbus", "name": "The great Plumbus"} def test_put_forbidden(): - response = client.put("/items/bar", headers={"X-Token": "fake-super-secret-token"}) + response = client.put( + "/items/bar?token=jessica", headers={"X-Token": "fake-super-secret-token"} + ) assert response.status_code == 403, response.text - assert response.json() == {"detail": "You can only update the item: foo"} + assert response.json() == {"detail": "You can only update the item: plumbus"} + + +def test_admin(): + response = client.post( + "/admin/?token=jessica", headers={"X-Token": "fake-super-secret-token"} + ) + assert response.status_code == 200, response.text + assert response.json() == {"message": "Admin getting schwifty"} + + +def test_admin_invalid_header(): + response = client.post("/admin/", headers={"X-Token": "invalid"}) + assert response.status_code == 400, response.text + assert response.json() == {"detail": "X-Token header invalid"} diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012.py b/tests/test_tutorial/test_dependencies/test_tutorial012.py new file mode 100644 index 0000000000..ada83c6260 --- /dev/null +++ b/tests/test_tutorial/test_dependencies/test_tutorial012.py @@ -0,0 +1,209 @@ +from fastapi.testclient import TestClient + +from docs_src.dependencies.tutorial012 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "parameters": [ + { + "required": True, + "schema": {"title": "X-Token", "type": "string"}, + "name": "x-token", + "in": "header", + }, + { + "required": True, + "schema": {"title": "X-Key", "type": "string"}, + "name": "x-key", + "in": "header", + }, + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/users/": { + "get": { + "summary": "Read Users", + "operationId": "read_users_users__get", + "parameters": [ + { + "required": True, + "schema": {"title": "X-Token", "type": "string"}, + "name": "x-token", + "in": "header", + }, + { + "required": True, + "schema": {"title": "X-Key", "type": "string"}, + "name": "x-key", + "in": "header", + }, + ], + "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"}, + } + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": {"type": "string"}, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_get_no_headers_items(): + response = client.get("/items/") + assert response.status_code == 422, response.text + assert response.json() == { + "detail": [ + { + "loc": ["header", "x-token"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["header", "x-key"], + "msg": "field required", + "type": "value_error.missing", + }, + ] + } + + +def test_get_no_headers_users(): + response = client.get("/users/") + assert response.status_code == 422, response.text + assert response.json() == { + "detail": [ + { + "loc": ["header", "x-token"], + "msg": "field required", + "type": "value_error.missing", + }, + { + "loc": ["header", "x-key"], + "msg": "field required", + "type": "value_error.missing", + }, + ] + } + + +def test_get_invalid_one_header_items(): + response = client.get("/items/", headers={"X-Token": "invalid"}) + assert response.status_code == 400, response.text + assert response.json() == {"detail": "X-Token header invalid"} + + +def test_get_invalid_one_users(): + response = client.get("/users/", headers={"X-Token": "invalid"}) + assert response.status_code == 400, response.text + assert response.json() == {"detail": "X-Token header invalid"} + + +def test_get_invalid_second_header_items(): + response = client.get( + "/items/", headers={"X-Token": "fake-super-secret-token", "X-Key": "invalid"} + ) + assert response.status_code == 400, response.text + assert response.json() == {"detail": "X-Key header invalid"} + + +def test_get_invalid_second_header_users(): + response = client.get( + "/users/", headers={"X-Token": "fake-super-secret-token", "X-Key": "invalid"} + ) + assert response.status_code == 400, response.text + assert response.json() == {"detail": "X-Key header invalid"} + + +def test_get_valid_headers_items(): + response = client.get( + "/items/", + headers={ + "X-Token": "fake-super-secret-token", + "X-Key": "fake-super-secret-key", + }, + ) + assert response.status_code == 200, response.text + assert response.json() == [{"item": "Portal Gun"}, {"item": "Plumbus"}] + + +def test_get_valid_headers_users(): + response = client.get( + "/users/", + headers={ + "X-Token": "fake-super-secret-token", + "X-Key": "fake-super-secret-key", + }, + ) + assert response.status_code == 200, response.text + assert response.json() == [{"username": "Rick"}, {"username": "Morty"}] -- 2.47.3