RequestClient.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. 'use strict'
  2. const AuthError = require('./AuthError')
  3. // Remove the trailing slash so we can always safely append /xyz.
  4. function stripSlash (url) {
  5. return url.replace(/\/$/, '')
  6. }
  7. module.exports = class RequestClient {
  8. constructor (uppy, opts) {
  9. this.uppy = uppy
  10. this.opts = opts
  11. this.onReceiveResponse = this.onReceiveResponse.bind(this)
  12. }
  13. get hostname () {
  14. const { companion } = this.uppy.getState()
  15. const host = this.opts.serverUrl
  16. return stripSlash(companion && companion[host] ? companion[host] : host)
  17. }
  18. get defaultHeaders () {
  19. return {
  20. 'Accept': 'application/json',
  21. 'Content-Type': 'application/json'
  22. }
  23. }
  24. headers () {
  25. return Promise.resolve(Object.assign({}, this.defaultHeaders, this.opts.serverHeaders || {}))
  26. }
  27. _getPostResponseFunc (skip) {
  28. return (response) => {
  29. if (!skip) {
  30. return this.onReceiveResponse(response)
  31. }
  32. return response
  33. }
  34. }
  35. onReceiveResponse (response) {
  36. const state = this.uppy.getState()
  37. const companion = state.companion || {}
  38. const host = this.opts.serverUrl
  39. const headers = response.headers
  40. // Store the self-identified domain name for the Companion instance we just hit.
  41. if (headers.has('i-am') && headers.get('i-am') !== companion[host]) {
  42. this.uppy.setState({
  43. companion: Object.assign({}, companion, {
  44. [host]: headers.get('i-am')
  45. })
  46. })
  47. }
  48. return response
  49. }
  50. _getUrl (url) {
  51. if (/^(https?:|)\/\//.test(url)) {
  52. return url
  53. }
  54. return `${this.hostname}/${url}`
  55. }
  56. _json(res) {
  57. if (res.status === 401) {
  58. throw new AuthError()
  59. }
  60. if (res.status < 200 || res.status > 300) {
  61. throw new Error(`Failed request to ${res.url}. ${res.statusText}`)
  62. }
  63. return res.json()
  64. }
  65. get (path, skipPostResponse) {
  66. return new Promise((resolve, reject) => {
  67. this.headers().then((headers) => {
  68. fetch(this._getUrl(path), {
  69. method: 'get',
  70. headers: headers,
  71. credentials: 'same-origin'
  72. })
  73. .then(this._getPostResponseFunc(skipPostResponse))
  74. .then((res) => this._json(res).then(resolve))
  75. .catch((err) => {
  76. err = err.isAuthError ? err : new Error(`Could not get ${this._getUrl(path)}. ${err}`)
  77. reject(err)
  78. })
  79. })
  80. })
  81. }
  82. post (path, data, skipPostResponse) {
  83. return new Promise((resolve, reject) => {
  84. this.headers().then((headers) => {
  85. fetch(this._getUrl(path), {
  86. method: 'post',
  87. headers: headers,
  88. credentials: 'same-origin',
  89. body: JSON.stringify(data)
  90. })
  91. .then(this._getPostResponseFunc(skipPostResponse))
  92. .then((res) => this._json(res).then(resolve))
  93. .catch((err) => {
  94. err = err.isAuthError ? err : new Error(`Could not post ${this._getUrl(path)}. ${err}`)
  95. reject(err)
  96. })
  97. })
  98. })
  99. }
  100. delete (path, data, skipPostResponse) {
  101. return new Promise((resolve, reject) => {
  102. this.headers().then((headers) => {
  103. fetch(`${this.hostname}/${path}`, {
  104. method: 'delete',
  105. headers: headers,
  106. credentials: 'same-origin',
  107. body: data ? JSON.stringify(data) : null
  108. })
  109. .then(this._getPostResponseFunc(skipPostResponse))
  110. .then((res) => this._json(res).then(resolve))
  111. .catch((err) => {
  112. err = err.isAuthError ? err : new Error(`Could not delete ${this._getUrl(path)}. ${err}`)
  113. reject(err)
  114. })
  115. })
  116. })
  117. }
  118. }