2018-11-01 10:40:08 +00:00
|
|
|
from starlette.applications import Starlette
|
|
|
|
from starlette.endpoints import HTTPEndpoint
|
2019-05-13 14:22:59 +00:00
|
|
|
from starlette.schemas import SchemaGenerator
|
2018-11-01 12:52:03 +00:00
|
|
|
from starlette.testclient import TestClient
|
2018-11-01 10:40:08 +00:00
|
|
|
|
2019-02-18 15:48:19 +00:00
|
|
|
schemas = SchemaGenerator(
|
2018-11-01 10:40:08 +00:00
|
|
|
{"openapi": "3.0.0", "info": {"title": "Example API", "version": "1.0"}}
|
|
|
|
)
|
|
|
|
|
2019-02-18 15:48:19 +00:00
|
|
|
app = Starlette()
|
|
|
|
|
2018-11-01 10:40:08 +00:00
|
|
|
|
2019-02-19 12:49:30 +00:00
|
|
|
subapp = Starlette()
|
|
|
|
app.mount("/subapp", subapp)
|
|
|
|
|
|
|
|
|
2018-11-01 10:40:08 +00:00
|
|
|
@app.websocket_route("/ws")
|
|
|
|
def ws(session):
|
|
|
|
"""ws"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/users", methods=["GET", "HEAD"])
|
|
|
|
def list_users(request):
|
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A list of users.
|
|
|
|
examples:
|
|
|
|
[{"username": "tom"}, {"username": "lucy"}]
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/users", methods=["POST"])
|
|
|
|
def create_user(request):
|
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A user.
|
|
|
|
examples:
|
|
|
|
{"username": "tom"}
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/orgs")
|
|
|
|
class OrganisationsEndpoint(HTTPEndpoint):
|
|
|
|
def get(self, request):
|
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: A list of organisations.
|
|
|
|
examples:
|
|
|
|
[{"name": "Foo Corp."}, {"name": "Acme Ltd."}]
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
def post(self, request):
|
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: An organisation.
|
|
|
|
examples:
|
|
|
|
{"name": "Foo Corp."}
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2019-02-19 12:49:30 +00:00
|
|
|
@app.route("/regular-docstring-and-schema")
|
|
|
|
def regular_docstring_and_schema(request):
|
|
|
|
"""
|
|
|
|
This a regular docstring example (not included in schema)
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: This is included in the schema.
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/regular-docstring")
|
|
|
|
def regular_docstring(request):
|
|
|
|
"""
|
|
|
|
This a regular docstring example (not included in schema)
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
|
|
|
@app.route("/no-docstring")
|
|
|
|
def no_docstring(request):
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
|
|
|
@subapp.route("/subapp-endpoint")
|
|
|
|
def subapp_endpoint(request):
|
|
|
|
"""
|
|
|
|
responses:
|
|
|
|
200:
|
|
|
|
description: This endpoint is part of a subapp.
|
|
|
|
"""
|
|
|
|
pass # pragma: no cover
|
|
|
|
|
|
|
|
|
2018-11-01 12:52:03 +00:00
|
|
|
@app.route("/schema", methods=["GET"], include_in_schema=False)
|
|
|
|
def schema(request):
|
2019-02-18 15:48:19 +00:00
|
|
|
return schemas.OpenAPIResponse(request=request)
|
2018-11-01 12:52:03 +00:00
|
|
|
|
|
|
|
|
2018-11-01 10:40:08 +00:00
|
|
|
def test_schema_generation():
|
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: {
|
|
|
|
"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."}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2018-11-01 10:40:08 +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"}}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
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.
|
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
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def test_schema_endpoint():
|
|
|
|
client = TestClient(app)
|
|
|
|
response = client.get("/schema")
|
|
|
|
assert response.headers["Content-Type"] == "application/vnd.oai.openapi"
|
|
|
|
assert response.text.strip() == EXPECTED_SCHEMA.strip()
|