Coverage for dj/api/main.py: 100%

39 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-04-17 20:05 -0700

1""" 

2Main DJ server app. 

3""" 

4 

5# All the models need to be imported here so that SQLModel can define their 

6# relationships at runtime without causing circular imports. 

7# See https://sqlmodel.tiangolo.com/tutorial/code-structure/#make-circular-imports-work. 

8# pylint: disable=unused-import 

9 

10import logging 

11from typing import TYPE_CHECKING, Optional 

12 

13from fastapi import Depends, FastAPI, Request 

14from fastapi.responses import JSONResponse 

15from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor 

16from starlette.middleware.cors import CORSMiddleware 

17 

18from dj import __version__ 

19from dj.api import ( 

20 attributes, 

21 catalogs, 

22 cubes, 

23 data, 

24 engines, 

25 health, 

26 metrics, 

27 namespaces, 

28 nodes, 

29 query, 

30 sql, 

31 tags, 

32) 

33from dj.api.attributes import default_attribute_types 

34from dj.errors import DJException 

35from dj.models.catalog import Catalog 

36from dj.models.column import Column 

37from dj.models.engine import Engine 

38from dj.models.node import NodeRevision 

39from dj.models.table import Table 

40from dj.utils import get_settings 

41 

42if TYPE_CHECKING: # pragma: no cover 

43 from opentelemetry import trace 

44 

45_logger = logging.getLogger(__name__) 

46 

47 

48def get_dj_app( 

49 tracer_provider: Optional["trace.TracerProvider"] = None, 

50) -> FastAPI: 

51 """ 

52 Get the DJ FastAPI app and optionally inject an OpenTelemetry tracer provider 

53 """ 

54 settings = get_settings() 

55 application = FastAPI( 

56 title=settings.name, 

57 description=settings.description, 

58 version=__version__, 

59 license_info={ 

60 "name": "MIT License", 

61 "url": "https://mit-license.org/", 

62 }, 

63 dependencies=[Depends(default_attribute_types)], 

64 ) 

65 application.add_middleware( 

66 CORSMiddleware, 

67 allow_origins=settings.cors_origin_whitelist, 

68 allow_credentials=True, 

69 allow_methods=["*"], 

70 allow_headers=["*"], 

71 ) 

72 

73 application.include_router(catalogs.router) 

74 application.include_router(engines.router) 

75 application.include_router(metrics.router) 

76 application.include_router(query.router) 

77 application.include_router(nodes.router) 

78 application.include_router(namespaces.router) 

79 application.include_router(data.router) 

80 application.include_router(health.router) 

81 application.include_router(cubes.router) 

82 application.include_router(tags.router) 

83 application.include_router(attributes.router) 

84 application.include_router(sql.router) 

85 

86 @application.exception_handler(DJException) 

87 async def dj_exception_handler( # pylint: disable=unused-argument 

88 request: Request, 

89 exc: DJException, 

90 ) -> JSONResponse: 

91 """ 

92 Capture errors and return JSON. 

93 """ 

94 return JSONResponse( 

95 status_code=exc.http_status_code, 

96 content=exc.to_dict(), 

97 headers={"X-DJ-Error": "true", "X-DBAPI-Exception": exc.dbapi_exception}, 

98 ) 

99 

100 FastAPIInstrumentor.instrument_app(application, tracer_provider=tracer_provider) 

101 

102 return application 

103 

104 

105app = get_dj_app()