Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

178 linhas
5.4 KiB

  1. import json
  2. from typing import Any, Dict, Optional
  3. from fastapi.encoders import jsonable_encoder
  4. from starlette.responses import HTMLResponse
  5. def get_swagger_ui_html(
  6. *,
  7. openapi_url: str,
  8. title: str,
  9. swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui-bundle.js",
  10. swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css",
  11. swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
  12. oauth2_redirect_url: Optional[str] = None,
  13. init_oauth: Optional[Dict[str, Any]] = None,
  14. ) -> HTMLResponse:
  15. html = f"""
  16. <!DOCTYPE html>
  17. <html>
  18. <head>
  19. <link type="text/css" rel="stylesheet" href="{swagger_css_url}">
  20. <link rel="shortcut icon" href="{swagger_favicon_url}">
  21. <title>{title}</title>
  22. </head>
  23. <body>
  24. <div id="swagger-ui">
  25. </div>
  26. <script src="{swagger_js_url}"></script>
  27. <!-- `SwaggerUIBundle` is now available on the page -->
  28. <script>
  29. const ui = SwaggerUIBundle({{
  30. url: '{openapi_url}',
  31. """
  32. if oauth2_redirect_url:
  33. html += f"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',"
  34. html += """
  35. dom_id: '#swagger-ui',
  36. presets: [
  37. SwaggerUIBundle.presets.apis,
  38. SwaggerUIBundle.SwaggerUIStandalonePreset
  39. ],
  40. layout: "BaseLayout",
  41. deepLinking: true,
  42. showExtensions: true,
  43. showCommonExtensions: true
  44. })"""
  45. if init_oauth:
  46. html += f"""
  47. ui.initOAuth({json.dumps(jsonable_encoder(init_oauth))})
  48. """
  49. html += """
  50. </script>
  51. </body>
  52. </html>
  53. """
  54. return HTMLResponse(html)
  55. def get_redoc_html(
  56. *,
  57. openapi_url: str,
  58. title: str,
  59. redoc_js_url: str = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js",
  60. redoc_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
  61. with_google_fonts: bool = True,
  62. ) -> HTMLResponse:
  63. html = f"""
  64. <!DOCTYPE html>
  65. <html>
  66. <head>
  67. <title>{title}</title>
  68. <!-- needed for adaptive design -->
  69. <meta charset="utf-8"/>
  70. <meta name="viewport" content="width=device-width, initial-scale=1">
  71. """
  72. if with_google_fonts:
  73. html += """
  74. <link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
  75. """
  76. html += f"""
  77. <link rel="shortcut icon" href="{redoc_favicon_url}">
  78. <!--
  79. ReDoc doesn't change outer page styles
  80. -->
  81. <style>
  82. body {{
  83. margin: 0;
  84. padding: 0;
  85. }}
  86. </style>
  87. </head>
  88. <body>
  89. <redoc spec-url="{openapi_url}"></redoc>
  90. <script src="{redoc_js_url}"> </script>
  91. </body>
  92. </html>
  93. """
  94. return HTMLResponse(html)
  95. def get_swagger_ui_oauth2_redirect_html() -> HTMLResponse:
  96. html = """
  97. <!DOCTYPE html>
  98. <html lang="en-US">
  99. <body onload="run()">
  100. </body>
  101. </html>
  102. <script>
  103. 'use strict';
  104. function run () {
  105. var oauth2 = window.opener.swaggerUIRedirectOauth2;
  106. var sentState = oauth2.state;
  107. var redirectUrl = oauth2.redirectUrl;
  108. var isValid, qp, arr;
  109. if (/code|token|error/.test(window.location.hash)) {
  110. qp = window.location.hash.substring(1);
  111. } else {
  112. qp = location.search.substring(1);
  113. }
  114. arr = qp.split("&")
  115. arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
  116. qp = qp ? JSON.parse('{' + arr.join() + '}',
  117. function (key, value) {
  118. return key === "" ? value : decodeURIComponent(value)
  119. }
  120. ) : {}
  121. isValid = qp.state === sentState
  122. if ((
  123. oauth2.auth.schema.get("flow") === "accessCode"||
  124. oauth2.auth.schema.get("flow") === "authorizationCode"
  125. ) && !oauth2.auth.code) {
  126. if (!isValid) {
  127. oauth2.errCb({
  128. authId: oauth2.auth.name,
  129. source: "auth",
  130. level: "warning",
  131. message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
  132. });
  133. }
  134. if (qp.code) {
  135. delete oauth2.state;
  136. oauth2.auth.code = qp.code;
  137. oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
  138. } else {
  139. let oauthErrorMsg
  140. if (qp.error) {
  141. oauthErrorMsg = "["+qp.error+"]: " +
  142. (qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
  143. (qp.error_uri ? "More info: "+qp.error_uri : "");
  144. }
  145. oauth2.errCb({
  146. authId: oauth2.auth.name,
  147. source: "auth",
  148. level: "error",
  149. message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
  150. });
  151. }
  152. } else {
  153. oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
  154. }
  155. window.close();
  156. }
  157. </script>
  158. """
  159. return HTMLResponse(content=html)