From 2f478eeca643c5c66370676cb521397479508e69 Mon Sep 17 00:00:00 2001 From: Ingmar Steen Date: Thu, 11 Jun 2020 23:53:19 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20ASGI=20root?= =?UTF-8?q?=5Fpath=20for=20openapi=20docs=20(#1199)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use ASGI root_path when it is provided and openapi_prefix is empty. * Strip trailing slashes from root_path. * Please mypy. * Fix extending openapi test. * 📝 Add docs and tutorial for using root_path behind a proxy * ♻️ Refactor application root_path logic, use root_path, deprecate openapi_prefix * ✅ Add tests for Behind a Proxy with root_path * ♻️ Refactor test * 📝 Update/add docs for Sub-applications and Behind a Proxy * 📝 Update Extending OpenAPI with openapi_prefix parameter * ✅ Add test for deprecated openapi_prefix Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/behind-a-proxy.md | 281 ++++++++++++++++++ docs/en/docs/advanced/extending-openapi.md | 15 +- .../docs/advanced/sub-applications-proxy.md | 100 ------- docs/en/docs/advanced/sub-applications.md | 73 +++++ .../img/tutorial/behind-a-proxy/image01.png | Bin 0 -> 60301 bytes .../img/tutorial/behind-a-proxy/image02.png | Bin 0 -> 29123 bytes docs/en/mkdocs.yml | 3 +- docs_src/behind_a_proxy/tutorial001.py | 8 + docs_src/behind_a_proxy/tutorial002.py | 8 + docs_src/extending_openapi/tutorial001.py | 3 +- docs_src/sub_applications/tutorial001.py | 2 +- fastapi/applications.py | 33 +- tests/test_deprecated_openapi_prefix.py | 43 +++ .../test_behind_a_proxy/__init__.py | 0 .../test_behind_a_proxy/test_tutorial001.py | 36 +++ .../test_behind_a_proxy/test_tutorial002.py | 36 +++ 16 files changed, 527 insertions(+), 114 deletions(-) create mode 100644 docs/en/docs/advanced/behind-a-proxy.md delete mode 100644 docs/en/docs/advanced/sub-applications-proxy.md create mode 100644 docs/en/docs/advanced/sub-applications.md create mode 100644 docs/en/docs/img/tutorial/behind-a-proxy/image01.png create mode 100644 docs/en/docs/img/tutorial/behind-a-proxy/image02.png create mode 100644 docs_src/behind_a_proxy/tutorial001.py create mode 100644 docs_src/behind_a_proxy/tutorial002.py create mode 100644 tests/test_deprecated_openapi_prefix.py create mode 100644 tests/test_tutorial/test_behind_a_proxy/__init__.py create mode 100644 tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py create mode 100644 tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py diff --git a/docs/en/docs/advanced/behind-a-proxy.md b/docs/en/docs/advanced/behind-a-proxy.md new file mode 100644 index 000000000..660e374a4 --- /dev/null +++ b/docs/en/docs/advanced/behind-a-proxy.md @@ -0,0 +1,281 @@ +# Behind a Proxy + +In some situations, you might need to use a **proxy** server like Traefik or Nginx with a configuration that adds an extra path prefix that is not seen by your application. + +In these cases you can use `root_path` to configure your application. + +The `root_path` is a mechanism provided by the ASGI specification (that FastAPI is built on, through Starlette). + +The `root_path` is used to handle these specific cases. + +And it's also used internally when mounting sub-applications. + +## Proxy with a stripped path prefix + +Having a proxy with a stripped path prefix, in this case, means that you could declare a path at `/app` in your code, but then, you add a layer on top (the proxy) that would put your **FastAPI** application under a path like `/api/v1`. + +In this case, the original path `/app` would actually be served at `/api/v1/app`. + +Even though all your code is written assuming there's just `/app`. + +And the proxy would be **"stripping"** the **path prefix** on the fly before transmitting the request to Uvicorn, keep your application convinced that it is serving at `/app`, so that you don't have to update all your code to include the prefix `/api/v1`. + +Up to here, everything would work as normally. + +But then, when you open the integrated docs UI (the frontend), it would expect to get the OpenAPI schema at `/openapi.json`, instead of `/api/v1/openapi.json`. + +So, the frontend (that runs in the browser) would try to reach `/openapi.json` and wouldn't be able to get the OpenAPI schema. + +Because we have a proxy with a path prefix of `/api/v1` for our app, the frontend needs to fetch the OpenAPI schema at `/api/v1/openapi.json`. + +```mermaid +graph LR + +browser("Browser") +proxy["Proxy on http://0.0.0.0:9999/api/v1/app"] +server["Server on http://127.0.0.1:8000/app"] + +browser --> proxy +proxy --> server +``` + +!!! tip + The IP `0.0.0.0` is commonly used to mean that the program listens on all the IPs available in that machine/server. + +The docs UI would also need that the JSON payload with the OpenAPI schema has the path defined as `/api/v1/app` (behind the proxy) instead of `/app`. For example, something like: + +```JSON hl_lines="5" +{ + "openapi": "3.0.2", + // More stuff here + "paths": { + "/api/v1/app": { + // More stuff here + } + } +} +``` + +In this example, the "Proxy" could be something like **Traefik**. And the server would be something like **Uvicorn**, running your FastAPI application. + +### Providing the `root_path` + +To achieve this, you can use the command line option `--root-path` like: + +
+ +```console +$ uvicorn main:app --root-path /api/v1 + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +If you use Hypercorn, it also has the option `--root-path`. + +!!! note "Technical Details" + The ASGI specification defines a `root_path` for this use case. + + And the `--root-path` command line option provides that `root_path`. + +### Checking the current `root_path` + +You can get the current `root_path` used by your application for each request, it is part of the `scope` dictionary (that's part of the ASGI spec). + +Here we are including it in the message just for demonstration purposes. + +```Python hl_lines="8" +{!../../../docs_src/behind_a_proxy/tutorial001.py!} +``` + +Then, if you start Uvicorn with: + +
+ +```console +$ uvicorn main:app --root-path /api/v1 + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +The response would be something like: + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +### Setting the `root_path` in the FastAPI app + +Alternatively, if you don't have a way to provide a command line option like `--root-path` or equivalent, you can set the `root_path` parameter when creating your FastAPI app: + +```Python hl_lines="3" +{!../../../docs_src/behind_a_proxy/tutorial002.py!} +``` + +Passing the `root_path` to `FastAPI` would be the equivalent of passing the `--root-path` command line option to Uvicorn or Hypercorn. + +### About `root_path` + +Have in mind that the server (Uvicorn) won't use that `root_path` for anything else than passing it to the app. + +But if you go with your browser to http://127.0.0.1:8000/app you will see the normal response: + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +So, it won't expect to be accessed at `http://127.0.0.1:8000/api/v1/app`. + +Uvicorn will expect the proxy to access Uvicorn at `http://127.0.0.1:8000/app`, and then it would be the proxy's responsibility to add the extra `/api/v1` prefix on top. + +## About proxies with a stripped path prefix + +Have in mind that a proxy with stripped path prefix is only one of the ways to configure it. + +Probably in many cases the default will be that the proxy doesn't have a stripped path prefix. + +In a case like that (without a stripped path prefix), the proxy would listen on something like `https://myawesomeapp.com`, and then if the browser goes to `https://myawesomeapp.com/api/v1/app` and your server (e.g. Uvicorn) listens on `http://127.0.0.1:8000` the proxy (without a stripped path prefix) would access Uvicorn at the same path: `http://127.0.0.1:8000/api/v1/app`. + +## Testing locally with Traefik + +You can easily run the experiment locally with a stripped path prefix using Traefik. + +Download Traefik, it's a single binary, you can extract the compressed file and run it directly from the terminal. + +Then create a file `traefik.toml` with: + +```TOML hl_lines="3" +[entryPoints] + [entryPoints.http] + address = ":9999" + +[providers] + [providers.file] + filename = "routes.toml" +``` + +This tells Traefik to listen on port 9999 and to use another file `routes.toml`. + +!!! tip + We are using port 9999 instead of the standard HTTP port 80 so that you don't have to run it with admin (`sudo`) privileges. + +Now create that other file `routes.toml`: + +```TOML hl_lines="5 12 20" +[http] + [http.middlewares] + + [http.middlewares.api-stripprefix.stripPrefix] + prefixes = ["/api/v1"] + + [http.routers] + + [http.routers.app-http] + entryPoints = ["http"] + service = "app" + rule = "PathPrefix(`/api/v1`)" + middlewares = ["api-stripprefix"] + + [http.services] + + [http.services.app] + [http.services.app.loadBalancer] + [[http.services.app.loadBalancer.servers]] + url = "http://127.0.0.1:8000" +``` + +This file configures Traefik to use the path prefix `/api/v1`. + +And then it will redirect its requests to your Uvicorn running on `http://127.0.0.1:8000`. + +Now start Traefik: + +
+ +```console +$ ./traefik --configFile=traefik.toml + +INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml +``` + +
+ +And now start your app with Uvicorn, using the `--root-path` option: + +
+ +```console +$ uvicorn main:app --root-path /api/v1 + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +### Check the responses + +Now, if you go to the URL with the port for Uvicorn: http://127.0.0.1:8000/app, you will see the normal response: + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +!!! tip + Notice that even though you are accessing it at `http://127.0.0.1:8000/app` it shows the `root_path` of `/api/v1`, taken from the option `--root-path`. + +And now open the URL with the port for Traefik, including the path prefix: http://127.0.0.1:9999/api/vi/app. + +We get the same response: + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +but this time at the URL with the prefix path provided by the proxy: `/api/v1`. + +Of course, the idea here is that everyone would access the app through the proxy, so the version with the path prefix `/app/v1` is the "correct" one. + +And the version without the path prefix (`http://127.0.0.1:8000/app`), provided by Uvicorn directly, would be exclusively for the _proxy_ (Traefik) to access it. + +That demonstrates how the Proxy (Traefik) uses the path prefix and how the server (Uvicorn) uses the `root_path` from the option `--root-path`. + +### Check the docs UI + +But here's the fun part. ✨ + +The "official" way to access the app would be through the proxy with the path prefix that we defined. So, as we would expect, if you try the docs UI served by Uvicorn directly, without the path prefix in the URL, it won't work, because it expects to be accessed through the proxy. + +You can check it at http://127.0.0.1:8000/docs: + + + +But if we access the docs UI at the "official" URL using the proxy, at `/api/v1/docs`, it works correctly! 🎉 + +Right as we wanted it. ✔️ + +This is because FastAPI uses this `root_path` internally to tell the docs UI to use the URL for OpenAPI with the path prefix provided by `root_path`. + +You can check it at http://127.0.0.1:9999/api/v1/docs: + + + +## Mounting a sub-application + +If you need to mount a sub-application (as described in [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}) while also using a proxy with `root_path`, you can do it normally, as you would expect. + +FastAPI will internally use the `root_path` smartly, so it will just work. ✨ diff --git a/docs/en/docs/advanced/extending-openapi.md b/docs/en/docs/advanced/extending-openapi.md index f98be49a6..30cd857d5 100644 --- a/docs/en/docs/advanced/extending-openapi.md +++ b/docs/en/docs/advanced/extending-openapi.md @@ -52,15 +52,22 @@ First, write all your **FastAPI** application as normally: Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function: -```Python hl_lines="2 15 16 17 18 19 20" +```Python hl_lines="2 15 16 17 18 19 20 21" {!../../../docs_src/extending_openapi/tutorial001.py!} ``` +!!! tip + The `openapi_prefix` will contain any prefix needed for the generated OpenAPI *path operations*. + + FastAPI will automatically use the `root_path` to pass it in the `openapi_prefix`. + + But the important thing is that your function should receive that parameter `openapi_prefix` and pass it along. + ### Modify the OpenAPI schema Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema: -```Python hl_lines="21 22 23" +```Python hl_lines="22 23 24" {!../../../docs_src/extending_openapi/tutorial001.py!} ``` @@ -72,7 +79,7 @@ That way, your application won't have to generate the schema every time a user o It will be generated only once, and then the same cached schema will be used for the next requests. -```Python hl_lines="13 14 24 25" +```Python hl_lines="13 14 25 26" {!../../../docs_src/extending_openapi/tutorial001.py!} ``` @@ -80,7 +87,7 @@ It will be generated only once, and then the same cached schema will be used for Now you can replace the `.openapi()` method with your new function. -```Python hl_lines="28" +```Python hl_lines="29" {!../../../docs_src/extending_openapi/tutorial001.py!} ``` diff --git a/docs/en/docs/advanced/sub-applications-proxy.md b/docs/en/docs/advanced/sub-applications-proxy.md deleted file mode 100644 index 03a7f9446..000000000 --- a/docs/en/docs/advanced/sub-applications-proxy.md +++ /dev/null @@ -1,100 +0,0 @@ -# Sub Applications - Behind a Proxy, Mounts - -There are at least two situations where you could need to create your **FastAPI** application using some specific paths. - -But then you need to set them up to be served with a path prefix. - -It could happen if you have a: - -* **Proxy** server. -* You are "**mounting**" a FastAPI application inside another FastAPI application (or inside another ASGI application, like Starlette). - -## Proxy - -Having a proxy in this case means that you could declare a path at `/app`, but then, you could need to add a layer on top (the Proxy) that would put your **FastAPI** application under a path like `/api/v1`. - -In this case, the original path `/app` will actually be served at `/api/v1/app`. - -Even though your application "thinks" it is serving at `/app`. - -And the Proxy could be re-writing the path "on the fly" to keep your application convinced that it is serving at `/app`. - -Up to here, everything would work as normally. - -But then, when you open the integrated docs, they would expect to get the OpenAPI schema at `/openapi.json`, instead of `/api/v1/openapi.json`. - -So, the frontend (that runs in the browser) would try to reach `/openapi.json` and wouldn't be able to get the OpenAPI schema. - -So, it's needed that the frontend looks for the OpenAPI schema at `/api/v1/openapi.json`. - -And it's also needed that the returned JSON OpenAPI schema has the defined path at `/api/v1/app` (behind the proxy) instead of `/app`. - ---- - -For these cases, you can declare an `openapi_prefix` parameter in your `FastAPI` application. - -See the section below, about "mounting", for an example. - -## Mounting a **FastAPI** application - -"Mounting" means adding a complete "independent" application in a specific path, that then takes care of handling all the sub-paths. - -You could want to do this if you have several "independent" applications that you want to separate, having their own independent OpenAPI schema and user interfaces. - -### Top-level application - -First, create the main, top-level, **FastAPI** application, and its *path operations*: - -```Python hl_lines="3 6 7 8" -{!../../../docs_src/sub_applications/tutorial001.py!} -``` - -### Sub-application - -Then, create your sub-application, and its *path operations*. - -This sub-application is just another standard FastAPI application, but this is the one that will be "mounted". - -When creating the sub-application, use the parameter `openapi_prefix`. In this case, with a prefix of `/subapi`: - -```Python hl_lines="11 14 15 16" -{!../../../docs_src/sub_applications/tutorial001.py!} -``` - -### Mount the sub-application - -In your top-level application, `app`, mount the sub-application, `subapi`. - -Here you need to make sure you use the same path that you used for the `openapi_prefix`, in this case, `/subapi`: - -```Python hl_lines="11 19" -{!../../../docs_src/sub_applications/tutorial001.py!} -``` - -## Check the automatic API docs - -Now, run `uvicorn`, if your file is at `main.py`, it would be: - -
- -```console -$ uvicorn main:app --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -``` - -
- -And open the docs at http://127.0.0.1:8000/docs. - -You will see the automatic API docs for the main app, including only its own paths: - - - -And then, open the docs for the sub-application, at http://127.0.0.1:8000/subapi/docs. - -You will see the automatic API docs for the sub-application, including only its own sub-paths, with their correct prefix: - - - -If you try interacting with any of the two user interfaces, they will work, because the browser will be able to talk to the correct path (or sub-path). diff --git a/docs/en/docs/advanced/sub-applications.md b/docs/en/docs/advanced/sub-applications.md new file mode 100644 index 000000000..68d5790db --- /dev/null +++ b/docs/en/docs/advanced/sub-applications.md @@ -0,0 +1,73 @@ +# Sub Applications - Mounts + +If you need to have two independent FastAPI applications, with their own independent OpenAPI and their own docs UIs, you can have a main app and "mount" one (or more) sub-application(s). + +## Mounting a **FastAPI** application + +"Mounting" means adding a completely "independent" application in a specific path, that then takes care of handling all everything under that path, with the _path operations_ declared in that sub-application. + +### Top-level application + +First, create the main, top-level, **FastAPI** application, and its *path operations*: + +```Python hl_lines="3 6 7 8" +{!../../../docs_src/sub_applications/tutorial001.py!} +``` + +### Sub-application + +Then, create your sub-application, and its *path operations*. + +This sub-application is just another standard FastAPI application, but this is the one that will be "mounted": + +```Python hl_lines="11 14 15 16" +{!../../../docs_src/sub_applications/tutorial001.py!} +``` + +### Mount the sub-application + +In your top-level application, `app`, mount the sub-application, `subapi`. + +In this case, it will be mounted at the path `/subapi`: + +```Python hl_lines="11 19" +{!../../../docs_src/sub_applications/tutorial001.py!} +``` + +### Check the automatic API docs + +Now, run `uvicorn` with the main app, if your file is `main.py`, it would be: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +And open the docs at http://127.0.0.1:8000/docs. + +You will see the automatic API docs for the main app, including only its own _path operations_: + + + +And then, open the docs for the sub-application, at http://127.0.0.1:8000/subapi/docs. + +You will see the automatic API docs for the sub-application, including only its own _path operations_, all under the correct sub-path prefix `/subapi`: + + + +If you try interacting with any of the two user interfaces, they will work correctly, because the browser will be able to talk to each specific app or sub-app. + +### Technical Details: `root_path` + +When you mount a sub-application as described above, FastAPI will take care of communicating the mount path for the sub-application using a mechanism from the ASGI specification called a `root_path`. + +That way, the sub-application will know to use that path prefix for the docs UI. + +And the sub-application could also have its own mounted sub-applications and everything would work correctly, because FastAPI handles all these `root_path`s automatically. + +You will learn more about the `root_path` and how to use it explicitly in the section about [Behind a Proxy](./behind-a-proxy.md){.internal-link target=_blank}. diff --git a/docs/en/docs/img/tutorial/behind-a-proxy/image01.png b/docs/en/docs/img/tutorial/behind-a-proxy/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..4ceae4421988a968a2903e55aacd66fc82741742 GIT binary patch literal 60301 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 RN&w_Q8Y()<#WyU&{tLI?+YkT% literal 0 HcmV?d00001 diff --git a/docs/en/docs/img/tutorial/behind-a-proxy/image02.png b/docs/en/docs/img/tutorial/behind-a-proxy/image02.png new file mode 100644 index 0000000000000000000000000000000000000000..8012031401c8365f9ff01c92479e05854bc8bf00 GIT binary patch literal 29123 zcmd?QXH-*L+b)ciy+L8C6s3p-qzNchx`=@E4nim@y#$cnLQq5$qzDA0_Yy)v4J84B zAS#3+CG_4QbO<4|oW*{h_s9E<^Nn%N?~^ey*2-LS%{A9O=iRRB&SyOxwX1Y&bTl+H zSJhuUH=v=p&`d*fUjDDkKnn?ZZ5cRR^m?Xl^cV06{>%0g@cSQcm6zUz?)Kh(uRZN( z3>|&Ez3n`0-v9ZVhUN~9`g0{C|IxLH01IQg*bU6y&Ub`}kXtqxS?V9Q zqo$Wm0!i%BV~}pI?nd0Me2-VAjUIoVYP7&_JpKkSEgG8WjJ7wum3H_mZBX{eu(GnU zELX}U4F%Xk&CKxB^JhK8o$ag42IZn$B@vQtiIX=%SEhQyIIXE!51~fm_zEFGBV1O_WA>t)@xy3Q_L0u2$%h$-|AP{D|mX%84H~a<8jw`umwb5nN1CJ7<}lnI-s8+bBTDusQ70tR^fqqAhnfo z0B%^$!11YHw#r^2hQ{^LOu4yW@NHJ_E|$8Q}CAE>zyPU@8| zcvx9w&d%AuQodSU|HR3`0ql^n{vus|MMdi(-K_YLbVN+XsR8m_kbPGwDpS6tL)*G? z9-2zp$GKQ6!rdDRjS)jeY@yl@5=>AB2KDv!6JDEtjkro;DTakwCb%ZQj*$_wfPerE zb#?vDn2f`{{%{%3`PleMY(2*LI8WCI;krJG?$3*jArLGvzq`7Od37@fP?lH;QkPRl zPmg<_^%vd6E&|-JJ#}ZC-nai~uSvVCali7A@n)%Ekq)8GO<(?dhO8l==`_X3|2%|u zx44I0oSsGX{JMUsXRjKlF17sr{dr)sm6(ZfWytvC+6JnsVq$oXa|B0gYKf8%g|}~M z#ce)9ybj>={UnV0$q^ZrkdV;O*yuwPk|K^>WnW*Ea-Xz-a>$pg^gFZz8ioYb_I;XZ z6{q5;y%+L+^4-0gqnbsWoy{dX;PN^Oho@X+yWOM2bPRE8`lu9c^-%3DamA*sB(X2nh^zXJD(rW4@3Rf&hsa6rqs1`!;&D8gk@|S*yg0le$($ zD;FX>ce9`yT$q`U8*JV~aq&)3tU?32W6(j_%?3gB)tgNDJ&IJLSb0e$+>f;oJ&iS4ljfOIsk$)3eg<(M==0 zxU#(}hZ1IBHI(b!`X$q}D=I2dB_T&k= z7Ut*q0EO%B?v_CH{P@9b_K;;FU}-(_^N2pGQxQxx^P7;+>q?Uvf*TgiudgHb*T+VL zh89+F0#Z_@Sn?VyUlGZxjv-Ixq#o=g90vEk0aI5T>gzCP(=s~RU)N{>8zoyZxtpcGKG^d>P~Q{R0-mgC|k6Kj!siPl*YdC#62J| zuoy~h;^{vmZz9T?4lyPZM}WxAZ)Vn@&3puz&N@)7hb+ zgYjpc%+iM-A>*_2A?CLH!}dGyX19!zy8ThqC|l!*o4Mml5l%V(7qpDGlB8bp$?rLeWNHQ;o>WBUpF8xy88zJ~pM8iOM1nL!_y$K0g^7)C9W@L(rErlKiYJWvOF`=sjlENL&*9^96$JawE2 zX@%CB3a(PZo0dN0Ujp{#y|k`EB8t9u$hxfG=k7#eW@ZlVxS(o$d^|BD1Gxb-fBTkE z`SM}>UJ=PwoK3=Qt<}6KxB%FgVez8OWrA=G{1aJO;@5~@j{9qj)o&IA)ccwsN9eb$ zG83L&ADS#MTJd|odhqcMK&CF5P80v#y1_V662k&f_D;^1R;xL#a-6n6V9U} z_bXp60k-=p>!ExDK}gLq$a(e$9c_caiPo0k4c=9Psa1X51rIX?g%D3KFVm2aCJqh` z+o}<70m}2Y&r!XSP^!F%;Z(Z4RF{1fJcvvr)%NBM^moyPm*=GHh4madG} zy-fgSR@!&R!aPk9>7z_0N(An;^7Nlgx2)kfJ{ST?OieX$dZg&PR(DF7#RDQA$_n`@ z)+2{hxoOv(aLU*0)dr!WZ;fFLG|_bql3t| z!#_@Dm*K36HYUo3I$(%_+D%TnzgG&EmywtajN9RKt2EEpQB|Px1O_c9FHf@B8`Qvq zV0NQ5jn9OIg#%aNIN~N$QR)$_-PYjgQ_Ya=)8{L{ZnO0uDz9=p0j#Kz*|uQJWQqhH z1*`RcRSI}(SB^3z&$n+Yj%39Im5=sMOYFOX2OezEWhg*2>ZPT9F92e!Ga-rr3QHPu z$Bk*zU%4_+n$o}5CB-g&bi!zdHYW`v+*mumGw)EejEQr@_zlY++D=*sS?z>Rh8#`g z@>#v@yD8@%2be5{6K|{ffRjTKp(Q+PjCL2^pO}!AS6wY86SVIN+jsc>zGsgxTBdo5 za+Hs1%iYAq_K~O5;MO=HR75iPqpbv$)z%`dOMK1_2@OfwnZIoev*KXwK}oPlSM+BK`S ztSle|aw2YIbzzs!mnYZ8Uio!hWAX$fw*^ZJdM&sGPf+K5wB=>?@| zJ?J{|&(z73<5vf4N0MKay)XXcdX+L@?Efs&a{U23e7_nOq%=L9!_Lk=iQZf_Pygg_ zpWu)s)OYCKgie!MeRm|`I8B44Ne9$zDumiNYNz|+N#TbNHpW&8nBoQWI&-oMo@E6a zowheWmG!4spNuCEjIn;3UjdU_s1;yhf-si#+vtPmF1hrW>Z-*)0KDMps0-G4tR@nx zY-E=*_xW=N5Mo5^ucL!09c)}f%CwA5)7j^Cww(%rW#Z{?edd1VhwNYh4=|6@0AtEC zQ|n#31b7kwF|mZD(0}b7KMgAr6A-FspPqKDTlpF3>D}Q~<1HvGV6&Ug%P`9ylr7jqa`YDp$S2 zRhShrit6X*-`U&xW9fG_k>E@ac`VDV4ulNMRW?PpLzdmmYfssMxC}h8pOBuRjUl4m z0nW@GM&uV1)TADHrl`i;EEIEcij0=c#+{M`>ao~l*E|9I%ZDtG!{ z9=KhQO!@=3`!O;DGZPb^kdXEigxtv8KGb8{y3wcx9<4S3;#Y>-a`_Gqbop0)9`&ku z5gO`oRuGak5K;_OE(j7H^S!93c*|VVeR{krBIC9AYyy|Qz|&ghPL*S@*f*yPyQ zSU|IU?wn>n&`Eb4x*ELDVT?J&{DZWng4JnGHn5vMW8hlH){mPd7P|3!GZ9?v-(UUt zbggwBP{t`}ER5i690C{aF*dWG=Np%mm33akomWjwEv8eY8`zCgV2iS|0j!CeMU|6HF8NlqmOpd@!XqPE{A@iEP6fvjpp7ZS74i2mmE{pf2 zYFjoc(d&m_Fn+sTGoFv0EYG(a?riP-DG%Dz*KtGDxQ&@0?f&fj6AY-rpO@l}G{PaV z$h5Q|^U4bYYyEOgNyk|-LgSGm?#Sv$!)gNY zes`9YvV{S2TF}d22K-mCME12gSzwcdY90pG$_X4xULo5PF3!Ld3pEWe5wRc6QnFAN9YCBP6B7f(LV*9U zn-hEGNs#(p>=VnC|<#IV2=mU$D7g=fdR9GD*sjqu+WU!5Ik{wvQ8Eqs3sC43IZjw)Yvc2t?e-0^3QoR0418W6G4 zNZ34j@*9{0gDS1Gv`mMsr`y)hLpDwhTW|3WNAJY2uyz5Rw%sqY5;EGg%TC*V?X%}q;#P_+nuWf?%%fr z278bI_Z_QTY;SF~thcYyNq=%zeP?gah@l^1h43t*Ht6)D+|c}_IA;K1%D7$w+@FWjdsK(kXGS z4t`u`n_loQgtMBShCqy4Sh`fZDJi|{>qiW|uz7ToJ4~tG-b?+!veCXkhL+a!Xjhh& z)`gS``!FpNpOz-5X_a|};bY6(z+Z$QR!2rg#;$MDmhs{t<9V#MyzccRdwBL!P|b01 zLqo%5iWYGFYEw{o;ND+`dU~|#2EoTlCm5oski|g?U^scy6S5$x{Y72H1c!zB#ox}z z$qWeqPr1sapfxii1>`I`@%eRiPgGREz41KOe0jyejvT>ZWu|)HmB6u@=&TvGY!{SE z-X5nS(SwBqsBFpRs7o1)`{X94WgZD>g7Eb8nqM_Q{{yZvTUcE!yuquJSbc0Vu*!bp zMxKPrpuoL*7V%8CZWWxna45*l{liUKL_`E~CQq&-zKI;-Q}fYVmo8oew!S7q^j5%h zAo!dx15QbaGoL;LcsQL#lPIZg`h_E++(at(8vDc~(aGN4MIP=>&pQ&1+W+h^kIXBbj0wrp^OVhNS0H z3_Fz>2Az?$;tM4AL_K|Ff1jk2eh43S;;9d=z6e#{V!hEZ2){48ck+`{L%?dh*EHk4 zo3Ud#ZhW`O$JH-i^4R}5PpzP{EY81TFk@hl@}Z{x2jF8@UoK6*0)SH3@ez4=m<{~P z9-ln&CMjw+3wQqskc(fs6rRTz6d34y@F`N+#nmYd@+D;Wd@P6GmsM}agW6BgFCh{tI6tKMDk>jxL!Yt%a(knpcqM_dD+)jtpw^9|r zs_F-@d|*{1Afs1+Ou5Xb);+0&HULmF`IEf_8IS4E4J`G0{1*14$PrA1muqUiF^C76 zlsKPwJf$8l(F37jao`^KMv2D#VKD|!nMD_ zO)s z>QUlDsaH>_8ng}OSbK26Sg~s+U@q^uF}Uyia-Ge00M-P`#%*(pWA%ZK@XPW)8&INQ zMlFrC>rAcdzuO!eaU}^rXqqUCAjoc4Ewiu~WyHa|OJZnX#KFYDsBxw>qP@T0kWuc@ zVFMn>XH*1Dh5NT=TKBf0i^e>s0`obnq!)j5xFZj&Hpg}$hZK%8OWEG_zrjZ z_t0G{^%yXLBx0p;Nbv%nu9xQD?*OwDzc#fl2(<(`E8^;Uryf650&8nbZmYeAwX}z_yNE`l9aIHgf$0xqB zZ{Kk)8RR`YTN+AqH{3*-{vI+Gb;$g)FM(%H=nMzknRffayLX;KY+C|Pp1geh`t{*_ z0wq5Gv5hJ*R*|l?oEw0*mK~oxBb0#E1IPVnenBjk2nQ2A|6MH8g?B|ZrWV*uYM z1mFY_bvBtjH+h+mQUGs-w?@P+Bb~&m?eL7g#3`Slr}F#D{%EIu^INx4G_4&iO7}1o(8H(y%sd7OzQ#fh${uHu*njP zDW3#|5P4{7ekDtEEjw=rl_8!^Hnw>BV~Itrf?8D|KY2yBxHxe@9!^%-S1IL4a7KnjK^v` zW1^GIHs~Bz1VKA)1&f+Hf5+jxFfkm8WUIw_8+B1XFx+IrARZ*N#7a9D%0TC-J{WUQ z6+cd>@0q|z-!YSwEHimOVtLA0W=u9XhqL_gYNGe9rfe>5Fo{Ft(!?LblMT;-$~I7< ztx)6{*KPG_p6ND__!a5myJ` zJNj7;jh0nPwxG)w2OJv#xX2VRXI3E;V`*&N^1CCo)d^^iLD?2aGt)F=>pQLZ0#^cn z2SZ8y`&ooiGqJXxx69MWKr#qGGX8DikbM zp2^l#;*@b*C|OvtKszwqo zI#6Y{f5-(55L8})7vy?*R(7vyP^A2l7*bto)+qaTZL&3a12EOa4&34I6amY4swv<{CsGTMrJxyOlmFSTnM6)=$vrIF0rg#)Kg6euB>zS z2g=Q}y~m*M>wOKG`zze60B0-CQ)Fl$4j#QCf3zk>2Y_iM#xB)?U2IspLT!};ks zXuyYi^V9%9&_um2Q$A>Kj!{1nFc>=vg0`Y5|Dr+fFJ(Ca7})xtm#^=jp{~v!pkZZd zvpb0!h&%NWCg%cuceueLJ7ECNNSaT$Q4Qc1sU`v<-@1~VVR@qb{QQwovU*6-jM%m} zU-R;8)T1EaFM(U{T9%-!15nNKxl7a<%jF?8i9WKagw-i#4ptv1xR*V7lT?#i)zO0^ zqW*Fs;tyx#Y#x3?Y{M4=hi@d?H+hO>>8-h|8?bY=W05FlBC_?UTT;tdhRGMIGXc?a z;AtPSwqjU`)Ge`f7jfaYju1ad)hp@izmb?YVhBEgaC`M0&oN&q^l_~X(Y{@rraE5M z48by2x!|t%A=A47ao+_*csPVFTg`c#C*k;q#?m(>OM$W(jJ3PXCT0#;%W}q8g2e6& zZ}pv;_t}e3>^)TS8!M_ROu;JEWZ*rK7%V(`c!UQP!Gb$1cI^+uhfTAvH8H8-CiphxhrUAl zX!bYxA2nO%)mFgRaM>+Y?eY1`B1?iza|F72VIyT!lQ|AWF_@yhW&to9^F@fLH45dn z+IwG1GbvcVuZ6g{T2fyAXnnjMp*mA5u=xdTjs())j`nu_H*XB;O{P_%Sb#*bjgFCV zXgqe&`3K}a)3s}N)z4!7L6liuOoq&gwMb)Wh0QPLrzt~H#^Rpd+6$>&JQs-O55tAf z%#EwY_d$iIm zZe9$Nas1i2!b7|JMo<3$iB~Gmg+5%FKTo`T2aZylOxq zMUZ~-640YFl3GW{_i7oahwCgoSN{f78BB3{Y^2Ac?bn^<#RB5bbjWKdxb)k%n{7XS zIIgEkr0#BWoLw0#wM5o?EhT{z`S~lXR*B2K7lFXX=!wDp_ppdW7_6YYoPE78;^Sm7 zfa$@~(hxwPa)wU>!8~HO($3blBt^H%ITJ|~%H3De1roJ0-q^OC)yKQg60UYTGA?)0$kvM1NAT1wP1j{A^FwZpnM1e* zq@W=N0t)e-sUZ^+3Um<^Rz?JM&mHYS>OY+S4iA(L$gIIkpwz?CT&BiF=+%5s+m*7^ zU@nc=^C!e>8NchzhxRa5a79jiOkSBx#3j5ur1rWf&jMF33bMlHd4iFw57Ar6RmyNm#e_uh z(o<4jk4*YpLAR8J2zBpdH29BznGLg7IrfmuR-Bd*GWb;-@#S`mhT=bEhPRdIoWKNl zzgeXWZE<~CUMGAc_XdFfX&b(Jl^t_i`_DIAv3^*nUEJtaJ%L{PL z`*<3TTepn+FrbHZTJAq}zGpB|Ac>-)VgvBb-9~1K!{@511WgEljYAG*I8IJBb${EV zSBlmZ@$K#EDJdz3zq-E9 z;7mQ88bA{zcD6jqd`5gXNAjBdCUdev4$T(FEzH1@CtIztOG1W(^By62vbDs5b4zdN zzhAu;5=B00WmM>!cgX5J`w~q3dLtJEH8IN8UR{LM{-Rnp+}wUkoHY2OPI~c#m!klK~EUOvXahB$xW0#N;tM?lciwysVb)x?`}*VkiA0=5udL&)wW%b$AQ z>%#Cy!#W-1K}k}Q8=<12-P)QmnZ;0Md3HI^ACM(fkeDbFy91TaT2=MqJzQ)_ZQ#*X zUOi9`QhG+ju!-4MpCRK}0a?pMSv4*IWdMW0kZX?ZY@dI}JEMR3+1UNy_3=tc%he>o;h^eVE z!+X2B-ELX>(wg&}PyP{6-yyqOIk1zrw#os%9;F(DLe2K(5XFv@2J_UuJy1N-Dwx1U zg?ZWu{UFGMUJf%bG%O)do1nO+)F<2gKor0yDq1o>?6-C^|I;TAJA3<8n5mT^KvmAn z4jdQuvW-ZZ(6hK13lM;Wa8<9?1-rWaiwg+(vDJXJ;VFB9>Fm*MjbQ9Y5BU=IR>Vj_ zuCB1!mE~n_F0L#A%P|b5Zgp?PHbsafnw|XVXAC$OA?9>9P6!dVX7!W=gS=>M9QPq}vRvdzkDT;{r$jDXr>66v!aK#qw zeDk{tk${Kf(QGQlCRq>2(?UsX63@Ukiv91AKdb>vqc-qEI6p5hNY;0wMEnjGgIW2t zye#0}kH@B@YZnR#fwIrnW9kI>`PDNsGgHOL_b<`oUh{%V~P#U|X`QJG)lf{NvLd{oihw4+E`{=%? zmbPiLNvzSeiJWTnwj0p`L`R)5npC@o1~&;=U#8_3TK@vj?trT+VZ#mb-M_DV;gAti z+*-zchB2`P4?P6{Gk&1(0w_5l098GRsgR?ST!A70R%d1!=z7t2^&QRlb2G3>hPoyq zLE!*E)t_2Ex_QNUu+uaqh7hEm*JYo8h^p#N*G?XBMZMMZuyLe-wJa(MrOJt{7RUTmDQxE z@pk=G$4jsYAZ|Vp5nU&zaGOd0z(9f7MGuwd9|Z4Y8>=Hc0N^h^{yH<@0iL`U|6bdD za3G!l7u#@j~Ar$yr~#Cw5;bVbx3IE=H)Gl zr(R*W3=r&R4AB>D8^ynywSgce$|4f;<>f>B1v6wv?SkOH_$I~ZA7FgvAFn*(!otG7 z03?%)4D4c2;8jNk)rG}xc5z0p;Lz@}D5(GF~ zeV{b*^#Sg}NE)Uejzxwy^f4vO3F1L~s!TIX{?QMg>LME_w&?A*wn0k~16qa_|_@dg_^UqYB7w4^Z3{wZ?WPdiL z|72m??p90nuv2ELY*L^;+hhgG+uvz^4Cn`8PDtR&0bk{&+LZ~OSfb2*A3BSNF%Q%8 zzwR=^vSubU-Gfi7?^z(&x*43hTNCzHdP|@+?F7rrQz0e}rqZ}S9;B694;2l4YTONe z(9@HC3KbSYvt4=7iv>&KJ}#*z-cc&I+IeBupa!?DOR3SE386dzh;d9dd!5upYlhYt zKa>ceJ)J5!`=s+%LUt`vo9g)mtnsh&Zfxc9bkF$C>_jf1Ls)L4xN3*!O+Q^)p@Y~$H#TWq# zg{cOYs(U?yC%)%^2V}dUn+(OQ*o_*Kl=C8v9i1A=W8C_swv8@ukGvsuG4ifIpoD+m zdu94%pCw{8oilPgwLqcKWs*n2c1=s0&PPCMB0iz;$H7amB~Hg>zX(Pj?6QdLi;D|d z&a^goZ3op&L#!_ps^SbmQf-OuBbR|~9U2wWYnhC8%Q3k)s=DxEK(cM5nD)geS3&Vy z0dJjP{?v<04nG~;*Xl#BH##9i1Bbll!3lCFV@B5p&J*|#oK^O)+B5xG{bI!R);gY$ zs(Xx6dA;jTj9`OqHq?`@&-(NG4;i@69;B&f|2|hLxTts?=h8D{qal~Z6Qv?rf4E#Z z2;Lh)NtNj0#+ddUgl?0LN7ECByAFL%OjI@%OYi^cPmH(usGmWE@H*N{=={NHqFF&7ttc&&f;01g%1q;tv*YG;D%q-C8g4D=I`DCJ_pyW~ z3v(lekMCuU{E_oAC$qca4(WAZh#}A1=GeaD>O`0X`d~BrtGW2nZ8UO~_+Eg`7)!d- zMcH)pd8|>HJ|KcHbqW|@SeFhq;AcsYYfK|X3g2aW=6;)1YBVKapTXJ{)1U0S!-HI~UckfTV3SzFJmdB*?9j;5VaE9T>;F?2vq!maW z=78Gnhnifa2eh)8hxf5F>XfwUGYb0d^(uUVyFc+JPHhVHvLx=S?uvC@ncJ`_Bt4oi zYv%6K&B%+7c%hkeo$;5zwnynbQz#tA05Lb@qNDUjE&R~lB&L|L`*0U^s*G*}W+LQ8 zFZ&?8CqaZ*kLS6?W4XmL_Hf-H_p0%yi1}NAd85MSfg2;Q@V8aK+Wny+B>!`poTYJh_&sAG8R-gN z1>l)Id7Ur2pesUM6L!{INuA=HBWN=>R7 zfd;q6bOqdw?1fHeRki)Mov!}v+$`Ls${PTKv>Dr*y!M-)N2XH7WzBtu4GKGdRZFdY z+gAk-)H0qJim6_<9=`zNoGKyPLrU$ieH~m9pk88Lysm(-eOi*xp8oG?wY~9WJ+!E0 zF6mPC_a}Onnt3=vq#6p|mYH%0cT^Pc+s_bF#YIdOFVo{5r&0!@0?Tr@K&W7|(W5pO zHYtD;74&wxHMX>xB8C5$RXOyNm$Y6wBp!rYxOelrjP}?5BFC1sNM*b5BY*!Yd!5u= zxMIGUYb-9-sSY6;7?<;QKswXkew>xI`=GrHhhOODe~?6*bhlcqpXLS-Sk z?4b8ajXTcuTcC})b+Z!I$#KW2HzAo@LAJmo$Qp!hPW(1FReD82D5h3?+V7`wVWn|q z0>5VW-7YBH^_w8H3b2o$)Wg=cF~|r9R^!G4t^V1_7WZ)4yV{Sfwfd(rK?P6n1*X@EJdG=kCg-mHD;r?TPWF_()f+)Add~A>W%o|qp;7SG$BSA8z_@JJFPk5rD z5i(#GEF|j;eQkp|R*k+ns(BYVVW%ErJkV!segnGE^5E^sQR)b~YI51Ku&whtf>JeP z{Ad-W4pw$Ea`f;@@zinJ90W&7ztzIC6t)|&BBASU{U0ha>?%0>$=0p|lYQrUhgBh} zQ-#yHEG~w6*%KD^}quorEz|&Uw zeIM67{TDbTwtq%-nmYQp9uuqmNw;}e+(o@&7aJ%A&lbmvbX2B(>C}E1_;5$PCLz)a zqw~0+wYnnwp6VoAxD6TKl!2HMD|FRm1|{u347A3-p{KXo+3K~s&61(;)mZ71R(~x$ zZg4r1z**dBdRJM^RZx)!Owr++k;RpHWX2qvev}KvvtE zbg9k2#t}JDI)#4++C$(hZ1}s#5sw%5Z#!F;Er_{W=hxfOIyyf7)w6pAmT4=})i2nDq6N*Yk+tHoZBbc8}ow(+(25`bTb)i*sob#CkG% z(H~ym^+p1^p-SS1$Ptz0VO6M}9(vzne8=bBTDxu+!y&!!Bs#W?7I&ku0)&Q7SPVf* zpI5@xG3rqIWBcPs1q;wuNQSG>rxg({G;wT{(PMWUDDwym3=p6b$1r^i@ zkc6MW7rgM3%O0k~35F7RQ}u^fR8a9fOat<5nX3u#@6n`IgoK~6byr=U2M!d@(D&(2 zOJ!l1$c<2fMNSy4Q>b4TB76LfdCf~9(Ce>l_g~(Bpn$BH5t@J49(+&L%Nh!bA}3Si z@!tO?Ry6!}l44ZX}H}`{JV) z&JTPYo+8$3+9%~Ujan>{ZXDp(TI5scrmSyu&({DbLlL zKWXBPq$mSe~ZKzy%=$L1um+VI=x36OyekMOY87; zBKL;2_ayy|Q+a*-u1JEvy3>2?F$619NEbUQ{_gO+hti+(SHx9o9%d+n7~Ce@yhRwn zh9ApmgtxOQ7-W@{4p)Ys|5CXbnVMR71%7JIB7|jbM7Wl$mX^n9U~H`d@}30`@jpiU zKTCa6!F_%SK9x{;|6c`UGgo^xsne>I-FUeI+Kysw0- zo|cuk;}4r0vksI!vt!!#FCU3ldJb+=0(v>955ds_yOYL4!b=#%WV-iK5jDLf14wIUvLH zeNcwDvArRc-JZt#_1D$j_$Cq;Ck43k=;*<`Z9kGqmTtD?GZ+X?(eDzZd^n3M za+r_1DG@GDhjf{%2qD=;{q0vD>6uC7yG|6!+u@wo-3XsHU=v!~`UlN=6!3(jU%vp4 zecJx;Gw+NFry75;lJzWPA>@x$w!@Eqr%1NHF{C(DuDVhgU|hw& zTP~1$+U|-bd;Y9yjNk?_lW*ITDV3TM=Pv^5W!6NZ{kdDuJb?HqT=*!PV1o%^c=x zNk2M9{jq{y-Qm(>cOf@m+1KtPhU6sz_otZUv8fAtjruoKtu4#$FW% z&SR+hYC;J0p>zPo|0NTas#m}H#X4CSdN_{Ug?*=!1RHs;F!$W!Vmx5z5@zmnsnR=G>eKmL|BJ7+N^W{qElv1$VDDgXMmR=T6mfK~Z;Y=}EqM_Qu z%HFuK^#zL&i z7{14=|0lZsd;i&kJaEEB`(SfPc1)SGqY zcAoObao2xFYZT><|0ufepe^W!^sVq}8B9VN9=i6zmy^vM-a_EupY}P(S1WuU6`h~l z=9OyGdv@u{qiaej(#yNF#mDhnbe|3ba8?b?K^ygpn6jhH?bB|bi6Nn@O{rsN@%2-3 ziF|IU)M|VSE>W(HlEkjrvMb zAaS>G%g9^u#hMZFem@mfl5Q>)H_44HdBU19EFDG8AgtsLs!~BC^fUyuPEG@s(O zsJo)KR|+-lJ5kzkeCf7Qlq!K-Z+DO}o(l0aPM{Gz$b#)JeTW)cY})A3UDK5TZJNoM z8T)ar*iDa?Wy$6L6uXsG+P7V!Gp;L>8c`Fnfh2qH{|NNm-yXTJ52Yk^9TwiW?(-ce zt<$_Y*-d_@-`gY9kDm)N*Zrpdv#Be2FkLQ(URTekpd%qh67RD<7Hl>zMlCSiw146{ zMC6UNm#<_Xq+mR zO#W~6xW<;ilv zv_2EA6P89jI*JM+N2gTvLG2*fC5ZPEP|B3`O4id2A*(F2;Dg`cSq4XWbfXOgLo^i1 z&9qD9bIiOSHb%-qn!3m?N;BUFvwUaOn5ELRHZP|HJL#VZJR`q=X4bDiT4h9~4j~^Hf|;OQNCfC%kj~nsfTcXtipm)=9xr zvEOS`$4w0jL5vpueHE=(TR||wDDS+xa|mvlt7!_l;zgIu`GpP>;9rH%=~(w=uHGq4 z&5#^PYl?up_laT@qB{du44;^DjIKQCZCSsovq6Z|UF!;a3TBxt?miiz< zOa9|{i}w=3Z}h4T7lSKT-k;0)xt}s9zJ6g-2Fyq(az*1yI*@}`8xEBe-fn&7)Ztv7Htj$o&K z)c%enor^KIf!NnK7UMFWzh$rNx2q5Wib^F3o3uB%Rv0KAVNFmka|Zm99lvXqxfC?M zzC_FC>8e+i`ME>L$^4IZZo!QpSdB-xYevZRH36Ic8<IL!GEgZ=R~d_aESo%*9EQ*>29^d569eMdp;DkBZQt!Ry^jp@>@vug(o+ z-_eYdQ*h}!@;TT{-5tKG5;4Iy6scUfUOq(nP_4cYVZ^FcJ&@Q) z*-Q0^%{3i{`BZQJ{fz|UB~5?yh{mp5Uioo%q-IfIvshU*OUYA6zOOD?xL~NO06GED z(qxP9Bf6-k+Rz(k7kRg|<(gI9TYZnC%BQm9%&Pj>7}|W6$C#mi!ayxd|Es<44rjaj z`%edLDeksLY0+UNic+IWXeny15PR=kTL^8fyGFGnwDt-iMr#B?l$H{-c53gv_X?hH zfB$%%>+1Df-|zG9?|1%6&Xv!}Iq&xwulG2w4;c255(k-|J6G-Q6b>0FbHV$}`#h5O zIx4^$Yn*9j@K|7Ih?F?|+MLDK-u2uC`fGwJ1N{%5pKvVZ7$2xMqf^0-9+-JY#Ka0~ zQ4}2uorurUkzUM^V^QY)2P_No8tWtER279OH|9HWztlkvPp;znrI<4>*^rFp6@y&q zeOtwja*wya+B8O$HZK8n7zdE$^*L{DMA!L7s{KtYgcnDjT#}@ueV>r1VgcRDn`slz z{P_M^*V{C!#4SVB+N%2~9ItzmO5^Y2?1Heve9t6C$(>4}dkxmiOZ+L1vujwZN|28e z;d$Pz_a8BceLTrMcY21+y#4k2P}pxxw9v_2wQ%yYv3~e+w3__+pnXG5IVYWw_#+ya z{B43^#q-TR#Tf;yGK=49{OIXBjo?kkY0hIs=I~qL@vdS4`L1F{WA>?xoKj4q0XI$R zF1LTW#x=-`ZQ>4aM>k{jd7Wt(w`sH*9z+&UOY2&HyRl?2%W0(i_=WjhF{K?@RhFZ_ zofc2{lQ<}7I<~@`PnuVeMzPsbUJ5LsAq1HuAu4C4z`WOtoX0P7?t!a0TRdUl>Z!dN zmBTu-?iuo81vePnV-m#pk&Ankdr=UwNjm z+ls@kPt%%A-VmSv(^`;f9-#g2?eu^ajp z_}$U6u>{#Yb(W_I7MF$H_=G6!`!=scIC;fh^BLY~4bmn=-SHbDc{J+tfBS@04~aE7 z$+8KhaUd=SfL-tkEqQg&q0jNe9o%6B%r8vNq|n%~&$Ti~YIjxXGIK{j7b@Omv^(R* zaR}{>6B!0P0xH4p)$C`RF+F}Q912E5NBy3?6!V%rUYLS;cdqv@AJ%!-35l^f=&t_# zCH~#^5G}3Fl&WexYq|Z=PhOH*FFbhbcM!?o%W;z^9`G>_k-PHVv@YkqYI6QdqcP=A zdrW0>pQ`D9ry9=Ryaa^xQ5$SQ^b&@J3KSNYGC~v{7?-pcJ)@iN?Fs6JC`;67%!wI& zQRnN(%x%EA^uYjV1-gfB(eAbLY1<3;B1@!>Axna0N^buwA;I90z#TD(T5DEGlo>j2VPbyN4 zJp#Npk52+Iq9V2ORcUga=B!8V7Jp}wuS>0ugw@a#9QFK~$9ZAM;p-7VkS{-`-q9aLEM zWj9rVtq$z=!kWQrRot@foX{a%oV90&#R@*lCCxOrjqcbaGC&u&Jn7_obo@7nHTFw! zbq(AVA>N!hXP&SY)HZgx-4Cp?zSB<7bB$YOzl4BpXb&GHN6Y*9j-+RZks~;sl@{C~ zB58T70NjgWGN7MrJLya9#KXOqfULjkVsy{K`&*ZP#IPrDkP~`KhksqUa^(ZZ(F2a9 zp^~KYZCB4OHv^1r{VNpve+_K^2eI=%hROd}Nk&a)VdDQu_w~ovF|lCL?mWQGY!a$9 zpr94_8lo@f52y@~96|v~g)Q?v6&^321EjoSGXp$!>=vD$mwqAPb0hGaQ6N&sD^0;8 zP{7(X7YsWHZD0j2RhK;;PBDWLxn1j!l(|LrewoWF3MK+0?-H~~T z93LbMn(ij8QKxg?gjo*He&Ar`$p)VVC{xe}Q~PmhfH~k@y;u;)p8C%@7JtlRcuMER zs!AR>3z-E#B{FET0k*x+J2CoC(#2f;_-@;$M*|*ab=c!yYDhM4K1+CTn0+XwlPB%< z1ut^i;`w$PnTLQavoqaBH>{3axKsx6NTEd{{t6t-Xd3Uxh`oN~H9Sk;<#|ke2Y8hl zP8JKm?dN=VF0yp9j#E+W(nX#Ftl$Ro=HR-cCKz7@@02&)(g15Kckv9chl&z z?4j&uj+6rN#=q?TERd(RW{h@#Im$j_T1SoZPb}1Py}KY(0AzmIncPrE|J=FL_J}`G z5%4`txw_QBjmh#*gRN=>2JvMb6nj<`08p4k)(j4ro0+RhoTA=Y!?iBS@{TXqsw?+c zE`mH;%P0(P`yZzl?=P^bsBPN$7(2 z-cF<$W8N45-3XgXJN@XXIw$QBV5Es!5?|{9lpzVL5L+=Z!wqcMdB<4r3%cLzYu$EB zKtM6SutRK7ck$cOs+9mx+q#f!+8$Y5Va^I)O+p*i{;V_F$6;G}N0E7rj@VZ3bUnFV zHD;PrA&QHg^OK56*_N-{g$r5MXMVyT{Ba4k^67$fm!NREQWn;;3p-R_m8G z&|(jy5mMlun+_2a+Rf7)IS_7FZq?D8X5)hiC|?s$jjd|mP%3vfhVQWk*6DJn$M*B& zVIj=L0zGevd96&-_zs7)tzMc7WG&Jcl5xJ*er&OvHuuHF=PL$Ym_B`<(l2Dckd_Gz(`|8dt*wF-9d$fP{o5rlgJ)bt8AdOkuNxoStM$roak^>` z=#Hp}XGAK>-4fX)8ctbnByc`_$`~m(*&t5{t__Ja+ggX3olxGt2a4QwR`hD+CC2Ba zm#z2;9}=a1z|rzo5$^ALinR^0&*x@uM8ky4Ewgf&Zu7@Ysb^g{&86r7*NBMtWz1ak zS<;sm+tt006JBjQNs*iHnTb8FDr&N+wLdyYrKwTtO?Jl`r(P}jE{(FXP1F*b#SG0u z{50_ea{DC)rHF-<;>u6zJc7xHXswM&%W0z73%p}ck>(|`ixrSQ z>o|!sAm;dZtxgsN^2a)GDn!fD=5=0e=g!anMPW#k3d6R>ab%@g*l+>4@Q|Hhf2+Y# zQ$K%iplwj-ZJki1AlJO}3T-+COx4uJ+ftP#Ij>_0kvbZ4h=8kF({uyGH5N1WxHihX z^b)0}yXQ(Ol|?xBOA>BPO*e7qovi{RI3PuIRBNcUri2pF!XSas(-iFlznNU z(D3|#ziPJjH0O`(*HR@>J0Gk)5gd7>Rx$dz??nXd(1V@y%U|bYq*%nBJdNC$=Jn{m zPV;~zKTD#-+UJ9(fmUJmF{3K&E}}OPQ!%pteEP0@e_zpu@*z_XMlO30*&aL-yKypT zq(WIdm%k<~{Fmyi?Hjya(}%>{(}hvLTC)jceyDiN*ZB;gs-E`qDcEY4-=%_kYK>Rz z75u^K;0lnSXonx#-svwH88Lg->}ehF_=r?z zOrqc1+l=t5sef`~1e%o@6&UeJ5Gwe{&i0Jwq=*K79`Vo>fBum)aTGtmc{om`L%1Vg z8WcJ#s=NM0ld1+^8(IZ)w~1w>DCi`#d-v1nqHD@jnxs;NXm+9BSp}6oc391vrhby= zo{@iMS|C)M6(0NRIiHEt`Ww1xc`&CVkr(*AR_LIK6c7dRCAiYqWnxoLLqy+ceF ziG#PwSpn&`7UYu@a7S^W7n49n5U4?yD!K4?h&lHC{R4$SDVpwcS$y#x%a;LjerKoZ ztol{huI|_OcX6(yUm|;9&)h{=>=B|{FTHxBg9E%y_Ns+RO}Bch#d4v54((1dPy(<} zm}S+YuN});i_+*iI~V>;7SDQQ`?KRQ-{ZkSGSB3_Z(hU}vxnpXok6*xkcZrgWP-GX z;pz%94VhY+l>SxWWP@e!HliP@c^ffH^JT zmCFw~(3y}Ri}%AT>ed<`l`syDR@T3AMznapjWJ1_!7BaJ4OmO08gP9 zjf2RyO8vv6YcX@&$o)O^4pX_uTQ2^gB7$Z&Qd~fZO_-njN94bQ-J@fd_S+UeaV>tm zB7B(6UYn9GqeP~`V0p&1lu!?^|hx!_EY09C#FSRl8_-LiCV8vfYy3MSI} zcwaU`94j|p9ig)_k@vfw8Yw(*Ck3S27v758(ZN%xFb@vErdnw;{mdaJ&ee+1N^idA0s@AR7dDoX^hSB$R(j_mUI#~ z4RWYBS{$>v)GM`L-W?HAiiLi*;2z4Wykf~P?l0;an2TT^JvgeJC4ag?X$Ka(M9uhclwHE+U|M{1FIZG=VsO)j8f+L*qes_SdzwgEd}77omM&{m%C6 zYf`bEwUR@eI!f=lm(c+Vi}q{KY*c-RW5SGF;&F?+6e-ns)-59tjifiz{JtG))lqo& z+=iZMPNu9}KICce*eX|K=o*>7pT1X_Gsl5FNePRX~<(1KCTVuR%e?V@u&4nK!ytDRamsdXM@Yg!dh7nZAu zC(>K8P4HzAAfGLhHUc%JFXFH=awu}3U>H}Gnqc<1E)3^Htl0N<2D9miU4+@+uPZ5WH<+ z>?nVH|8V-(Ibei{GTXRdgmJCH{2|dnH`BO+*1LQCTd4c zQW0*{l!U~Rr^(QED{k~;lfwDjSfVFs@1#x3Kg;bpdIkn%e@S`hoQY5>$G;U$B zK|kw?FOw3eHa{(ox`Mek4Z|W^Cn3DBzYPa5Y(|(61rv>ddRqFRhlW5PHT}unjpacm zV_YFPq~6fHA{>N1K`~fT(L&oUvr7e&Z>^l|=wfqx^S`~1mKP7b7MEQTD)_%~&$sKF zUk8n1#P zi7THS0K@7ZCfT(n5Sm_#@iq>9-Iy(B=V2UnKgI#YQFW1bez+>47Jor!em2kC=7e$a zj<}AQaR#DSv|l;Jos~YlMLWk)%@;0UP|qEaR;Tc?m>XDxf8{FmqGu>e8?oPZvx<;c zfZ#?h25WrrkwqnIwILefBb%dhAU3UEUM?HlFkqR-O6tOlkz z+2GdgG3Ca@gM%TQ=xsrhxA!@EXB-wMqTM}x4LMm4)$G{|v~aZ=(;Gc}=7Ncvn71XB z6+VWj#8@LfwZrH7)sZ^$6M0_;x$IY>)~S}XEBKsOhyya#5B6WoS5xb_^#F;-fmFAA z(ymX+x3r>M(ySh+^jIWFFu+03z6OVu`%hn9d4znJA2>^#aWH9+D0#x!^3T5Sra&9pv;MRS@^hy1eQ5>&Tzhi*jsW}NNvRv^3* zI(#}{5APoD^N@tiupufW9@hJ8eB46l)*RQE;A9D~LsdS)s-F0?gfl4VA(TC6Er;>P z3ub!^(nGYL^(UlD!Z5p80l8xk8#w7o9Q8IK{k5cInA3N=lqaypH0zFOV3&61%TnY4 z;e6po_TtZ7<%!i+)u3Ai(>w&7kuiINv5>O`f#`Yjnad!TWS8Ym1tNUEBnFvz`UE?GMcUUg3}o(*Q2q_!%9 z^#ig8{P#_9(HhK@7b-d?+Sr?!-PeR!SqlM+L8RiI>;G6__q@{E+ByRLdFc^@UuW=j z65{jcm812IWj=bXq~fxQ#ZkxNT%M!Q{zQfazTQ+*PJts;&e_Kdn~SsC>%8jr4kxRK zja-IzX(bM(-HCT}@jXLbl5|NpVRW!RPPGGU#mwZ!DBPtKV5BEK2K^PRO?`P3ATSrDk5D zG+t^#IH<}ONoI2M4%CjjtIMf>%B)-iP#hdITd|=+s)JE*|FVi_9UuJB6AS*&j4xQw zvrmw@SY5F}1D+3{yrn6LH*fW#ZHK)eAMceZ^p!p<6(w)Zp%2E*H^{02*T^#ar6x)` zM`X532~k9KuCh@fy={1B^$xM+JpP43heLT&Aw2q&hs{>By_R&*9~Ozx-~1g9b>Q+2 z3sG+)n5PBeVq)5|xEx@WNlPccN73Nu`<6eE=4|X)c9U$@0mIS6M?_sT>7x}b8PomH zHVM8!58w5bgQd_lf9kgu8U?Ffxf>|7Pszh?9_s?esyed3H75%{`e#|K+|LU_Teyhw zxSl+dngyhXTV56hcrr1G4YS-p1qwLz^i{S*vw`@5aRKt8EK>HOhl+jo7hG@S0 zG_~jxm}Eo}c3Nxn+U;HXsRh$~l_R}8y7cAVAUBK`UhQs;&y6VumlZIHdTEH8WfK z=f5e*#Jiv_x*u1C=6dJ7#4X({TK4o{}ORo3t;9EF&8aOp4+KBRs#fIt+3; zx`ev0KFXgol`6v);<@(o^eAZLNBig*7cTj=P7UInMUsxP-+)U}aC=#{t|l1{@=-bg zdd7Rmd>su)r;}FkMuQAP3I_6pN{K^SdX=`$#M&<};)(B)$dol3>Z9T=FVL^(IwjN& zQ+WLMl4V!Nu^Pi|C%4EF!o4F6{!an5`fgm6aCtJXeL}=mbUb(C)BHo7u&aT)IHwBpPz3wSB4 zs*CQxeuMS?qV76#(VbljXA(|NBo?$OwlF!&N?knDELeiDah!gKTa;>b)>k^o$nq+T z7qN^4$#OYtj4`t9Y{#`|@(ki}uOJ?e4P6Tbobah0F!s~(FWFl>lHw2AN*YG=3*6|z2OYD-FW}wfX z^OdOZTC;1UgxIxj#8~n1=x82$*J43X77_W*qrr;89Q50WKGE78?;Lk3B^}R7jZv%O z-Zyk5zruU5_}@2|xLHT;8yysw^shqbo`*Uyl7>wq)4x@t-C&AdG7t%z-rmv zJ_oqc&GJX_2kGq;-D6JeK6oQYS~ufO${<49;eCId)DZ5X-Nf<;NUy?(*M|Xv<}jVN zcSL%?E4d8k?oz(uWtB}omtM_$f!-&#u1nhCujYdoO|1z*6lwZ?yHdgXA(H1}2sdIY zlB;6)C39Y0Oo-!Zgcw88cunQto$>||4wGW8f{s?qs764dc9GP%2)_XAb@^mEkJ9T+ zAmB2^aP?1Z+2AaC=9zxBN9A$MMx4i19Y8^K2*g!lq20_g#=+86Y2N~-n%({#hV99KvT z2iYI1p!f{4C|WQOlSQs>v!GD9(b1Jfyy|4G{YbqqibE=op8WP7is!%`Z&$u21HRzm zwRM)n>gOl80vQ(if{vLOmM=*63bXZWU%O&a-7pb7Pe^9!UBQ**S7<&-#54jO zbs+kD+q=-IY;MF&FZ?CxwG3|Ll3speo&Znzz@6^3hn(OW#V>rM@PIKT;$o`*iuh(- zxow&2=x%KGg~Q!W5THm^x*D^x%M^s-g9(!vA~OPilzq?Pcb}Rj*`C%*RN~&z?lA<-3LvybRYT)^*t@zXXLpFQ&x!* z+qHG2=uLLHCN&(XcTQUCC7sdzK^O&a zkEGKW1mR&GqJR9vq@^>J>=rwbJ$PtenV=pg}Haf}TYb-)Ze%!ST~Ek;{MH+JEM(H2&J1wX#bWZbuCOf9wC1 zRhp)L=2Z5KFhBOHODKw^qU&Y@@CWS~Kzh3wjWRoWD)?0Ou&RhonfTq(Qss&x@Y2b^M@FHFe(l4VZ^n7gDn zZ}Rvmsm`3c|CfROOG5v?X8x?w|Er$=)!M)5<2}{oA65Ft%0GBJ$j|?Aq<^gZ4`$8( zqr-m%P$4r-lgl5MTSwOEEI%zU-23@A{|7>z& z5p?zcQ=tFa{GgTq?&02Jlao)^iOz4 None: self.default_response_class = default_response_class @@ -68,7 +70,15 @@ class FastAPI(Starlette): self.description = description self.version = version self.openapi_url = openapi_url - self.openapi_prefix = openapi_prefix.rstrip("/") + # TODO: remove when discarding the openapi_prefix parameter + if openapi_prefix: + logger.warning( + '"openapi_prefix" has been deprecated in favor of "root_path", which ' + "follows more closely the ASGI standard, is simpler, and more " + "automatic. Check the docs at " + "https://fastapi.tiangolo.com/advanced/sub-applications-proxy/" + ) + self.root_path = root_path or openapi_prefix self.docs_url = docs_url self.redoc_url = redoc_url self.swagger_ui_oauth2_redirect_url = swagger_ui_oauth2_redirect_url @@ -84,7 +94,7 @@ class FastAPI(Starlette): self.openapi_schema: Optional[Dict[str, Any]] = None self.setup() - def openapi(self) -> Dict: + def openapi(self, openapi_prefix: str = "") -> Dict: if not self.openapi_schema: self.openapi_schema = get_openapi( title=self.title, @@ -92,7 +102,7 @@ class FastAPI(Starlette): openapi_version=self.openapi_version, description=self.description, routes=self.routes, - openapi_prefix=self.openapi_prefix, + openapi_prefix=openapi_prefix, ) return self.openapi_schema @@ -100,17 +110,22 @@ class FastAPI(Starlette): if self.openapi_url: async def openapi(req: Request) -> JSONResponse: - return JSONResponse(self.openapi()) + root_path = req.scope.get("root_path", "").rstrip("/") + return JSONResponse(self.openapi(root_path)) self.add_route(self.openapi_url, openapi, include_in_schema=False) - openapi_url = self.openapi_prefix + self.openapi_url if self.openapi_url and self.docs_url: async def swagger_ui_html(req: Request) -> HTMLResponse: + root_path = req.scope.get("root_path", "").rstrip("/") + openapi_url = root_path + self.openapi_url + oauth2_redirect_url = self.swagger_ui_oauth2_redirect_url + if oauth2_redirect_url: + oauth2_redirect_url = root_path + oauth2_redirect_url return get_swagger_ui_html( openapi_url=openapi_url, title=self.title + " - Swagger UI", - oauth2_redirect_url=self.swagger_ui_oauth2_redirect_url, + oauth2_redirect_url=oauth2_redirect_url, init_oauth=self.swagger_ui_init_oauth, ) @@ -129,6 +144,8 @@ class FastAPI(Starlette): if self.openapi_url and self.redoc_url: async def redoc_html(req: Request) -> HTMLResponse: + root_path = req.scope.get("root_path", "").rstrip("/") + openapi_url = root_path + self.openapi_url return get_redoc_html( openapi_url=openapi_url, title=self.title + " - ReDoc" ) @@ -140,6 +157,8 @@ class FastAPI(Starlette): ) async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if self.root_path: + scope["root_path"] = self.root_path if AsyncExitStack: async with AsyncExitStack() as stack: scope["fastapi_astack"] = stack diff --git a/tests/test_deprecated_openapi_prefix.py b/tests/test_deprecated_openapi_prefix.py new file mode 100644 index 000000000..df7e69bd5 --- /dev/null +++ b/tests/test_deprecated_openapi_prefix.py @@ -0,0 +1,43 @@ +from fastapi import FastAPI, Request +from fastapi.testclient import TestClient + +app = FastAPI(openapi_prefix="/api/v1") + + +@app.get("/app") +def read_main(request: Request): + return {"message": "Hello World", "root_path": request.scope.get("root_path")} + + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/api/v1/app": { + "get": { + "summary": "Read Main", + "operationId": "read_main_app_get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + } + }, +} + + +def test_openapi(): + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_schema + + +def test_main(): + response = client.get("/app") + assert response.status_code == 200 + assert response.json() == {"message": "Hello World", "root_path": "/api/v1"} diff --git a/tests/test_tutorial/test_behind_a_proxy/__init__.py b/tests/test_tutorial/test_behind_a_proxy/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py new file mode 100644 index 000000000..8b3b526ed --- /dev/null +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py @@ -0,0 +1,36 @@ +from fastapi.testclient import TestClient + +from behind_a_proxy.tutorial001 import app + +client = TestClient(app, root_path="/api/v1") + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/api/v1/app": { + "get": { + "summary": "Read Main", + "operationId": "read_main_app_get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + } + }, +} + + +def test_openapi(): + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_schema + + +def test_main(): + response = client.get("/app") + assert response.status_code == 200 + assert response.json() == {"message": "Hello World", "root_path": "/api/v1"} diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py new file mode 100644 index 000000000..0a889c469 --- /dev/null +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py @@ -0,0 +1,36 @@ +from fastapi.testclient import TestClient + +from behind_a_proxy.tutorial002 import app + +client = TestClient(app) + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/api/v1/app": { + "get": { + "summary": "Read Main", + "operationId": "read_main_app_get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + } + }, +} + + +def test_openapi(): + response = client.get("/openapi.json") + assert response.status_code == 200 + assert response.json() == openapi_schema + + +def test_main(): + response = client.get("/app") + assert response.status_code == 200 + assert response.json() == {"message": "Hello World", "root_path": "/api/v1"}