Coverage for polar/openapi.py: 95%

41 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-12-05 16:17 +0000

1from enum import StrEnum 1a

2from typing import Any, NotRequired, TypedDict 1a

3 

4from fastapi import FastAPI 1a

5from fastapi.openapi.utils import get_openapi 1a

6 

7from polar.config import Environment, settings 1a

8from polar.kit.metadata import add_metadata_query_schema 1a

9from polar.oauth2.schemas import add_oauth2_form_schemas 1a

10 

11 

12class OpenAPIExternalDoc(TypedDict): 1a

13 description: NotRequired[str] 1a

14 url: str 1a

15 

16 

17class OpenAPITag(TypedDict): 1a

18 name: str 1a

19 description: NotRequired[str] 1a

20 externalDocs: NotRequired[dict[str, str]] 1a

21 

22 

23class APITag(StrEnum): 1a

24 """ 

25 Tags used by our documentation to better organize the endpoints. 

26 

27 They should be set after the "group" tag, which is used to group the endpoints 

28 in the generated documentation. 

29 

30 **Example** 

31 

32 ```py 

33 router = APIRouter(prefix="/products", tags=["products", APITag.public]) 

34 ``` 

35 """ 

36 

37 public = "public" 1a

38 private = "private" 1a

39 mcp = "mcp" 1a

40 

41 @classmethod 1a

42 def metadata(cls) -> list[OpenAPITag]: 1a

43 return [ 1a

44 { 

45 "name": cls.public, 

46 "description": ( 

47 "Endpoints shown and documented in the Polar API documentation " 

48 "and available in our SDKs." 

49 ), 

50 }, 

51 { 

52 "name": cls.private, 

53 "description": ( 

54 "Endpoints that should appear in the schema only " 

55 "in development to generate our internal JS SDK." 

56 ), 

57 }, 

58 { 

59 "name": cls.mcp, 

60 "description": "Endpoints enabled in the MCP server.", 

61 }, 

62 ] 

63 

64 

65class OpenAPIParameters(TypedDict): 1a

66 title: str 1a

67 summary: str 1a

68 version: str 1a

69 description: str 1a

70 docs_url: str | None 1a

71 redoc_url: str | None 1a

72 openapi_tags: list[dict[str, Any]] 1a

73 servers: list[dict[str, Any]] | None 1a

74 

75 

76OPENAPI_PARAMETERS: OpenAPIParameters = { 1a

77 "title": "Polar API", 

78 "summary": "Polar HTTP and Webhooks API", 

79 "version": "0.1.0", 

80 "description": "Read the docs at https://polar.sh/docs/api-reference", 

81 "docs_url": None 

82 if settings.is_environment({Environment.sandbox, Environment.production}) 

83 else "/docs", 

84 "redoc_url": None 

85 if settings.is_environment({Environment.sandbox, Environment.production}) 

86 else "/redoc", 

87 "openapi_tags": APITag.metadata(), # type: ignore 

88 "servers": [ 

89 { 

90 "url": "https://api.polar.sh", 

91 "description": "Production environment", 

92 "x-speakeasy-server-id": "production", 

93 }, 

94 { 

95 "url": "https://sandbox-api.polar.sh", 

96 "description": "Sandbox environment", 

97 "x-speakeasy-server-id": "sandbox", 

98 }, 

99 ], 

100} 

101 

102 

103def set_openapi_generator(app: FastAPI) -> None: 1a

104 def _openapi_generator() -> dict[str, Any]: 

105 if app.openapi_schema: 105 ↛ 106line 105 didn't jump to line 106 because the condition on line 105 was never true1b

106 return app.openapi_schema 

107 

108 openapi_schema = get_openapi( 1b

109 title=app.title, 

110 version=app.version, 

111 openapi_version=app.openapi_version, 

112 summary=app.summary, 

113 description=app.description, 

114 terms_of_service=app.terms_of_service, 

115 contact=app.contact, 

116 license_info=app.license_info, 

117 routes=app.routes, 

118 webhooks=app.webhooks.routes, 

119 tags=app.openapi_tags, 

120 servers=app.servers, 

121 separate_input_output_schemas=app.separate_input_output_schemas, 

122 ) 

123 

124 openapi_schema = add_metadata_query_schema(openapi_schema) 1b

125 openapi_schema = add_oauth2_form_schemas(openapi_schema) 1b

126 

127 return openapi_schema 1b

128 

129 app.openapi = _openapi_generator # type: ignore[method-assign] 

130 

131 

132__all__ = [ 1a

133 "OPENAPI_PARAMETERS", 

134 "APITag", 

135 "set_openapi_generator", 

136]