committed by
GitHub
33 changed files with 545 additions and 166 deletions
@ -0,0 +1,5 @@ |
|||
# یادگیری |
|||
|
|||
اینجا بخشهای مقدماتی و آموزشهایی هستن که برای یادگیری **FastAPI** بهت کمک میکنن. |
|||
|
|||
میتونی اینو یه **کتاب**، یه **دوره آموزشی**، یا راه **رسمی** و پیشنهادی برای یادگیری FastAPI در نظر بگیری. 😎 |
@ -0,0 +1,67 @@ |
|||
# 하위 응용프로그램 - 마운트 |
|||
|
|||
만약 각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 응용프로그램이 필요하다면, 메인 어플리케이션에 하나 (또는 그 이상의) 하위-응용프로그램(들)을 “마운트"해서 사용할 수 있습니다. |
|||
|
|||
## **FastAPI** 응용프로그램 마운트 |
|||
|
|||
“마운트"이란 완전히 “독립적인" 응용프로그램을 특정 경로에 추가하여 해당 하위 응용프로그램에서 선언된 *경로 동작*을 통해 해당 경로 아래에 있는 모든 작업들을 처리할 수 있도록 하는 것을 의미합니다. |
|||
|
|||
### 최상단 응용프로그램 |
|||
|
|||
먼저, 메인, 최상단의 **FastAPI** 응용프로그램과 이것의 *경로 동작*을 생성합니다: |
|||
|
|||
{* ../../docs_src/sub_applications/tutorial001.py hl[3, 6:8] *} |
|||
|
|||
### 하위 응용프로그램 |
|||
|
|||
다음으로, 하위 응용프로그램과 이것의 *경로 동작*을 생성합니다: |
|||
|
|||
이 하위 응용프로그램은 또 다른 표준 FastAPI 응용프로그램입니다. 다만 이것은 “마운트”될 것입니다: |
|||
|
|||
{* ../../docs_src/sub_applications/tutorial001.py hl[11, 14:16] *} |
|||
|
|||
### 하위 응용프로그램 마운트 |
|||
|
|||
최상단 응용프로그램, `app`에 하위 응용프로그램, `subapi`를 마운트합니다. |
|||
|
|||
이 예시에서, 하위 응용프로그램션은 `/subapi` 경로에 마운트 될 것입니다: |
|||
|
|||
{* ../../docs_src/sub_applications/tutorial001.py hl[11, 19] *} |
|||
|
|||
### 자동으로 생성된 API 문서 확인 |
|||
|
|||
이제, `uvicorn`으로 메인 응용프로그램을 실행하십시오. 당신의 파일이 `main.py`라면, 이렇게 실행합니다: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ uvicorn main:app --reload |
|||
|
|||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
그리고 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>에서 문서를 여십시오. |
|||
|
|||
메인 응용프로그램의 *경로 동작*만을 포함하는, 메인 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다: |
|||
|
|||
<img src="https://fastapi.tiangolo.com//img/tutorial/sub-applications/image01.png"> |
|||
|
|||
다음으로, <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>에서 하위 응용프로그램의 문서를 여십시오. |
|||
|
|||
하위 경로 접두사 `/subapi` 아래에 선언된 *경로 동작* 을 포함하는, 하위 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다: |
|||
|
|||
<img src="https://fastapi.tiangolo.com//img/tutorial/sub-applications/image02.png"> |
|||
|
|||
두 사용자 인터페이스 중 어느 하나를 사용해야하는 경우, 브라우저는 특정 응용프로그램 또는 하위 응용프로그램과 각각 통신할 수 있기 때문에 올바르게 동작할 것입니다. |
|||
|
|||
### 기술적 세부사항: `root_path` |
|||
|
|||
위에 설명된 것과 같이 하위 응용프로그램을 마운트하는 경우, FastAPI는 `root_path`라고 하는 ASGI 명세의 매커니즘을 사용하여 하위 응용프로그램에 대한 마운트 경로 통신을 처리합니다. |
|||
|
|||
이를 통해, 하위 응용프로그램은 문서 UI를 위해 경로 접두사를 사용해야 한다는 사실을 인지합니다. |
|||
|
|||
하위 응용프로그램에도 역시 다른 하위 응용프로그램을 마운트하는 것이 가능하며 FastAPI가 모든 `root_path` 들을 자동적으로 처리하기 때문에 모든 것은 올바르게 동작할 것입니다. |
|||
|
|||
`root_path`와 이것을 사용하는 방법에 대해서는 [프록시의 뒷단](./behind-a-proxy.md){.internal-link target=_blank} 섹션에서 배울 수 있습니다. |
@ -0,0 +1,21 @@ |
|||
# Расширенное руководство пользователя |
|||
|
|||
## Дополнительные возможности |
|||
|
|||
Основное [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} должно быть достаточно, чтобы познакомить вас со всеми основными функциями **FastAPI**. |
|||
|
|||
В следующих разделах вы увидите другие варианты, конфигурации и дополнительные возможности. |
|||
|
|||
/// tip |
|||
|
|||
Следующие разделы **не обязательно являются "продвинутыми"**. |
|||
|
|||
И вполне возможно, что для вашего случая использования решение находится в одном из них. |
|||
|
|||
/// |
|||
|
|||
## Сначала прочитайте Учебник - Руководство пользователя |
|||
|
|||
Вы все еще можете использовать большинство функций **FastAPI** со знаниями из [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank}. |
|||
|
|||
И следующие разделы предполагают, что вы уже прочитали его, и предполагают, что вы знаете эти основные идеи. |
@ -0,0 +1,31 @@ |
|||
# Response - Изменение cтатус кода |
|||
|
|||
Вы, вероятно, уже читали о том, что можно установить [Состояние ответа по умолчанию](../tutorial/response-status-code.md){.internal-link target=_blank}. |
|||
|
|||
Но в некоторых случаях вам нужно вернуть код состояния, отличный от установленного по умолчанию. |
|||
|
|||
## Пример использования |
|||
|
|||
Например, представьте, что вы хотите возвращать HTTP код состояния "OK" `200` по умолчанию. |
|||
|
|||
Но если данные не существовали, вы хотите создать их и вернуть HTTP код состояния "CREATED" `201`. |
|||
|
|||
При этом вы всё ещё хотите иметь возможность фильтровать и преобразовывать возвращаемые данные с помощью `response_model`. |
|||
|
|||
Для таких случаев вы можете использовать параметр `Response`. |
|||
|
|||
## Использование параметра `Response` |
|||
|
|||
Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (так же как для cookies и headers). |
|||
|
|||
И затем вы можете установить `status_code` в этом *временном* объекте ответа. |
|||
|
|||
{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *} |
|||
|
|||
После этого вы можете вернуть любой объект, который вам нужен, как обычно (`dict`, модель базы данных и т.д.). |
|||
|
|||
И если вы объявили `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта. |
|||
|
|||
**FastAPI** будет использовать этот *временный* ответ для извлечения кода состояния (а также cookies и headers) и поместит их в финальный ответ, который содержит возвращаемое вами значение, отфильтрованное любым `response_model`. |
|||
|
|||
Вы также можете объявить параметр `Response` в зависимостях и установить код состояния в них. Но помните, что последнее установленное значение будет иметь приоритет. |
@ -0,0 +1,222 @@ |
|||
# Декларування прикладів вхідних даних |
|||
|
|||
Ви можете задати приклади даних, які Ваш застосунок може отримувати. |
|||
|
|||
Ось кілька способів, як це зробити. |
|||
|
|||
## Додаткові дані JSON-схеми в моделях Pydantic |
|||
|
|||
Ви можете задати `examples` для моделі Pydantic, які буде додано до згенерованої JSON-схеми. |
|||
|
|||
//// tab | Pydantic v2 |
|||
|
|||
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *} |
|||
|
|||
//// |
|||
|
|||
//// tab | Pydantic v1 |
|||
|
|||
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *} |
|||
|
|||
//// |
|||
|
|||
Ця додаткова інформація буде додана як є до **JSON-схеми**, і вона буде використовуватися в документації до API. |
|||
|
|||
//// tab | Pydantic v2 |
|||
|
|||
У версії Pydantic 2 використовується атрибут `model_config`, який приймає `dict`, як описано в <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">документації Pydantic: Конфігурація</a>. |
|||
|
|||
Ви можете встановити `"json_schema_extra"` як `dict`, що містить будь-які додаткові дані, які Ви хочете відобразити у згенерованій JSON-схемі, включаючи `examples`. |
|||
|
|||
//// |
|||
|
|||
//// tab | Pydantic v1 |
|||
|
|||
У версії Pydantic 1 використовується внутрішній клас `Config` і параметр `schema_extra`, як описано в <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">документації Pydantic: Налаштування схеми</a>. |
|||
|
|||
Ви можете задати `schema_extra` як `dict`, що містить будь-які додаткові дані, які Ви хочете бачити у згенерованій JSON-схемі, включаючи `examples`. |
|||
|
|||
//// |
|||
|
|||
/// tip | Підказка |
|||
|
|||
Ви можете використати ту ж техніку, щоб розширити JSON-схему і додати власну додаткову інформацію. |
|||
|
|||
Наприклад, Ви можете використати її для додавання метаданих для інтерфейсу користувача на фронтенді тощо. |
|||
|
|||
/// |
|||
|
|||
/// info | Інформація |
|||
|
|||
OpenAPI 3.1.0 (який використовується починаючи з FastAPI 0.99.0) додав підтримку `examples`, що є частиною стандарту **JSON-схеми**. |
|||
|
|||
До цього підтримувався лише ключ `example` з одним прикладом. Він все ще підтримується в OpenAPI 3.1.0, але є застарілим і не входить до стандарту JSON Schema. Тому рекомендується перейти з `example` на `examples`. 🤓 |
|||
|
|||
Більше про це можна прочитати в кінці цієї сторінки. |
|||
|
|||
/// |
|||
|
|||
## Додаткові аргументи `Field` |
|||
|
|||
Коли ви використовуєте `Field()` у моделях Pydantic, Ви також можете вказати додаткові `examples`: |
|||
|
|||
{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *} |
|||
|
|||
## `examples` у JSON-схемі — OpenAPI |
|||
|
|||
При використанні будь-кого з наступного: |
|||
|
|||
* `Path()` |
|||
* `Query()` |
|||
* `Header()` |
|||
* `Cookie()` |
|||
* `Body()` |
|||
* `Form()` |
|||
* `File()` |
|||
|
|||
Ви також можете задати набір `examples` з додатковою інформацією, яка буде додана до їхніх **JSON-схем** у **OpenAPI**. |
|||
|
|||
### `Body` з `examples` |
|||
|
|||
Тут ми передаємо `examples`, які містять один приклад очікуваних даних у `Body()`: |
|||
|
|||
{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *} |
|||
|
|||
### Приклад у UI документації |
|||
|
|||
За допомогою будь-якого з наведених вище методів це виглядатиме так у документації за `/docs`: |
|||
|
|||
<img src="/img/tutorial/body-fields/image01.png"> |
|||
|
|||
### `Body` з кількома `examples` |
|||
|
|||
Звичайно, Ви також можете передати кілька `examples`: |
|||
|
|||
{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *} |
|||
|
|||
Коли Ви це робите, приклади будуть частиною внутрішньої **JSON-схеми** для цих даних. |
|||
|
|||
Втім, на момент написання цього (<abbr title="2023-08-26">26 серпня 2023</abbr>), Swagger UI — інструмент, який відповідає за відображення UI документації — не підтримує показ кількох прикладів у **JSON-схеми**. Але нижче можна прочитати про обхідний шлях. |
|||
|
|||
### Специфічні для OpenAPI `examples` |
|||
|
|||
Ще до того, як **JSON-схема** почала підтримувати `examples`, OpenAPI вже мала підтримку поля з такою ж назвою — `examples`. |
|||
|
|||
Це **специфічне для OpenAPI** поле `examples` розміщується в іншій частині специфікації OpenAPI — у **деталях кожної *операції шляху***, а не всередині самої JSON-схеми. |
|||
|
|||
Swagger UI вже давно підтримує це поле `examples`. Тому Ви можете використовувати його, щоб **відображати** кілька **прикладів у документації**. |
|||
|
|||
Це поле `examples` у специфікації OpenAPI — це `dict` (словник) з **кількома прикладами** (а не список `list`), кожен із яких може містити додаткову інформацію, що буде додана до **OpenAPI**. |
|||
|
|||
Воно не включається до JSON Schema кожного параметра, а розміщується зовні, безпосередньо в *операції шляху*. |
|||
|
|||
### Використання параметра `openapi_examples` |
|||
|
|||
Ви можете оголосити специфічні для OpenAPI `examples` у FastAPI за допомогою параметра `openapi_examples` для: |
|||
|
|||
* `Path()` |
|||
* `Query()` |
|||
* `Header()` |
|||
* `Cookie()` |
|||
* `Body()` |
|||
* `Form()` |
|||
* `File()` |
|||
|
|||
Ключі словника (`dict`) ідентифікують кожен приклад, а кожне значення `dict` — кожен специфічний словник `dict` в `examples` може містити: |
|||
|
|||
* `summary`: короткий опис прикладу. |
|||
* `description`: розгорнутий опис (може містити Markdown). |
|||
* `value`: сам приклад, наприклад, словник (`dict`). |
|||
* `externalValue`: альтернатива `value`, URL-адреса, що вказує на приклад. Проте ця опція може не підтримуватися більшістю інструментів, на відміну від `value`. |
|||
|
|||
Використання виглядає так: |
|||
|
|||
{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *} |
|||
|
|||
### Приклади OpenAPI у UI документації |
|||
|
|||
З параметром `openapi_examples`, доданим до `Body()`, документація `/docs` виглядатиме так: |
|||
|
|||
<img src="/img/tutorial/body-fields/image02.png"> |
|||
|
|||
## Технічні деталі |
|||
|
|||
/// tip | Підказка |
|||
|
|||
Якщо Ви вже використовуєте **FastAPI** версії **0.99.0 або вище**, Ви можете **пропустити** цей розділ. |
|||
|
|||
Він більш актуальний для старих версій, до появи OpenAPI 3.1.0. |
|||
|
|||
Можна вважати це коротким **історичним екскурсом** у OpenAPI та JSON Schema. 🤓 |
|||
|
|||
/// |
|||
|
|||
/// warning | Попередження |
|||
|
|||
Це дуже технічна інформація про стандарти **JSON Schema** і **OpenAPI**. |
|||
|
|||
Якщо вищезгадані ідеї вже працюють у Вас — можете не заглиблюватися в ці деталі. |
|||
|
|||
/// |
|||
|
|||
До OpenAPI 3.1.0 специфікація використовувала стару та модифіковану версію **JSON Schema**. |
|||
|
|||
Оскільки JSON Schema раніше не підтримувала `examples`, OpenAPI додала власне поле `examples`. |
|||
|
|||
OpenAPI також додала `example` і `examples` до інших частин специфікації: |
|||
|
|||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object" class="external-link" target="_blank">`Parameter Object` (в специфікації)</a> використовується FastAPI для: |
|||
* `Path()` |
|||
* `Query()` |
|||
* `Header()` |
|||
* `Cookie()` |
|||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object" class="external-link" target="_blank">`Request Body Object`, в полі `content`, в `Media Type Object` (в специфікації)</a> використовується FastAPI для: |
|||
* `Body()` |
|||
* `File()` |
|||
* `Form()` |
|||
|
|||
/// info | Інформація |
|||
|
|||
Цей старий параметр `examples`, специфічний для OpenAPI, тепер називається `openapi_examples`, починаючи з FastAPI версії `0.103.0`. |
|||
|
|||
/// |
|||
|
|||
### Поле `examples` у JSON Schema |
|||
|
|||
Пізніше JSON Schema додала поле <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a> у нову версію специфікації. |
|||
|
|||
І вже OpenAPI 3.1.0 базується на цій новій версії (JSON Schema 2020-12), яка включає поле `examples`. |
|||
|
|||
Тепер це поле `examples` є пріоритетним і замінює старе (і кастомне) поле `example`, яке стало застарілим. |
|||
|
|||
Нове поле `examples` у JSON Schema — це **просто список (`list`)** прикладів, без додаткових метаданих (на відміну від OpenAPI). |
|||
|
|||
/// info | Інформація |
|||
|
|||
Навіть після того, як з'явився OpenAPI 3.1.0, який підтримував examples у JSON Schema, інструмент Swagger UI ще деякий час не підтримував цю версію (підтримка з’явилась з версії 5.0.0 🎉). |
|||
|
|||
Через це версії FastAPI до 0.99.0 все ще використовували версії OpenAPI нижчі за 3.1.0. |
|||
|
|||
/// |
|||
|
|||
### `Examples` в Pydantic і FastAPI |
|||
|
|||
Коли Ви додаєте `examples` у модель Pydantic через `schema_extra` або `Field(examples=["something"])`, ці приклади додаються до **JSON Schema** цієї моделі. |
|||
|
|||
І ця **JSON Schema** Pydantic-моделі включається до **OpenAPI** Вашого API, а потім використовується в UI документації (docs UI). |
|||
|
|||
У версіях FastAPI до 0.99.0 (починаючи з 0.99.0 використовується новіший OpenAPI 3.1.0), коли Ви використовували `example` або `examples` з іншими утилітами (`Query()`, `Body()` тощо), ці приклади не додавалися до JSON Schema, який описує ці дані (навіть не до власної версії JSON Schema у OpenAPI). Натомість вони додавалися безпосередньо до опису *обробника шляху* *(path operation)* в OpenAPI (тобто поза межами частин, які використовують JSON Schema). |
|||
|
|||
Але тепер, коли FastAPI 0.99.0 і вище використовують OpenAPI 3.1.0, а той — JSON Schema 2020-12, разом із Swagger UI 5.0.0 і вище — все стало більш узгодженим, і examples тепер включаються до JSON Schema. |
|||
|
|||
### Swagger UI та специфічні для OpenAPI `examples` |
|||
|
|||
Раніше (станом на 26 серпня 2023 року) Swagger UI не підтримував кілька прикладів у JSON Schema, тому користувачі не мали можливості показати декілька прикладів у документації. |
|||
|
|||
Щоб вирішити це, FastAPI починаючи з версії 0.103.0 **додав підтримку** старого **OpenAPI-специфічного** поля `examples` через новий параметр `openapi_examples`. 🤓 |
|||
|
|||
### Підсумок |
|||
|
|||
Раніше я казав, що не люблю історію... а тепер ось я — розповідаю "технічні історичні" лекції. 😅 |
|||
|
|||
Коротко: **оновіться до FastAPI 0.99.0 або вище** — і все стане значно **простішим, узгодженим та інтуїтивно зрозумілим**, і Вам не доведеться знати всі ці історичні деталі. 😎 |
@ -0,0 +1,31 @@ |
|||
from fastapi import FastAPI |
|||
from fastapi.testclient import TestClient |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class MyModel(BaseModel): |
|||
""" |
|||
A model with a form feed character in the title. |
|||
\f |
|||
Text after form feed character. |
|||
""" |
|||
|
|||
|
|||
@app.get("/foo") |
|||
def foo(v: MyModel): # pragma: no cover |
|||
pass |
|||
|
|||
|
|||
client = TestClient(app) |
|||
|
|||
|
|||
def test_openapi(): |
|||
response = client.get("/openapi.json") |
|||
assert response.status_code == 200, response.text |
|||
openapi_schema = response.json() |
|||
|
|||
assert openapi_schema["components"]["schemas"]["MyModel"]["description"] == ( |
|||
"A model with a form feed character in the title.\n" |
|||
) |
@ -1,19 +0,0 @@ |
|||
from fastapi.testclient import TestClient |
|||
from pytest import MonkeyPatch |
|||
|
|||
from ...utils import needs_pydanticv1 |
|||
|
|||
|
|||
@needs_pydanticv1 |
|||
def test_settings(monkeypatch: MonkeyPatch): |
|||
monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com") |
|||
from docs_src.settings.tutorial001_pv1 import app |
|||
|
|||
client = TestClient(app) |
|||
response = client.get("/info") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"app_name": "Awesome API", |
|||
"admin_email": "admin@example.com", |
|||
"items_per_user": 50, |
|||
} |
@ -1,51 +0,0 @@ |
|||
from typing import List |
|||
|
|||
from fastapi import FastAPI |
|||
from pydantic import BaseModel |
|||
|
|||
app = FastAPI() |
|||
|
|||
|
|||
class RecursiveItem(BaseModel): |
|||
sub_items: List["RecursiveItem"] = [] |
|||
name: str |
|||
|
|||
|
|||
RecursiveItem.model_rebuild() |
|||
|
|||
|
|||
class RecursiveSubitemInSubmodel(BaseModel): |
|||
sub_items2: List["RecursiveItemViaSubmodel"] = [] |
|||
name: str |
|||
|
|||
|
|||
class RecursiveItemViaSubmodel(BaseModel): |
|||
sub_items1: List[RecursiveSubitemInSubmodel] = [] |
|||
name: str |
|||
|
|||
|
|||
RecursiveSubitemInSubmodel.model_rebuild() |
|||
RecursiveItemViaSubmodel.model_rebuild() |
|||
|
|||
|
|||
@app.get("/items/recursive", response_model=RecursiveItem) |
|||
def get_recursive(): |
|||
return {"name": "item", "sub_items": [{"name": "subitem", "sub_items": []}]} |
|||
|
|||
|
|||
@app.get("/items/recursive-submodel", response_model=RecursiveItemViaSubmodel) |
|||
def get_recursive_submodel(): |
|||
return { |
|||
"name": "item", |
|||
"sub_items1": [ |
|||
{ |
|||
"name": "subitem", |
|||
"sub_items2": [ |
|||
{ |
|||
"name": "subsubitem", |
|||
"sub_items1": [{"name": "subsubsubitem", "sub_items2": []}], |
|||
} |
|||
], |
|||
} |
|||
], |
|||
} |
@ -1,12 +1,9 @@ |
|||
from fastapi.testclient import TestClient |
|||
|
|||
from ..utils import needs_pydanticv2 |
|||
from .app import app |
|||
|
|||
|
|||
@needs_pydanticv2 |
|||
def test_recursive(): |
|||
from .app_pv2 import app |
|||
|
|||
client = TestClient(app) |
|||
response = client.get("/items/recursive") |
|||
assert response.status_code == 200, response.text |
@ -1,33 +0,0 @@ |
|||
from fastapi.testclient import TestClient |
|||
|
|||
from ..utils import needs_pydanticv1 |
|||
|
|||
|
|||
@needs_pydanticv1 |
|||
def test_recursive(): |
|||
from .app_pv1 import app |
|||
|
|||
client = TestClient(app) |
|||
response = client.get("/items/recursive") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"sub_items": [{"name": "subitem", "sub_items": []}], |
|||
"name": "item", |
|||
} |
|||
|
|||
response = client.get("/items/recursive-submodel") |
|||
assert response.status_code == 200, response.text |
|||
assert response.json() == { |
|||
"name": "item", |
|||
"sub_items1": [ |
|||
{ |
|||
"name": "subitem", |
|||
"sub_items2": [ |
|||
{ |
|||
"name": "subsubitem", |
|||
"sub_items1": [{"name": "subsubsubitem", "sub_items2": []}], |
|||
} |
|||
], |
|||
} |
|||
], |
|||
} |
Loading…
Reference in new issue