커스텀 문서 UI 정적 자산
커스텀 문서 UI 정적 자산 (자체 호스팅) (Custom Docs UI Static Assets (Self-Hosting))
API 문서는 Swagger UI와 ReDoc을 쓰는데, 둘 다 JavaScript와 CSS 파일이 필요해요. 기본적으로 이 파일들은 CDN에서 불러와요.
그런데 이걸 커스터마이즈할 수 있어요. 특정 CDN을 지정하거나, 파일을 직접 서빙할 수도 있죠.
출처: 공식문서
JavaScript와 CSS를 위한 커스텀 CDN
다른 CDN을 쓰고 싶다면, 예를 들어 https://unpkg.com/을 쓰고 싶다고 해 볼게요.
이게 유용할 수 있는 경우가 있어요. 예를 들어 여러분이 사는 국가에서 특정 URL을 차단하고 있어서 기본 CDN에 접근이 안 될 때죠.
자동 문서 비활성화하기
첫 단계는 자동으로 생성되는 문서를 끄는 거예요. 기본적으로 자동 문서는 기본 CDN을 쓰거든요.
FastAPI 앱을 만들 때 해당 URL들을 None으로 설정하면 문서를 끌 수 있어요:
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@2/bundles/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
커스텀 문서 포함하기
이제 커스텀 문서를 위한 *경로 연산(path operations)*을 만들 수 있어요.
FastAPI의 내부 함수를 재사용해서 문서용 HTML 페이지를 만들고, 필요한 인자들을 넘겨주면 돼요:
openapi_url: 문서의 HTML 페이지가 여러분 API의 OpenAPI 스키마를 받아올 URL이에요. 여기서는 속성app.openapi_url을 쓰면 돼요.title: API의 제목이에요.oauth2_redirect_url: 기본값을 쓰려면app.swagger_ui_oauth2_redirect_url을 쓰면 돼요.swagger_js_url: 여러분의 Swagger UI 문서 HTML이 JavaScript 파일을 받아올 URL이에요. 바로 이 커스텀 CDN URL이죠.swagger_css_url: 여러분의 Swagger UI 문서 HTML이 CSS 파일을 받아올 URL이에요. 역시 커스텀 CDN URL이에요.
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@2/bundles/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
팁 —
swagger_ui_redirect를 위한 경로 연산은 OAuth2를 쓸 때 필요한 헬퍼예요. API를 OAuth2 제공자와 연동하면, 인증 후 얻은 자격 증명으로 API 문서로 돌아올 수 있죠. 그러면 실제 OAuth2 인증으로 문서와 상호작용할 수 있어요. Swagger UI가 뒤에서 알아서 처리하지만, 이 "redirect" 헬퍼가 필요해요.
테스트용 경로 연산 만들기
이제 모든 게 잘 동작하는지 테스트하려면 경로 연산을 만들어요:
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@2/bundles/redoc.standalone.js",
)
@app.get("/users/{username}")
async def read_user(username: str):
return {"message": f"Hello {username}"}
테스트하기
이제 http://127.0.0.1:8000/docs로 가서 페이지를 새로고침하면, 새 CDN에서 자산들을 불러오는 걸 볼 수 있어요.
문서용 JavaScript와 CSS 자체 호스팅하기
JavaScript와 CSS를 자체 호스팅하는 건 예를 들어 오프라인 상태에서도, 인터넷에 연결되지 않아도, 또는 로컬 네트워크 안에서도 앱이 계속 동작해야 할 때 유용해요.
여기서는 이 파일들을 직접 서빙하고, 문서가 그 파일들을 쓰도록 설정하는 방법을 볼게요.
프로젝트 파일 구조
여러분의 프로젝트 파일 구조가 다음과 같다고 해 볼게요:
.
├── app
│ ├── __init__.py
│ ├── main.py
이제 이런 정적 파일들을 저장할 디렉터리를 만들어요. 새 구조는 이렇게 될 수 있어요:
.
├── app
│ ├── __init__.py
│ ├── main.py
└── static/
파일 다운로드하기
문서에 필요한 정적 파일들을 다운로드해서 그 static/ 디렉터리에 넣어요. 각 링크를 마우스 오른쪽 버튼으로 클릭해서 "Save link as..." 같은 옵션을 선택하면 돼요.
Swagger UI는 이 파일들을 써요:
그리고 ReDoc은 이 파일을 써요:
그 후 파일 구조는 이렇게 될 수 있어요:
.
├── app
│ ├── __init__.py
│ ├── main.py
└── static
├── redoc.standalone.js
├── swagger-ui-bundle.js
└── swagger-ui.css
정적 파일 서빙하기
StaticFiles를 임포트해요.- 특정 경로에
StaticFiles()인스턴스를 "마운트(mount)"해요.
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}"}
정적 파일 테스트하기
앱을 시작하고 http://127.0.0.1:8000/static/redoc.standalone.js로 가 보세요.
ReDoc을 위한 아주 긴 JavaScript 파일이 보일 거예요. 대략 이런 식으로 시작할 거예요:
/*! For license information please see redoc.standalone.js.LICENSE.txt */
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
...
이건 여러분이 앱에서 정적 파일을 서빙할 수 있고, 문서용 정적 파일을 올바른 위치에 두었다는 걸 확인해 주는 거예요.
이제 문서가 그 정적 파일들을 쓰도록 앱을 설정해 볼게요.
정적 파일을 위한 자동 문서 비활성화하기
커스텀 CDN을 쓸 때와 마찬가지로, 첫 단계는 자동 문서를 끄는 거예요. 기본적으로 자동 문서는 CDN을 쓰거든요.
FastAPI 앱을 만들 때 URL들을 None으로 설정하면 돼요:
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}"}
정적 파일을 위한 커스텀 문서 포함하기
커스텀 CDN을 쓸 때와 같은 방식으로, 이제 커스텀 문서를 위한 경로 연산을 만들 수 있어요.
역시 FastAPI의 내부 함수를 재사용해서 문서용 HTML 페이지를 만들고 필요한 인자들을 넘겨줘요:
openapi_url: 문서의 HTML 페이지가 여러분 API의 OpenAPI 스키마를 받아올 URL이에요. 여기서는app.openapi_url을 쓰면 돼요.title: API의 제목이에요.oauth2_redirect_url:app.swagger_ui_oauth2_redirect_url을 쓰면 기본값을 쓸 수 있어요.swagger_js_url: 여러분의 Swagger UI 문서 HTML이 JavaScript 파일을 받아올 URL이에요. 바로 여러분 앱이 지금 서빙하고 있는 파일이에요.swagger_css_url: 여러분의 Swagger UI 문서 HTML이 CSS 파일을 받아올 URL이에요. 역시 여러분 앱이 지금 서빙하고 있는 파일이에요.
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}"}
팁 —
swagger_ui_redirect를 위한 경로 연산은 OAuth2를 쓸 때 필요한 헬퍼예요. API를 OAuth2 제공자와 연동하면, 인증 후 얻은 자격 증명으로 API 문서로 돌아올 수 있어요. 그러면 실제 OAuth2 인증으로 문서와 상호작용할 수 있죠. Swagger UI가 뒤에서 알아서 처리하지만, 이 "redirect" 헬퍼가 필요해요.
정적 파일을 테스트할 경로 연산 만들기
이제 모든 게 잘 동작하는지 테스트하려면 경로 연산을 만들어요:
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}"}
정적 파일 UI 테스트하기
이제 WiFi를 끊고 http://127.0.0.1:8000/docs로 가서 페이지를 새로고침해 보세요.
인터넷이 없어도 여러분 API의 문서를 보고 상호작용할 수 있을 거예요.