EffectiveURL.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { combineLatest, Observable } from "rxjs"
  2. import { map } from "rxjs/operators"
  3. import { FormDataKeyValue, HoppRESTRequest } from "../types/HoppRESTRequest"
  4. import parseTemplateString from "../templating"
  5. import { Environment, getGlobalVariables } from "~/newstore/environments"
  6. export interface EffectiveHoppRESTRequest extends HoppRESTRequest {
  7. /**
  8. * The effective final URL.
  9. *
  10. * This contains path, params and environment variables all applied to it
  11. */
  12. effectiveFinalURL: string
  13. effectiveFinalHeaders: { key: string; value: string }[]
  14. effectiveFinalParams: { key: string; value: string }[]
  15. effectiveFinalBody: FormData | string | null
  16. }
  17. function getFinalBodyFromRequest(
  18. request: HoppRESTRequest,
  19. env: Environment
  20. ): FormData | string | null {
  21. if (request.body.contentType === null) {
  22. return null
  23. }
  24. if (request.body.contentType === "multipart/form-data") {
  25. const formData = new FormData()
  26. request.body.body
  27. .filter((x) => x.key !== "" && x.active) // Remove empty keys
  28. .map(
  29. (x) =>
  30. <FormDataKeyValue>{
  31. active: x.active,
  32. isFile: x.isFile,
  33. key: parseTemplateString(x.key, env.variables),
  34. value: x.isFile
  35. ? x.value
  36. : parseTemplateString(x.value, env.variables),
  37. }
  38. )
  39. .forEach((entry) => {
  40. if (!entry.isFile) formData.append(entry.key, entry.value)
  41. else entry.value.forEach((blob) => formData.append(entry.key, blob))
  42. })
  43. return formData
  44. } else return request.body.body
  45. }
  46. /**
  47. * Outputs an executable request format with environment variables applied
  48. *
  49. * @param request The request to source from
  50. * @param environment The environment to apply
  51. *
  52. * @returns An object with extra fields defining a complete request
  53. */
  54. export function getEffectiveRESTRequest(
  55. request: HoppRESTRequest,
  56. environment: Environment
  57. ): EffectiveHoppRESTRequest {
  58. const envVariables = [...environment.variables, ...getGlobalVariables()]
  59. const effectiveFinalHeaders = request.headers
  60. .filter(
  61. (x) =>
  62. x.key !== "" && // Remove empty keys
  63. x.active // Only active
  64. )
  65. .map((x) => ({
  66. // Parse out environment template strings
  67. active: true,
  68. key: parseTemplateString(x.key, envVariables),
  69. value: parseTemplateString(x.value, envVariables),
  70. }))
  71. // Authentication
  72. if (request.auth.authActive) {
  73. // TODO: Support a better b64 implementation than btoa ?
  74. if (request.auth.authType === "basic") {
  75. const username = parseTemplateString(request.auth.username, envVariables)
  76. const password = parseTemplateString(request.auth.password, envVariables)
  77. effectiveFinalHeaders.push({
  78. active: true,
  79. key: "Authorization",
  80. value: `Basic ${btoa(`${username}:${password}`)}`,
  81. })
  82. } else if (
  83. request.auth.authType === "bearer" ||
  84. request.auth.authType === "oauth-2"
  85. ) {
  86. effectiveFinalHeaders.push({
  87. active: true,
  88. key: "Authorization",
  89. value: `Bearer ${parseTemplateString(
  90. request.auth.token,
  91. envVariables
  92. )}`,
  93. })
  94. }
  95. }
  96. const effectiveFinalBody = getFinalBodyFromRequest(request, environment)
  97. if (request.body.contentType)
  98. effectiveFinalHeaders.push({
  99. active: true,
  100. key: "content-type",
  101. value: request.body.contentType,
  102. })
  103. return {
  104. ...request,
  105. effectiveFinalURL: parseTemplateString(request.endpoint, envVariables),
  106. effectiveFinalHeaders,
  107. effectiveFinalParams: request.params
  108. .filter(
  109. (x) =>
  110. x.key !== "" && // Remove empty keys
  111. x.active // Only active
  112. )
  113. .map((x) => ({
  114. active: true,
  115. key: parseTemplateString(x.key, envVariables),
  116. value: parseTemplateString(x.value, envVariables),
  117. })),
  118. effectiveFinalBody,
  119. }
  120. }
  121. /**
  122. * Creates an Observable Stream that emits HoppRESTRequests whenever
  123. * the input streams emit a value
  124. *
  125. * @param request$ The request stream containing request data
  126. * @param environment$ The environment stream containing environment data to apply
  127. *
  128. * @returns Observable Stream for the Effective Request Object
  129. */
  130. export function getEffectiveRESTRequestStream(
  131. request$: Observable<HoppRESTRequest>,
  132. environment$: Observable<Environment>
  133. ): Observable<EffectiveHoppRESTRequest> {
  134. return combineLatest([request$, environment$]).pipe(
  135. map(([request, env]) => getEffectiveRESTRequest(request, env))
  136. )
  137. }