2018-11-01 10:40:08 +00:00
|
|
|
from starlette.applications import Starlette
|
|
|
|
from starlette.endpoints import HTTPEndpoint
|
2024-02-07 18:47:23 +00:00
|
|
|
from starlette.requests import Request
|
|
|
|
from starlette.responses import Response
|
2023-06-13 06:22:29 +00:00
|
|
|
from starlette.routing import Host, Mount, Route, Router, WebSocketRoute
|
2019-05-13 14:22:59 +00:00
|
|
|
from starlette.schemas import SchemaGenerator
|
2024-02-07 18:47:23 +00:00
|
|
|
from starlette.websockets import WebSocket
|
2024-07-27 09:31:16 +00:00
|
|
|
from tests.types import TestClientFactory
|
2018-11-01 10:40:08 +00:00
|
|
|
|
2024-09-01 13:11:01 +00:00
|
|
|
schemas = SchemaGenerator({"openapi": "3.0.0", "info": {"title": "Example API", "version": "1.0"}})
|
2018-11-01 10:40:08 +00:00
|
|
|
|
2019-02-18 15:48:19 +00:00
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def ws(session: WebSocket) -> None:
|
2018-11-01 10:40:08 +00:00
|
|
|
"""ws"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def get_user(request: Request) -> None:
|
2022-06-28 05:23:27 +00:00
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A user.
|
|
|
|
examples:
|
|
|
|
{"username": "tom"}
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def list_users(request: Request) -> None:
|
2018-11-01 10:40:08 +00:00
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A list of users.
|
|
|
|
examples:
|
|
|
|
[{"username": "tom"}, {"username": "lucy"}]
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def create_user(request: Request) -> None:
|
2018-11-01 10:40:08 +00:00
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A user.
|
|
|
|
examples:
|
|
|
|
{"username": "tom"}
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
|
|
|
class OrganisationsEndpoint(HTTPEndpoint):
|
2024-02-07 18:47:23 +00:00
|
|
|
def get(self, request: Request) -> None:
|
2018-11-01 10:40:08 +00:00
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A list of organisations.
|
|
|
|
examples:
|
|
|
|
[{"name": "Foo Corp."}, {"name": "Acme Ltd."}]
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def post(self, request: Request) -> None:
|
2018-11-01 10:40:08 +00:00
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: An organisation.
|
|
|
|
examples:
|
|
|
|
{"name": "Foo Corp."}
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def regular_docstring_and_schema(request: Request) -> None:
|
2019-02-19 12:49:30 +00:00
|
|
|
"""
|
|
|
|
This a regular docstring example (not included in schema)
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: This is included in the schema.
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def regular_docstring(request: Request) -> None:
|
2019-02-19 12:49:30 +00:00
|
|
|
"""
|
|
|
|
This a regular docstring example (not included in schema)
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def no_docstring(request: Request) -> None:
|
2019-02-19 12:49:30 +00:00
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def subapp_endpoint(request: Request) -> None:
|
2019-02-19 12:49:30 +00:00
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: This endpoint is part of a subapp.
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def schema(request: Request) -> Response:
|
2019-02-18 15:48:19 +00:00
|
|
|
return schemas.OpenAPIResponse(request=request)
|
2018-11-01 12:52:03 +00:00
|
|
|
|
|
|
|
|
2022-02-10 11:51:13 +00:00
|
|
|
subapp = Starlette(
|
|
|
|
routes=[
|
|
|
|
Route("/subapp-endpoint", endpoint=subapp_endpoint),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
app = Starlette(
|
|
|
|
routes=[
|
|
|
|
WebSocketRoute("/ws", endpoint=ws),
|
2022-06-28 05:23:27 +00:00
|
|
|
Route("/users/{id:int}", endpoint=get_user, methods=["GET"]),
|
2022-02-10 11:51:13 +00:00
|
|
|
Route("/users", endpoint=list_users, methods=["GET", "HEAD"]),
|
|
|
|
Route("/users", endpoint=create_user, methods=["POST"]),
|
|
|
|
Route("/orgs", endpoint=OrganisationsEndpoint),
|
|
|
|
Route("/regular-docstring-and-schema", endpoint=regular_docstring_and_schema),
|
|
|
|
Route("/regular-docstring", endpoint=regular_docstring),
|
|
|
|
Route("/no-docstring", endpoint=no_docstring),
|
|
|
|
Route("/schema", endpoint=schema, methods=["GET"], include_in_schema=False),
|
|
|
|
Mount("/subapp", subapp),
|
2023-06-13 06:22:29 +00:00
|
|
|
Host("sub.domain.com", app=Router(routes=[Mount("/subapp2", subapp)])),
|
2022-02-10 11:51:13 +00:00
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def test_schema_generation() -> None:
|
2019-02-18 15:48:19 +00:00
|
|
|
schema = schemas.get_schema(routes=app.routes)
|
|
|
|
assert schema == {
|
2018-11-01 10:40:08 +00:00
|
|
|
"openapi": "3.0.0",
|
|
|
|
"info": {"title": "Example API", "version": "1.0"},
|
|
|
|
"paths": {
|
|
|
|
"/orgs": {
|
|
|
|
"get": {
|
|
|
|
"responses": {
|
|
|
|
200: {
|
2024-09-01 13:11:01 +00:00
|
|
|
"description": "A list of organisations.",
|
2018-11-01 10:40:08 +00:00
|
|
|
"examples": [{"name": "Foo Corp."}, {"name": "Acme Ltd."}],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"post": {
|
|
|
|
"responses": {
|
|
|
|
200: {
|
|
|
|
"description": "An organisation.",
|
|
|
|
"examples": {"name": "Foo Corp."},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
2019-02-19 12:49:30 +00:00
|
|
|
"/regular-docstring-and-schema": {
|
2024-09-01 13:11:01 +00:00
|
|
|
"get": {"responses": {200: {"description": "This is included in the schema."}}}
|
2019-02-19 12:49:30 +00:00
|
|
|
},
|
|
|
|
"/subapp/subapp-endpoint": {
|
2024-09-01 13:11:01 +00:00
|
|
|
"get": {"responses": {200: {"description": "This endpoint is part of a subapp."}}}
|
2019-02-19 12:49:30 +00:00
|
|
|
},
|
2023-06-13 06:22:29 +00:00
|
|
|
"/subapp2/subapp-endpoint": {
|
2024-09-01 13:11:01 +00:00
|
|
|
"get": {"responses": {200: {"description": "This endpoint is part of a subapp."}}}
|
2023-06-13 06:22:29 +00:00
|
|
|
},
|
2018-11-01 10:40:08 +00:00
|
|
|
"/users": {
|
|
|
|
"get": {
|
|
|
|
"responses": {
|
|
|
|
200: {
|
|
|
|
"description": "A list of users.",
|
|
|
|
"examples": [{"username": "tom"}, {"username": "lucy"}],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2024-09-01 13:11:01 +00:00
|
|
|
"post": {"responses": {200: {"description": "A user.", "examples": {"username": "tom"}}}},
|
2018-11-01 10:40:08 +00:00
|
|
|
},
|
2022-06-28 05:23:27 +00:00
|
|
|
"/users/{id}": {
|
|
|
|
"get": {
|
|
|
|
"responses": {
|
|
|
|
200: {
|
|
|
|
"description": "A user.",
|
|
|
|
"examples": {"username": "tom"},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
2018-11-01 10:40:08 +00:00
|
|
|
},
|
|
|
|
}
|
2018-11-01 12:52:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
EXPECTED_SCHEMA = """
|
|
|
|
info:
|
|
|
|
title: Example API
|
|
|
|
version: '1.0'
|
|
|
|
openapi: 3.0.0
|
|
|
|
paths:
|
|
|
|
/orgs:
|
|
|
|
get:
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A list of organisations.
|
|
|
|
examples:
|
|
|
|
- name: Foo Corp.
|
|
|
|
- name: Acme Ltd.
|
|
|
|
post:
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: An organisation.
|
|
|
|
examples:
|
|
|
|
name: Foo Corp.
|
2019-02-19 12:49:30 +00:00
|
|
|
/regular-docstring-and-schema:
|
|
|
|
get:
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: This is included in the schema.
|
|
|
|
/subapp/subapp-endpoint:
|
|
|
|
get:
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: This endpoint is part of a subapp.
|
2023-06-13 06:22:29 +00:00
|
|
|
/subapp2/subapp-endpoint:
|
|
|
|
get:
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: This endpoint is part of a subapp.
|
2018-11-01 12:52:03 +00:00
|
|
|
/users:
|
|
|
|
get:
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A list of users.
|
|
|
|
examples:
|
|
|
|
- username: tom
|
|
|
|
- username: lucy
|
|
|
|
post:
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A user.
|
|
|
|
examples:
|
|
|
|
username: tom
|
2022-06-28 05:23:27 +00:00
|
|
|
/users/{id}:
|
|
|
|
get:
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A user.
|
|
|
|
examples:
|
|
|
|
username: tom
|
2018-11-01 12:52:03 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
2024-02-07 18:47:23 +00:00
|
|
|
def test_schema_endpoint(test_client_factory: TestClientFactory) -> None:
|
2021-06-28 20:36:13 +00:00
|
|
|
client = test_client_factory(app)
|
2018-11-01 12:52:03 +00:00
|
|
|
response = client.get("/schema")
|
|
|
|
assert response.headers["Content-Type"] == "application/vnd.oai.openapi"
|
|
|
|
assert response.text.strip() == EXPECTED_SCHEMA.strip()
|