Repository: tiangolo/fastapi

Issue:
OpenAPI fails when forcing query params to be body and multiple params in each
**Describe the bug**

The OpenAPI spec for my app breaks with the following error (shown in my web browser).

```
Fetch error
Internal Server Error /openapi.json
```

This only happens when I have endpoints defined in two separate files, each of which force all their arguments to be body parameters via annotating each parameter with `Body(...)` to force them to be body parameters, as opposed to query parameters.

Check this out!

- If the endpoints are defined in the same file, then the problem does not happen.
- If each endpoint only has a single parameter, the problem does not happen.
- If only one endpoint has multiple parameters, then the problem does not happen.

It only happens when both endpoints have *multiple* parameters annotated with `Body(...)`.


**To Reproduce**

Steps to reproduce the behavior:

1. Create a directory with the following structure.

```
.
├── foo
│   ├── __init__.py
│   ├── bar.py
│   └── baz.py
└── main.py
```

main.py

```python
from fastapi import FastAPI

import foo.bar
import foo.baz

app = FastAPI()

app.get('/v1/compute')(foo.bar.compute)
app.get('/v2/compute')(foo.baz.compute)
```

foo/bar.py

```python
from fastapi import Body

def compute(
        a: int = Body(...),
        b: str = Body(...),
):
    return a + b 
```

foo/baz.py (identical to foo/bar.py)

```python
from fastapi import Body

def compute(
        a: int = Body(...),
        b: str = Body(...),
):
    return a + b
```

2. Run with `uvicorn main:app --reload`
3. Visit `http://localhost:8000/docs`

**Expected behavior**

The OpenAPI page shows without error.

**Screenshots**

![image](https://user-images.githubusercontent.com/2068912/58768563-3e448080-8552-11e9-92b1-cfc1e8040d68.png)

Here's the exception my app produces when I try to visit `http://localhost:8000`.

```
ip-10-8-0-198% % uvicorn run:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [77186]
WARNING:root:email-validator not installed, email fields will be treated as str.
To install, run: pip install email-validator
INFO:uvicorn:Started server process [77188]
INFO:uvicorn:Waiting for application startup.
INFO:uvicorn:('127.0.0.1', 54932) - "GET /docs HTTP/1.1" 200
INFO:uvicorn:('127.0.0.1', 54932) - "GET /openapi.json HTTP/1.1" 500
ERROR:uvicorn:Exception in ASGI application
Traceback (most recent call last):
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/uvicorn/protocols/http/httptools_impl.py", line 368, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/uvicorn/middleware/asgi2.py", line 7, in __call__
    await instance(receive, send)
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/starlette/middleware/errors.py", line 125, in asgi
    raise exc from None
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/starlette/middleware/errors.py", line 103, in asgi
    await asgi(receive, _send)
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/starlette/exceptions.py", line 74, in app
    raise exc from None
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/starlette/exceptions.py", line 63, in app
    await instance(receive, sender)
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/starlette/routing.py", line 43, in awaitable
    response = await run_in_threadpool(func, request)
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/starlette/concurrency.py", line 24, in run_in_threadpool
    return await loop.run_in_executor(None, func, *args)
  File "/Users/edwardbanner/.anaconda/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/fastapi/applications.py", line 83, in <lambda>
    lambda req: JSONResponse(self.openapi()),
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/fastapi/applications.py", line 75, in openapi                                                                                            
    openapi_prefix=self.openapi_prefix,
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/fastapi/openapi/utils.py", line 248, in get_openapi                                                                                      
    flat_models=flat_models, model_name_map=model_name_map
  File "/Users/edwardbanner/.anaconda/lib/python3.6/site-packages/fastapi/utils.py", line 45, in get_model_definitions                                                                                     
    model_name = model_name_map[model]
KeyError: <class 'Body_compute'>
```

**Environment:**
 - OS: [e.g. macOS]
 - FastAPI Version [e.g. 0.27.0], get it with `pip install fastapi`.

```Python
import fastapi
print(fastapi.__version__)
```

**Additional context**

- When I only have a single endpoint, the value of `model_name_map` is `{<class 'Body_compute'>: 'Body_compute'}`.
- However, when I have both endpoints take multiple parameters, the value of `model_name_map` is `{<class 'Body_compute'>: 'None__Body_compute'}`.


Discussion:
Thanks for the report. I'll check it soon.

Resolving patch:
diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py
--- a/fastapi/openapi/utils.py
+++ b/fastapi/openapi/utils.py
@@ -8,7 +8,11 @@
 from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX
 from fastapi.openapi.models import OpenAPI
 from fastapi.params import Body, Param
-from fastapi.utils import get_flat_models_from_routes, get_model_definitions
+from fastapi.utils import (
+    generate_operation_id_for_path,
+    get_flat_models_from_routes,
+    get_model_definitions,
+)
 from pydantic.fields import Field
 from pydantic.schema import field_schema, get_model_name_map
 from pydantic.utils import lenient_issubclass
@@ -113,10 +117,7 @@ def generate_operation_id(*, route: routing.APIRoute, method: str) -> str:
     if route.operation_id:
         return route.operation_id
     path: str = route.path_format
-    operation_id = route.name + path
-    operation_id = operation_id.replace("{", "_").replace("}", "_").replace("/", "_")
-    operation_id = operation_id + "_" + method.lower()
-    return operation_id
+    return generate_operation_id_for_path(name=route.name, path=path, method=method)
 
 
 def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str:
diff --git a/fastapi/routing.py b/fastapi/routing.py
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -13,7 +13,7 @@
 )
 from fastapi.encoders import jsonable_encoder
 from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
-from fastapi.utils import create_cloned_field
+from fastapi.utils import create_cloned_field, generate_operation_id_for_path
 from pydantic import BaseConfig, BaseModel, Schema
 from pydantic.error_wrappers import ErrorWrapper, ValidationError
 from pydantic.fields import Field
@@ -205,12 +205,19 @@ def __init__(
         self.path = path
         self.endpoint = endpoint
         self.name = get_name(endpoint) if name is None else name
+        self.path_regex, self.path_format, self.param_convertors = compile_path(path)
+        if methods is None:
+            methods = ["GET"]
+        self.methods = set([method.upper() for method in methods])
+        self.unique_id = generate_operation_id_for_path(
+            name=self.name, path=self.path_format, method=list(methods)[0]
+        )
         self.response_model = response_model
         if self.response_model:
             assert lenient_issubclass(
                 response_class, JSONResponse
             ), "To declare a type the response must be a JSON response"
-            response_name = "Response_" + self.name
+            response_name = "Response_" + self.unique_id
             self.response_field: Optional[Field] = Field(
                 name=response_name,
                 type_=self.response_model,
@@ -251,7 +258,7 @@ def __init__(
                 assert lenient_issubclass(
                     model, BaseModel
                 ), "A response model must be a Pydantic model"
-                response_name = f"Response_{additional_status_code}_{self.name}"
+                response_name = f"Response_{additional_status_code}_{self.unique_id}"
                 response_field = Field(
                     name=response_name,
                     type_=model,
@@ -267,9 +274,6 @@ def __init__(
         else:
             self.response_fields = {}
         self.deprecated = deprecated
-        if methods is None:
-            methods = ["GET"]
-        self.methods = set([method.upper() for method in methods])
         self.operation_id = operation_id
         self.response_model_include = response_model_include
         self.response_model_exclude = response_model_exclude
@@ -278,7 +282,6 @@ def __init__(
         self.include_in_schema = include_in_schema
         self.response_class = response_class
 
-        self.path_regex, self.path_format, self.param_convertors = compile_path(path)
         assert inspect.isfunction(endpoint) or inspect.ismethod(
             endpoint
         ), f"An endpoint must be a function or method"
@@ -288,7 +291,7 @@ def __init__(
                 0,
                 get_parameterless_sub_dependant(depends=depends, path=self.path_format),
             )
-        self.body_field = get_body_field(dependant=self.dependant, name=self.name)
+        self.body_field = get_body_field(dependant=self.dependant, name=self.unique_id)
         self.dependency_overrides_provider = dependency_overrides_provider
         self.app = request_response(
             get_app(
diff --git a/fastapi/utils.py b/fastapi/utils.py
--- a/fastapi/utils.py
+++ b/fastapi/utils.py
@@ -93,3 +93,10 @@ def create_cloned_field(field: Field) -> Field:
     new_field.shape = field.shape
     new_field._populate_validators()
     return new_field
+
+
+def generate_operation_id_for_path(*, name: str, path: str, method: str) -> str:
+    operation_id = name + path
+    operation_id = operation_id.replace("{", "_").replace("}", "_").replace("/", "_")
+    operation_id = operation_id + "_" + method.lower()
+    return operation_id


Test patch:
diff --git a/tests/test_modules_same_name_body/__init__.py b/tests/test_modules_same_name_body/__init__.py
new file mode 100644
diff --git a/tests/test_modules_same_name_body/app/__init__.py b/tests/test_modules_same_name_body/app/__init__.py
new file mode 100644
diff --git a/tests/test_modules_same_name_body/app/a.py b/tests/test_modules_same_name_body/app/a.py
new file mode 100644
--- /dev/null
+++ b/tests/test_modules_same_name_body/app/a.py
@@ -0,0 +1,8 @@
+from fastapi import APIRouter, Body
+
+router = APIRouter()
+
+
+@router.post("/compute")
+def compute(a: int = Body(...), b: str = Body(...)):
+    return {"a": a, "b": b}
diff --git a/tests/test_modules_same_name_body/app/b.py b/tests/test_modules_same_name_body/app/b.py
new file mode 100644
--- /dev/null
+++ b/tests/test_modules_same_name_body/app/b.py
@@ -0,0 +1,8 @@
+from fastapi import APIRouter, Body
+
+router = APIRouter()
+
+
+@router.post("/compute/")
+def compute(a: int = Body(...), b: str = Body(...)):
+    return {"a": a, "b": b}
diff --git a/tests/test_modules_same_name_body/app/main.py b/tests/test_modules_same_name_body/app/main.py
new file mode 100644
--- /dev/null
+++ b/tests/test_modules_same_name_body/app/main.py
@@ -0,0 +1,8 @@
+from fastapi import FastAPI
+
+from . import a, b
+
+app = FastAPI()
+
+app.include_router(a.router, prefix="/a")
+app.include_router(b.router, prefix="/b")
diff --git a/tests/test_modules_same_name_body/test_main.py b/tests/test_modules_same_name_body/test_main.py
new file mode 100644
--- /dev/null
+++ b/tests/test_modules_same_name_body/test_main.py
@@ -0,0 +1,155 @@
+from starlette.testclient import TestClient
+
+from .app.main import app
+
+client = TestClient(app)
+
+openapi_schema = {
+    "openapi": "3.0.2",
+    "info": {"title": "Fast API", "version": "0.1.0"},
+    "paths": {
+        "/a/compute": {
+            "post": {
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+                "summary": "Compute",
+                "operationId": "compute_a_compute_post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_compute_a_compute_post"
+                            }
+                        }
+                    },
+                    "required": True,
+                },
+            }
+        },
+        "/b/compute/": {
+            "post": {
+                "responses": {
+                    "200": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                    "422": {
+                        "description": "Validation Error",
+                        "content": {
+                            "application/json": {
+                                "schema": {
+                                    "$ref": "#/components/schemas/HTTPValidationError"
+                                }
+                            }
+                        },
+                    },
+                },
+                "summary": "Compute",
+                "operationId": "compute_b_compute__post",
+                "requestBody": {
+                    "content": {
+                        "application/json": {
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_compute_b_compute__post"
+                            }
+                        }
+                    },
+                    "required": True,
+                },
+            }
+        },
+    },
+    "components": {
+        "schemas": {
+            "Body_compute_b_compute__post": {
+                "title": "Body_compute_b_compute__post",
+                "required": ["a", "b"],
+                "type": "object",
+                "properties": {
+                    "a": {"title": "A", "type": "integer"},
+                    "b": {"title": "B", "type": "string"},
+                },
+            },
+            "Body_compute_a_compute_post": {
+                "title": "Body_compute_a_compute_post",
+                "required": ["a", "b"],
+                "type": "object",
+                "properties": {
+                    "a": {"title": "A", "type": "integer"},
+                    "b": {"title": "B", "type": "string"},
+                },
+            },
+            "ValidationError": {
+                "title": "ValidationError",
+                "required": ["loc", "msg", "type"],
+                "type": "object",
+                "properties": {
+                    "loc": {
+                        "title": "Location",
+                        "type": "array",
+                        "items": {"type": "string"},
+                    },
+                    "msg": {"title": "Message", "type": "string"},
+                    "type": {"title": "Error Type", "type": "string"},
+                },
+            },
+            "HTTPValidationError": {
+                "title": "HTTPValidationError",
+                "type": "object",
+                "properties": {
+                    "detail": {
+                        "title": "Detail",
+                        "type": "array",
+                        "items": {"$ref": "#/components/schemas/ValidationError"},
+                    }
+                },
+            },
+        }
+    },
+}
+
+
+def test_openapi_schema():
+    response = client.get("/openapi.json")
+    assert response.status_code == 200
+    assert response.json() == openapi_schema
+
+
+def test_post_a():
+    data = {"a": 2, "b": "foo"}
+    response = client.post("/a/compute", json=data)
+    assert response.status_code == 200
+    data = response.json()
+
+
+def test_post_a_invalid():
+    data = {"a": "bar", "b": "foo"}
+    response = client.post("/a/compute", json=data)
+    assert response.status_code == 422
+
+
+def test_post_b():
+    data = {"a": 2, "b": "foo"}
+    response = client.post("/b/compute/", json=data)
+    assert response.status_code == 200
+    data = response.json()
+
+
+def test_post_b_invalid():
+    data = {"a": "bar", "b": "foo"}
+    response = client.post("/b/compute/", json=data)
+    assert response.status_code == 422
diff --git a/tests/test_security_oauth2.py b/tests/test_security_oauth2.py
--- a/tests/test_security_oauth2.py
+++ b/tests/test_security_oauth2.py
@@ -66,7 +66,7 @@ def read_current_user(current_user: User = Depends(get_current_user)):
                     "content": {
                         "application/x-www-form-urlencoded": {
                             "schema": {
-                                "$ref": "#/components/schemas/Body_read_current_user"
+                                "$ref": "#/components/schemas/Body_read_current_user_login_post"
                             }
                         }
                     },
@@ -90,8 +90,8 @@ def read_current_user(current_user: User = Depends(get_current_user)):
     },
     "components": {
         "schemas": {
-            "Body_read_current_user": {
-                "title": "Body_read_current_user",
+            "Body_read_current_user_login_post": {
+                "title": "Body_read_current_user_login_post",
                 "required": ["grant_type", "username", "password"],
                 "type": "object",
                 "properties": {
diff --git a/tests/test_security_oauth2_optional.py b/tests/test_security_oauth2_optional.py
--- a/tests/test_security_oauth2_optional.py
+++ b/tests/test_security_oauth2_optional.py
@@ -73,7 +73,7 @@ def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
                     "content": {
                         "application/x-www-form-urlencoded": {
                             "schema": {
-                                "$ref": "#/components/schemas/Body_read_current_user"
+                                "$ref": "#/components/schemas/Body_read_current_user_login_post"
                             }
                         }
                     },
@@ -97,8 +97,8 @@ def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
     },
     "components": {
         "schemas": {
-            "Body_read_current_user": {
-                "title": "Body_read_current_user",
+            "Body_read_current_user_login_post": {
+                "title": "Body_read_current_user_login_post",
                 "required": ["grant_type", "username", "password"],
                 "type": "object",
                 "properties": {
diff --git a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
--- a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
+++ b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
@@ -14,7 +14,7 @@
                         "content": {
                             "application/json": {
                                 "schema": {
-                                    "title": "Response_Read_Notes",
+                                    "title": "Response_Read_Notes_Notes__Get",
                                     "type": "array",
                                     "items": {"$ref": "#/components/schemas/Note"},
                                 }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
@@ -40,7 +40,9 @@
                 "requestBody": {
                     "content": {
                         "application/json": {
-                            "schema": {"$ref": "#/components/schemas/Body_update_item"}
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+                            }
                         }
                     },
                     "required": True,
@@ -70,8 +72,8 @@
                     "full_name": {"title": "Full_Name", "type": "string"},
                 },
             },
-            "Body_update_item": {
-                "title": "Body_update_item",
+            "Body_update_item_items__item_id__put": {
+                "title": "Body_update_item_items__item_id__put",
                 "required": ["item", "user", "importance"],
                 "type": "object",
                 "properties": {
diff --git a/tests/test_tutorial/test_body_schema/test_tutorial001.py b/tests/test_tutorial/test_body_schema/test_tutorial001.py
--- a/tests/test_tutorial/test_body_schema/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_schema/test_tutorial001.py
@@ -41,7 +41,9 @@
                 "requestBody": {
                     "content": {
                         "application/json": {
-                            "schema": {"$ref": "#/components/schemas/Body_update_item"}
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+                            }
                         }
                     },
                     "required": True,
@@ -71,8 +73,8 @@
                     "tax": {"title": "Tax", "type": "number"},
                 },
             },
-            "Body_update_item": {
-                "title": "Body_update_item",
+            "Body_update_item_items__item_id__put": {
+                "title": "Body_update_item_items__item_id__put",
                 "required": ["item"],
                 "type": "object",
                 "properties": {"item": {"$ref": "#/components/schemas/Item"}},
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
@@ -44,7 +44,9 @@
                 "requestBody": {
                     "content": {
                         "application/json": {
-                            "schema": {"$ref": "#/components/schemas/Body_read_items"}
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_read_items_items__item_id__put"
+                            }
                         }
                     }
                 },
@@ -53,8 +55,8 @@
     },
     "components": {
         "schemas": {
-            "Body_read_items": {
-                "title": "Body_read_items",
+            "Body_read_items_items__item_id__put": {
+                "title": "Body_read_items_items__item_id__put",
                 "type": "object",
                 "properties": {
                     "start_datetime": {
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py
--- a/tests/test_tutorial/test_extra_models/test_tutorial003.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py
@@ -16,7 +16,7 @@
                         "content": {
                             "application/json": {
                                 "schema": {
-                                    "title": "Response_Read_Item",
+                                    "title": "Response_Read_Item_Items__Item_Id__Get",
                                     "anyOf": [
                                         {"$ref": "#/components/schemas/PlaneItem"},
                                         {"$ref": "#/components/schemas/CarItem"},
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004.py b/tests/test_tutorial/test_extra_models/test_tutorial004.py
--- a/tests/test_tutorial/test_extra_models/test_tutorial004.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial004.py
@@ -16,7 +16,7 @@
                         "content": {
                             "application/json": {
                                 "schema": {
-                                    "title": "Response_Read_Items",
+                                    "title": "Response_Read_Items_Items__Get",
                                     "type": "array",
                                     "items": {"$ref": "#/components/schemas/Item"},
                                 }
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005.py b/tests/test_tutorial/test_extra_models/test_tutorial005.py
--- a/tests/test_tutorial/test_extra_models/test_tutorial005.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial005.py
@@ -16,7 +16,7 @@
                         "content": {
                             "application/json": {
                                 "schema": {
-                                    "title": "Response_Read_Keyword_Weights",
+                                    "title": "Response_Read_Keyword_Weights_Keyword-Weights__Get",
                                     "type": "object",
                                     "additionalProperties": {"type": "number"},
                                 }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py
--- a/tests/test_tutorial/test_request_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001.py
@@ -33,7 +33,9 @@
                 "requestBody": {
                     "content": {
                         "multipart/form-data": {
-                            "schema": {"$ref": "#/components/schemas/Body_create_file"}
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_create_file_files__post"
+                            }
                         }
                     },
                     "required": True,
@@ -64,7 +66,7 @@
                     "content": {
                         "multipart/form-data": {
                             "schema": {
-                                "$ref": "#/components/schemas/Body_create_upload_file"
+                                "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
                             }
                         }
                     },
@@ -75,16 +77,16 @@
     },
     "components": {
         "schemas": {
-            "Body_create_file": {
-                "title": "Body_create_file",
+            "Body_create_upload_file_uploadfile__post": {
+                "title": "Body_create_upload_file_uploadfile__post",
                 "required": ["file"],
                 "type": "object",
                 "properties": {
                     "file": {"title": "File", "type": "string", "format": "binary"}
                 },
             },
-            "Body_create_upload_file": {
-                "title": "Body_create_upload_file",
+            "Body_create_file_files__post": {
+                "title": "Body_create_file_files__post",
                 "required": ["file"],
                 "type": "object",
                 "properties": {
diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py
--- a/tests/test_tutorial/test_request_files/test_tutorial002.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial002.py
@@ -33,7 +33,9 @@
                 "requestBody": {
                     "content": {
                         "multipart/form-data": {
-                            "schema": {"$ref": "#/components/schemas/Body_create_files"}
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_create_files_files__post"
+                            }
                         }
                     },
                     "required": True,
@@ -64,7 +66,7 @@
                     "content": {
                         "multipart/form-data": {
                             "schema": {
-                                "$ref": "#/components/schemas/Body_create_upload_files"
+                                "$ref": "#/components/schemas/Body_create_upload_files_uploadfiles__post"
                             }
                         }
                     },
@@ -87,8 +89,8 @@
     },
     "components": {
         "schemas": {
-            "Body_create_files": {
-                "title": "Body_create_files",
+            "Body_create_upload_files_uploadfiles__post": {
+                "title": "Body_create_upload_files_uploadfiles__post",
                 "required": ["files"],
                 "type": "object",
                 "properties": {
@@ -99,8 +101,8 @@
                     }
                 },
             },
-            "Body_create_upload_files": {
-                "title": "Body_create_upload_files",
+            "Body_create_files_files__post": {
+                "title": "Body_create_files_files__post",
                 "required": ["files"],
                 "type": "object",
                 "properties": {
diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001.py b/tests/test_tutorial/test_request_forms/test_tutorial001.py
--- a/tests/test_tutorial/test_request_forms/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_forms/test_tutorial001.py
@@ -32,7 +32,9 @@
                 "requestBody": {
                     "content": {
                         "application/x-www-form-urlencoded": {
-                            "schema": {"$ref": "#/components/schemas/Body_login"}
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_login_login__post"
+                            }
                         }
                     },
                     "required": True,
@@ -42,8 +44,8 @@
     },
     "components": {
         "schemas": {
-            "Body_login": {
-                "title": "Body_login",
+            "Body_login_login__post": {
+                "title": "Body_login_login__post",
                 "required": ["username", "password"],
                 "type": "object",
                 "properties": {
diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
--- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
@@ -34,7 +34,9 @@
                 "requestBody": {
                     "content": {
                         "multipart/form-data": {
-                            "schema": {"$ref": "#/components/schemas/Body_create_file"}
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_create_file_files__post"
+                            }
                         }
                     },
                     "required": True,
@@ -44,8 +46,8 @@
     },
     "components": {
         "schemas": {
-            "Body_create_file": {
-                "title": "Body_create_file",
+            "Body_create_file_files__post": {
+                "title": "Body_create_file_files__post",
                 "required": ["file", "fileb", "token"],
                 "type": "object",
                 "properties": {
diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py
--- a/tests/test_tutorial/test_security/test_tutorial003.py
+++ b/tests/test_tutorial/test_security/test_tutorial003.py
@@ -31,7 +31,9 @@
                 "requestBody": {
                     "content": {
                         "application/x-www-form-urlencoded": {
-                            "schema": {"$ref": "#/components/schemas/Body_login"}
+                            "schema": {
+                                "$ref": "#/components/schemas/Body_login_token_post"
+                            }
                         }
                     },
                     "required": True,
@@ -54,8 +56,8 @@
     },
     "components": {
         "schemas": {
-            "Body_login": {
-                "title": "Body_login",
+            "Body_login_token_post": {
+                "title": "Body_login_token_post",
                 "required": ["username", "password"],
                 "type": "object",
                 "properties": {
diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py
--- a/tests/test_tutorial/test_security/test_tutorial005.py
+++ b/tests/test_tutorial/test_security/test_tutorial005.py
@@ -42,7 +42,7 @@
                     "content": {
                         "application/x-www-form-urlencoded": {
                             "schema": {
-                                "$ref": "#/components/schemas/Body_login_for_access_token"
+                                "$ref": "#/components/schemas/Body_login_for_access_token_token_post"
                             }
                         }
                     },
@@ -116,8 +116,8 @@
                     "token_type": {"title": "Token_Type", "type": "string"},
                 },
             },
-            "Body_login_for_access_token": {
-                "title": "Body_login_for_access_token",
+            "Body_login_for_access_token_token_post": {
+                "title": "Body_login_for_access_token_token_post",
                 "required": ["username", "password"],
                 "type": "object",
                 "properties": {
@@ -177,6 +177,12 @@
 }
 
 
+def test_openapi_schema():
+    response = client.get("/openapi.json")
+    assert response.status_code == 200
+    assert response.json() == openapi_schema
+
+
 def get_access_token(username="johndoe", password="secret", scope=None):
     data = {"username": username, "password": password}
     if scope:
@@ -187,12 +193,6 @@ def get_access_token(username="johndoe", password="secret", scope=None):
     return access_token
 
 
-def test_openapi_schema():
-    response = client.get("/openapi.json")
-    assert response.status_code == 200
-    assert response.json() == openapi_schema
-
-
 def test_login():
     response = client.post("/token", data={"username": "johndoe", "password": "secret"})
     assert response.status_code == 200
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases.py b/tests/test_tutorial/test_sql_databases/test_sql_databases.py
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases.py
@@ -16,7 +16,7 @@
                         "content": {
                             "application/json": {
                                 "schema": {
-                                    "title": "Response_Read_Users",
+                                    "title": "Response_Read_Users_Users__Get",
                                     "type": "array",
                                     "items": {"$ref": "#/components/schemas/User"},
                                 }
@@ -168,7 +168,7 @@
                         "content": {
                             "application/json": {
                                 "schema": {
-                                    "title": "Response_Read_Items",
+                                    "title": "Response_Read_Items_Items__Get",
                                     "type": "array",
                                     "items": {"$ref": "#/components/schemas/Item"},
                                 }