ApiCaller.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. Copyright (C) 2017 Cloudbase Solutions SRL
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. // @flow
  15. import axios from 'axios'
  16. import type { AxiosXHRConfig, $AxiosXHR } from 'axios'
  17. import NotificationStore from '../stores/NotificationStore'
  18. type Cancelable = {
  19. requestId: string,
  20. cancel: () => void,
  21. }
  22. type RequestOptions = {|
  23. url: string,
  24. method?: string,
  25. cancelId?: string,
  26. headers?: {[string]: string},
  27. data?: any,
  28. responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream',
  29. |}
  30. let cancelables: Cancelable[] = []
  31. const CancelToken = axios.CancelToken
  32. const addCancelable = (cancelable: Cancelable) => {
  33. cancelables.unshift(cancelable)
  34. if (cancelables.length > 100) {
  35. cancelables.pop()
  36. }
  37. }
  38. class ApiCaller {
  39. constructor() {
  40. axios.defaults.headers.common['Content-Type'] = 'application/json'
  41. }
  42. cancelRequests(cancelRequestId: string) {
  43. const filteredCancelables = cancelables.filter(r => r.requestId === cancelRequestId)
  44. filteredCancelables.forEach(c => {
  45. c.cancel()
  46. })
  47. cancelables = cancelables.filter(r => r.requestId !== cancelRequestId)
  48. }
  49. get(url: string): Promise<$AxiosXHR<any>> {
  50. return this.send({ url })
  51. }
  52. send(options: RequestOptions): Promise<$AxiosXHR<any>> {
  53. return new Promise((resolve, reject) => {
  54. const axiosOptions: AxiosXHRConfig<any> = {
  55. url: options.url,
  56. method: options.method || 'GET',
  57. headers: options.headers || {},
  58. data: options.data || null,
  59. responseType: options.responseType || 'json',
  60. }
  61. if (options.cancelId) {
  62. let cancel = () => {}
  63. axiosOptions.cancelToken = new CancelToken(c => {
  64. cancel = c
  65. })
  66. addCancelable({ requestId: options.cancelId, cancel })
  67. }
  68. console.log(`%cSending ${axiosOptions.method || 'GET'} Request to ${axiosOptions.url}`, 'color: #F5A623')
  69. axios(axiosOptions).then((response) => {
  70. console.log(`%cResponse ${axiosOptions.url}`, 'color: #0044CA', response.data)
  71. resolve(response)
  72. }).catch(error => {
  73. const loginUrl = '#/'
  74. if (error.response) {
  75. // The request was made and the server responded with a status code
  76. // that falls out of the range of 2xx
  77. if (error.response.status !== 401 || window.location.hash !== loginUrl) {
  78. NotificationStore.notify(error.response.data.error.message, 'error')
  79. }
  80. if (error.response.status === 401 && window.location.hash !== loginUrl) {
  81. window.location.href = '/'
  82. }
  83. console.log(`%cError Response: ${axiosOptions.url}`, 'color: #D0021B', error.response)
  84. reject(error.response)
  85. } else if (error.request) {
  86. // The request was made but no response was received
  87. // `error.request` is an instance of XMLHttpRequest
  88. NotificationStore.notify('Request failed, there might be a problem with the connection to the server.', 'error')
  89. console.log(`%cError No Response: ${axiosOptions.url}`, 'color: #D0021B')
  90. reject({})
  91. } else {
  92. reject({})
  93. if (error.constructor.name === 'Cancel') {
  94. return
  95. }
  96. // Something happened in setting up the request that triggered an Error
  97. NotificationStore.notify('Request failed, there might be a problem with the connection to the server.', 'error')
  98. console.log(`%cError Something happened in setting up the request: ${axiosOptions.url}`, 'color: #D0021B')
  99. }
  100. })
  101. })
  102. }
  103. setDefaultHeader(name: string, value: ?string) {
  104. axios.defaults.headers.common[name] = value
  105. }
  106. }
  107. export default new ApiCaller()