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.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 .emailsender import EmailSender | ||||
| @ -34,18 +37,45 @@ from .subs import init_subs_api | ||||
| 
 | ||||
| from .crawlmanager import CrawlManager | ||||
| from .utils import run_once_lock, register_exit_handler, is_bool | ||||
| 
 | ||||
| from .version import __version__ | ||||
| 
 | ||||
| API_PREFIX = "/api" | ||||
| app_root = FastAPI( | ||||
|     docs_url=API_PREFIX + "/docs", | ||||
|     redoc_url=API_PREFIX + "/redoc", | ||||
|     openapi_url=API_PREFIX + "/openapi.json", | ||||
| ) | ||||
| 
 | ||||
| OPENAPI_URL = API_PREFIX + "/openapi.json" | ||||
| 
 | ||||
| app_root = FastAPI(docs_url=None, redoc_url=None, OPENAPI_URL=OPENAPI_URL) | ||||
| 
 | ||||
| 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 | ||||
| def main(): | ||||
| @ -200,7 +230,6 @@ def main(): | ||||
|         return settings | ||||
| 
 | ||||
|     # internal routes | ||||
| 
 | ||||
|     @app.get("/openapi.json", include_in_schema=False) | ||||
|     async def openapi() -> JSONResponse: | ||||
|         return JSONResponse(app_root.openapi()) | ||||
| @ -221,6 +250,31 @@ def main(): | ||||
| 
 | ||||
|     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") | ||||
|  | ||||
							
								
								
									
										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