-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathapi.js
More file actions
87 lines (80 loc) · 2.15 KB
/
api.js
File metadata and controls
87 lines (80 loc) · 2.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
const axios = require('axios')
const { setTimeout } = require('timers/promises')
const MAX_RETRIES = 20
const DEFAULT_TIMEOUT = 3e3
class ApiError extends Error {
name = 'ApiError'
constructor(axiosError) {
super(axiosError.message)
if (axiosError.response) {
const { data, config } = axiosError.response
this.message = data?.error?.message || JSON.stringify(data)
this.method = config.method
this.url = config.url
this.body = config?.data
}
}
}
module.exports = class API {
constructor(token) {
this.request = axios.create({
baseURL: 'https://api.spotify.com/v1/',
headers: {
Authorization: `Bearer ${token}`,
},
})
;['get', 'put', 'post', 'delete'].forEach((k) => {
const method = this.request[k]
this.request[k] = (url, data, config = {}) =>
method(url, data, config).catch(async (err) => {
const statusCode = err.response?.status
console.log(
'Error',
statusCode,
err.config.method,
err.response.request.path,
)
const updatedConfig = {
...config,
retries: (config.retries ?? MAX_RETRIES) - 1,
}
if (updatedConfig.retries < 0) {
throw new ApiError(err)
}
switch (statusCode) {
case 404:
return {}
case 400:
case 403:
case 429:
case 500:
case 501:
case 502:
case 504:
const ms =
Number(err.response.headers['retry-after']) * 1e3 + 1e3 ||
DEFAULT_TIMEOUT
console.log(
`Waiting ${ms / 1e3} second (retries left: ${updatedConfig.retries})`,
)
await setTimeout(ms)
return this.request[k](url, data, updatedConfig)
default:
throw new ApiError(err)
}
})
})
}
get get() {
return this.request.get
}
get post() {
return this.request.post
}
get put() {
return this.request.put
}
get delete() {
return this.request.delete
}
}