OpenAPI Metadata for API Endpoints (#1941)
- Updates the `/docs` and `/redoc` API endpoints to have better metadata, including using Browsertrix favicon and our logo for the `/redoc` endpoint. - add new logo file 'docs-logo.svg' to root Based on info at: https://fastapi.tiangolo.com/how-to/extending-openapi/ https://fastapi.tiangolo.com/tutorial/metadata/ --------- Co-authored-by: Henry Wilkinson <henry@wilkinson.graphics>
This commit is contained in:
		
							parent
							
								
									3bf7967754
								
							
						
					
					
						commit
						b1ccdc4d16
					
				| @ -11,6 +11,9 @@ from fastapi import FastAPI, HTTPException | |||||||
| from fastapi.responses import JSONResponse | from fastapi.responses import JSONResponse | ||||||
| from fastapi.routing import APIRouter | from fastapi.routing import APIRouter | ||||||
| 
 | 
 | ||||||
|  | from fastapi.openapi.utils import get_openapi | ||||||
|  | from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html | ||||||
|  | 
 | ||||||
| from .db import init_db, await_db_and_migrations, update_and_prepare_db | from .db import init_db, await_db_and_migrations, update_and_prepare_db | ||||||
| 
 | 
 | ||||||
| from .emailsender import EmailSender | from .emailsender import EmailSender | ||||||
| @ -34,18 +37,45 @@ from .subs import init_subs_api | |||||||
| 
 | 
 | ||||||
| from .crawlmanager import CrawlManager | from .crawlmanager import CrawlManager | ||||||
| from .utils import run_once_lock, register_exit_handler, is_bool | from .utils import run_once_lock, register_exit_handler, is_bool | ||||||
| 
 | from .version import __version__ | ||||||
| 
 | 
 | ||||||
| API_PREFIX = "/api" | API_PREFIX = "/api" | ||||||
| app_root = FastAPI( | 
 | ||||||
|     docs_url=API_PREFIX + "/docs", | OPENAPI_URL = API_PREFIX + "/openapi.json" | ||||||
|     redoc_url=API_PREFIX + "/redoc", | 
 | ||||||
|     openapi_url=API_PREFIX + "/openapi.json", | app_root = FastAPI(docs_url=None, redoc_url=None, OPENAPI_URL=OPENAPI_URL) | ||||||
| ) |  | ||||||
| 
 | 
 | ||||||
| db_inited = {"inited": False} | db_inited = {"inited": False} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | # ============================================================================ | ||||||
|  | def make_schema(): | ||||||
|  |     """make custom openapi schema""" | ||||||
|  |     schema = get_openapi( | ||||||
|  |         title="Browsertrix", | ||||||
|  |         description="""\ | ||||||
|  | The Browsertrix API provides access to all aspects of the Browsertrix app. | ||||||
|  | 
 | ||||||
|  | See [https://docs.browsertrix.com/](https://docs.browsertrix.com/) for more info on deploying Browsertrix\ | ||||||
|  |         """, | ||||||
|  |         summary="Browsertrix Crawling System API", | ||||||
|  |         version=__version__, | ||||||
|  |         terms_of_service="http://browsertrix.com/terms", | ||||||
|  |         contact={ | ||||||
|  |             "name": "Browsertrix", | ||||||
|  |             "url": "https://browsertrix.com/", | ||||||
|  |             "email": "info@webrecorder.net", | ||||||
|  |         }, | ||||||
|  |         license_info={ | ||||||
|  |             "name": "AGPL v3", | ||||||
|  |             "url": "https://www.gnu.org/licenses/agpl-3.0.en.html", | ||||||
|  |         }, | ||||||
|  |         routes=app_root.routes, | ||||||
|  |     ) | ||||||
|  |     schema["info"]["x-logo"] = {"url": "/docs-logo.svg"} | ||||||
|  |     return schema | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| # ============================================================================ | # ============================================================================ | ||||||
| # pylint: disable=too-many-locals, duplicate-code | # pylint: disable=too-many-locals, duplicate-code | ||||||
| def main(): | def main(): | ||||||
| @ -200,7 +230,6 @@ def main(): | |||||||
|         return settings |         return settings | ||||||
| 
 | 
 | ||||||
|     # internal routes |     # internal routes | ||||||
| 
 |  | ||||||
|     @app.get("/openapi.json", include_in_schema=False) |     @app.get("/openapi.json", include_in_schema=False) | ||||||
|     async def openapi() -> JSONResponse: |     async def openapi() -> JSONResponse: | ||||||
|         return JSONResponse(app_root.openapi()) |         return JSONResponse(app_root.openapi()) | ||||||
| @ -221,6 +250,31 @@ def main(): | |||||||
| 
 | 
 | ||||||
|     app_root.include_router(app, prefix=API_PREFIX) |     app_root.include_router(app, prefix=API_PREFIX) | ||||||
| 
 | 
 | ||||||
|  |     # API Configurations -- needed to provide custom favicon | ||||||
|  |     @app_root.get(API_PREFIX + "/docs", include_in_schema=False) | ||||||
|  |     def overridden_swagger(): | ||||||
|  |         return get_swagger_ui_html( | ||||||
|  |             openapi_url=OPENAPI_URL, | ||||||
|  |             title="Browsertrix API", | ||||||
|  |             swagger_favicon_url="/favicon.ico", | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     @app_root.get(API_PREFIX + "/redoc", include_in_schema=False) | ||||||
|  |     def overridden_redoc(): | ||||||
|  |         return get_redoc_html( | ||||||
|  |             openapi_url=OPENAPI_URL, | ||||||
|  |             title="Browsertrix API", | ||||||
|  |             redoc_favicon_url="/favicon.ico", | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def get_api_schema(): | ||||||
|  |         if not app_root.openapi_schema: | ||||||
|  |             app_root.openapi_schema = make_schema() | ||||||
|  | 
 | ||||||
|  |         return app_root.openapi_schema | ||||||
|  | 
 | ||||||
|  |     app_root.openapi = get_api_schema  # type: ignore | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| # ============================================================================ | # ============================================================================ | ||||||
| @app_root.on_event("startup") | @app_root.on_event("startup") | ||||||
|  | |||||||
							
								
								
									
										32
									
								
								backend/test/test_api.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								backend/test/test_api.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | import requests | ||||||
|  | 
 | ||||||
|  | from .conftest import API_PREFIX | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_api_docs(): | ||||||
|  |     r = requests.get(f"{API_PREFIX}/docs") | ||||||
|  |     assert r.status_code == 200 | ||||||
|  | 
 | ||||||
|  |     text = r.text | ||||||
|  |     assert "<title>Browsertrix API</title>" in text | ||||||
|  |     assert "/favicon.ico" in text | ||||||
|  |     assert "/api/openapi.json" in text | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_api_redoc(): | ||||||
|  |     r = requests.get(f"{API_PREFIX}/redoc") | ||||||
|  |     assert r.status_code == 200 | ||||||
|  | 
 | ||||||
|  |     text = r.text | ||||||
|  |     assert "<title>Browsertrix API</title>" in text | ||||||
|  |     assert "/favicon.ico" in text | ||||||
|  |     assert "/api/openapi.json" in text | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def test_api_openapi(): | ||||||
|  |     r = requests.get(f"{API_PREFIX}/openapi.json") | ||||||
|  |     assert r.status_code == 200 | ||||||
|  | 
 | ||||||
|  |     json = r.json() | ||||||
|  |     assert json["info"]["title"] == "Browsertrix" | ||||||
|  |     assert json["info"]["x-logo"]["url"] == "/docs-logo.svg" | ||||||
							
								
								
									
										1
									
								
								frontend/src/assets/favicons/docs-logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								frontend/src/assets/favicons/docs-logo.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 12 KiB | 
		Loading…
	
		Reference in New Issue
	
	Block a user