api.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import { $fetch } from 'ofetch'
  2. import { useLogger } from '@/composables/useLogger'
  3. import { useUser } from '~/store/useUser'
  4. interface TUserData {
  5. user_id: number
  6. access_token: string
  7. }
  8. interface Detail {
  9. type: string
  10. loc: string[]
  11. msg: string
  12. }
  13. interface TException {
  14. error?: string
  15. code?: number
  16. detail?: Detail[]
  17. }
  18. export class API {
  19. private log
  20. private module: string = 'API'
  21. private API_URL: string = useRuntimeConfig().public.API_URL
  22. private user = useUser()
  23. constructor(module: string) {
  24. this.module = module
  25. this.log = useLogger(this.module)
  26. }
  27. private throwError(request: string, data: TException) {
  28. const err = {
  29. info: '',
  30. request,
  31. }
  32. if (Object.prototype.hasOwnProperty.call(data, 'code') && Object.prototype.hasOwnProperty.call(data, 'error')) {
  33. err.info = `${data.error} (${data.code})`
  34. }
  35. else if (Object.prototype.hasOwnProperty.call(data, 'detail')) {
  36. const details = data.detail[0]
  37. err.info = `${details.type} ${details.loc.join(', ')} (${details.msg})`
  38. }
  39. else {
  40. err.info = data
  41. }
  42. this.log.error(err)
  43. showError(data)
  44. }
  45. private instance = $fetch.create({
  46. baseURL: this.API_URL,
  47. onRequest: (ctx) => {
  48. if (!this.user.data.access_token && ctx.request !== '/login')
  49. navigateTo('/auth')
  50. },
  51. onResponse: (ctx) => {
  52. const statusCode = ctx.response.status
  53. if (statusCode > 300)
  54. this.throwError(ctx.request.toString(), ctx.response._data)
  55. },
  56. onResponseError: async (ctx) => {
  57. const statusCode = ctx.response.status
  58. if (statusCode === 401) {
  59. const newToken: TUserData = await this.get('/user/refresh', {
  60. access_token: ctx.request.toString().split('?')[1].split('=')[1],
  61. })
  62. this.user.data.access_token = newToken.access_token
  63. this.log.log('Access token обновлен:', this.user.data.access_token)
  64. return this.instance(ctx.request, {
  65. method: ctx.request.method,
  66. body: ctx.request.body,
  67. params: ctx.request.params,
  68. })
  69. }
  70. else if (statusCode === 400 && ctx.request !== `${this.API_URL}/user/login`) {
  71. this.user.logout()
  72. }
  73. else {
  74. this.throwError(ctx.request.toString(), ctx.response._data)
  75. }
  76. },
  77. })
  78. get = <T>(url: string, params?: object): Promise<T> => {
  79. return this.instance(url, {
  80. method: 'GET',
  81. params: {
  82. access_token: this.user.data.access_token,
  83. ...params,
  84. },
  85. })
  86. }
  87. post = <T>(url: string, body?: object, params?: object): Promise<T> => {
  88. return this.instance(url, {
  89. method: 'POST',
  90. body,
  91. params: {
  92. access_token: this.user.data.access_token,
  93. ...params,
  94. },
  95. })
  96. }
  97. put = <T>(url: string, body?: object, params?: object): Promise<T> => {
  98. return this.instance(url, {
  99. method: 'PUT',
  100. body,
  101. params: {
  102. access_token: this.user.data.access_token,
  103. ...params,
  104. },
  105. })
  106. }
  107. delete = <T>(url: string, body?: object, params?: object): Promise<T> => {
  108. return this.instance(url, {
  109. method: 'DELETE',
  110. body,
  111. params: {
  112. access_token: this.user.data.access_token,
  113. ...params,
  114. },
  115. })
  116. }
  117. }