Browse Source

Add support for OpenAPI servers metadata (#1547)

* feat: add servers option for OpenAPI

Closes #872

*  Use dicts for OpenAPI servers

* ♻️ Update OpenAPI Server model to support relative URLs

*  Add tests for OpenAPI servers

* ♻️ Re-order parameter location of servers for OpenAPI

* 🎨 Format code

Co-authored-by: Sebastián Ramírez <[email protected]>
pull/1576/head
mikaello 5 years ago
committed by GitHub
parent
commit
b591de2ace
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      fastapi/applications.py
  2. 2
      fastapi/openapi/models.py
  3. 9
      fastapi/openapi/utils.py
  4. 60
      tests/test_openapi_servers.py

3
fastapi/applications.py

@ -38,6 +38,7 @@ class FastAPI(Starlette):
version: str = "0.1.0",
openapi_url: Optional[str] = "/openapi.json",
openapi_tags: Optional[List[Dict[str, Any]]] = None,
servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
default_response_class: Type[Response] = JSONResponse,
docs_url: Optional[str] = "/docs",
redoc_url: Optional[str] = "/redoc",
@ -70,6 +71,7 @@ class FastAPI(Starlette):
self.title = title
self.description = description
self.version = version
self.servers = servers
self.openapi_url = openapi_url
self.openapi_tags = openapi_tags
# TODO: remove when discarding the openapi_prefix parameter
@ -106,6 +108,7 @@ class FastAPI(Starlette):
routes=self.routes,
openapi_prefix=openapi_prefix,
tags=self.openapi_tags,
servers=self.servers,
)
return self.openapi_schema

2
fastapi/openapi/models.py

@ -63,7 +63,7 @@ class ServerVariable(BaseModel):
class Server(BaseModel):
url: AnyUrl
url: Union[AnyUrl, str]
description: Optional[str] = None
variables: Optional[Dict[str, ServerVariable]] = None

9
fastapi/openapi/utils.py

@ -86,7 +86,7 @@ def get_openapi_security_definitions(flat_dependant: Dependant) -> Tuple[Dict, L
def get_openapi_operation_parameters(
*,
all_route_params: Sequence[ModelField],
model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str]
model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
) -> List[Dict[str, Any]]:
parameters = []
for param in all_route_params:
@ -112,7 +112,7 @@ def get_openapi_operation_parameters(
def get_openapi_operation_request_body(
*,
body_field: Optional[ModelField],
model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str]
model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
) -> Optional[Dict]:
if not body_field:
return None
@ -318,12 +318,15 @@ def get_openapi(
description: str = None,
routes: Sequence[BaseRoute],
openapi_prefix: str = "",
tags: Optional[List[Dict[str, Any]]] = None
tags: Optional[List[Dict[str, Any]]] = None,
servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
) -> Dict:
info = {"title": title, "version": version}
if description:
info["description"] = description
output: Dict[str, Any] = {"openapi": openapi_version, "info": info}
if servers:
output["servers"] = servers
components: Dict[str, Dict] = {}
paths: Dict[str, Dict] = {}
flat_models = get_flat_models_from_routes(routes)

60
tests/test_openapi_servers.py

@ -0,0 +1,60 @@
from fastapi import FastAPI
from fastapi.testclient import TestClient
app = FastAPI(
servers=[
{"url": "/", "description": "Default, relative server"},
{
"url": "http://staging.localhost.tiangolo.com:8000",
"description": "Staging but actually localhost still",
},
{"url": "https://prod.example.com"},
]
)
@app.get("/foo")
def foo():
return {"message": "Hello World"}
client = TestClient(app)
openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "FastAPI", "version": "0.1.0"},
"servers": [
{"url": "/", "description": "Default, relative server"},
{
"url": "http://staging.localhost.tiangolo.com:8000",
"description": "Staging but actually localhost still",
},
{"url": "https://prod.example.com"},
],
"paths": {
"/foo": {
"get": {
"summary": "Foo",
"operationId": "foo_foo_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
}
}
},
}
def test_openapi_servers():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == openapi_schema
def test_app():
response = client.get("/foo")
assert response.status_code == 200, response.text
Loading…
Cancel
Save