Recursos Estáticos Personalizados para la Docs UI (Self-Hosting)¶
La documentación de la API utiliza Swagger UI y ReDoc, y cada uno de estos necesita algunos archivos JavaScript y CSS.
Por defecto, esos archivos se sirven desde un CDN.
Pero es posible personalizarlo, puedes establecer un CDN específico, o servir los archivos tú mismo.
CDN Personalizado para JavaScript y CSS¶
Digamos que quieres usar un CDN diferente, por ejemplo, quieres usar https://unpkg.com/
.
Esto podría ser útil si, por ejemplo, vives en un país que restringe algunas URLs.
Desactiva la documentación automática¶
El primer paso es desactivar la documentación automática, ya que por defecto, esos usan el CDN predeterminado.
Para desactivarlos, establece sus URLs en None
cuando crees tu aplicación de FastAPI
:
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
app = FastAPI(docs_url=None, redoc_url=None)
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js",
swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
Incluye la documentación personalizada¶
Ahora puedes crear las path operations para la documentación personalizada.
Puedes reutilizar las funciones internas de FastAPI para crear las páginas HTML para la documentación, y pasarles los argumentos necesarios:
openapi_url
: la URL donde la página HTML para la documentación puede obtener el OpenAPI esquema de tu API. Puedes usar aquí el atributoapp.openapi_url
.title
: el título de tu API.oauth2_redirect_url
: puedes usarapp.swagger_ui_oauth2_redirect_url
aquí para usar el valor predeterminado.swagger_js_url
: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo JavaScript. Esta es la URL personalizada del CDN.swagger_css_url
: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo CSS. Esta es la URL personalizada del CDN.
Y de manera similar para ReDoc...
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
app = FastAPI(docs_url=None, redoc_url=None)
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js",
swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
Consejo
La path operation para swagger_ui_redirect
es una herramienta cuando utilizas OAuth2.
Si integras tu API con un proveedor OAuth2, podrás autenticarte y regresar a la documentación de la API con las credenciales adquiridas. E interactuar con ella usando la autenticación real de OAuth2.
Swagger UI lo manejará detrás de escena para ti, pero necesita este auxiliar de "redirección".
Crea una path operation para probarlo¶
Ahora, para poder probar que todo funciona, crea una path operation:
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
app = FastAPI(docs_url=None, redoc_url=None)
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js",
swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
Pruébalo¶
Ahora, deberías poder ir a tu documentación en http://127.0.0.1:8000/docs, y recargar la página, cargará esos recursos desde el nuevo CDN.
Self-hosting de JavaScript y CSS para la documentación¶
El self-hosting de JavaScript y CSS podría ser útil si, por ejemplo, necesitas que tu aplicación siga funcionando incluso offline, sin acceso a Internet, o en una red local.
Aquí verás cómo servir esos archivos tú mismo, en la misma aplicación de FastAPI, y configurar la documentación para usarla.
Estructura de archivos del proyecto¶
Supongamos que la estructura de archivos de tu proyecto se ve así:
.
├── app
│ ├── __init__.py
│ ├── main.py
Ahora crea un directorio para almacenar esos archivos estáticos.
Tu nueva estructura de archivos podría verse así:
.
├── app
│ ├── __init__.py
│ ├── main.py
└── static/
Descarga los archivos¶
Descarga los archivos estáticos necesarios para la documentación y ponlos en ese directorio static/
.
Probablemente puedas hacer clic derecho en cada enlace y seleccionar una opción similar a Guardar enlace como...
.
Swagger UI utiliza los archivos:
Y ReDoc utiliza el archivo:
Después de eso, tu estructura de archivos podría verse así:
.
├── app
│ ├── __init__.py
│ ├── main.py
└── static
├── redoc.standalone.js
├── swagger-ui-bundle.js
└── swagger-ui.css
Sirve los archivos estáticos¶
- Importa
StaticFiles
. - "Monta" una instance de
StaticFiles()
en un path específico.
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
app = FastAPI(docs_url=None, redoc_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="/static/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
Prueba los archivos estáticos¶
Inicia tu aplicación y ve a http://127.0.0.1:8000/static/redoc.standalone.js.
Deberías ver un archivo JavaScript muy largo de ReDoc.
Podría comenzar con algo como:
/*!
* ReDoc - OpenAPI/Swagger-generated API Reference Documentation
* -------------------------------------------------------------
* Version: "2.0.0-rc.18"
* Repo: https://github.com/Redocly/redoc
*/
!function(e,t){"object"==typeof exports&&"object"==typeof m
...
Eso confirma que puedes servir archivos estáticos desde tu aplicación, y que colocaste los archivos estáticos para la documentación en el lugar correcto.
Ahora podemos configurar la aplicación para usar esos archivos estáticos para la documentación.
Desactiva la documentación automática para archivos estáticos¶
Igual que cuando usas un CDN personalizado, el primer paso es desactivar la documentación automática, ya que esos usan el CDN por defecto.
Para desactivarlos, establece sus URLs en None
cuando crees tu aplicación de FastAPI
:
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
app = FastAPI(docs_url=None, redoc_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="/static/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
Incluye la documentación personalizada para archivos estáticos¶
Y de la misma manera que con un CDN personalizado, ahora puedes crear las path operations para la documentación personalizada.
Nuevamente, puedes reutilizar las funciones internas de FastAPI para crear las páginas HTML para la documentación, y pasarles los argumentos necesarios:
openapi_url
: la URL donde la página HTML para la documentación puede obtener el OpenAPI esquema de tu API. Puedes usar aquí el atributoapp.openapi_url
.title
: el título de tu API.oauth2_redirect_url
: puedes usarapp.swagger_ui_oauth2_redirect_url
aquí para usar el valor predeterminado.swagger_js_url
: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo JavaScript. Este es el que tu propia aplicación está sirviendo ahora.swagger_css_url
: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo CSS. Este es el que tu propia aplicación está sirviendo ahora.
Y de manera similar para ReDoc...
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
app = FastAPI(docs_url=None, redoc_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="/static/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
Consejo
La path operation para swagger_ui_redirect
es una herramienta cuando utilizas OAuth2.
Si integras tu API con un proveedor OAuth2, podrás autenticarte y regresar a la documentación de la API con las credenciales adquiridas. Y interactuar con ella usando la autenticación real de OAuth2.
Swagger UI lo manejará detrás de escena para ti, pero necesita este auxiliar de "redirección".
Crea una path operation para probar archivos estáticos¶
Ahora, para poder probar que todo funciona, crea una path operation:
from fastapi import FastAPI
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
from fastapi.staticfiles import StaticFiles
app = FastAPI(docs_url=None, redoc_url=None)
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
swagger_js_url="/static/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui.css",
)
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
redoc_js_url="/static/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
Prueba la UI de Archivos Estáticos¶
Ahora, deberías poder desconectar tu WiFi, ir a tu documentación en http://127.0.0.1:8000/docs, y recargar la página.
E incluso sin Internet, podrás ver la documentación de tu API e interactuar con ella.