-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy patherrors.go
236 lines (206 loc) · 10.3 KB
/
errors.go
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
package apipgu
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
)
// Ошибки первого уровня.
var (
ErrOrderCreate = errors.New("ошибка OrderCreate")
ErrPushChunked = errors.New("ошибка OrderPushChunked")
ErrPush = errors.New("ошибка OrderPush")
ErrOrderInfo = errors.New("ошибка OrderInfo")
ErrOrderCancel = errors.New("ошибка OrderCancel")
ErrAttachmentDownload = errors.New("ошибка AttachmentDownload")
ErrDict = errors.New("ошибка Dict")
ErrGetOrdersStatus = errors.New("ошибка GetOrdersStatus")
ErrGetUpdatedAfter = errors.New("ошибка GetUpdatedAfter")
ErrService = errors.New("ошибка услуги")
)
// Ошибки второго уровня.
var (
ErrMultipartBody = errors.New("ошибка подготовки multipart-содержимого")
ErrRequest = errors.New("ошибка HTTP-запроса")
ErrUnexpectedContentType = errors.New("неожиданный тип содержимого")
ErrJSONUnmarshal = errors.New("ошибка чтения JSON")
ErrNoFiles = errors.New("нет файлов во вложении")
ErrZip = errors.New("ошибка создания zip-архива")
ErrGUID = errors.New("не удалось сгенерировать GUID")
ErrXMLMarshal = errors.New("ошибка создания XML")
ErrNilArchive = errors.New("не передан архив")
ErrWrongOrderID = errors.New("некорректный ID заявления")
ErrInvalidFileLink = errors.New("некорректная ссылка на файл")
ErrDictResponse = errors.New("ошибка получения справочных данных")
)
// HTTP-ошибки.
//
// Подробнее см. "Спецификация API ЕПГУ версия 1.12",
// "Приложение 4. Ошибки, возвращаемые при запросах к API ЕПГУ"
var (
ErrStatusOrderNotFound = errors.New("заявление не найдено") // HTTP 204
ErrStatusBadRequest = errors.New("неверные параметры") // HTTP 400
ErrStatusUnauthorized = errors.New("отказ в доступе") // HTTP 401
ErrStatusForbidden = errors.New("доступ запрещен") // HTTP 403
ErrStatusURLNotFound = errors.New("не найден URL запроса") // HTTP 404
ErrStatusUnableToHandleRequest = errors.New("невозможно обработать запрос") // HTTP 409
ErrStatusTooManyRequests = errors.New("слишком много запросов") // HTTP 429
ErrStatusInternalError = errors.New("внутренняя ошибка") // HTTP 500
ErrStatusBadGateway = errors.New("некорректный шлюз") // HTTP 502
ErrStatusServiceUnavailable = errors.New("сервис недоступен") // HTTP 503
ErrStatusGatewayTimeout = errors.New("шлюз не отвечает") // HTTP 504
ErrStatusUnexpected = errors.New("неожиданный HTTP-статус") // Другие HTTP-коды ошибок
)
// Ошибки ЕПГУ.
//
// Подробнее см. "Спецификация API ЕПГУ версия 1.12",
// "Приложение 4. Ошибки, возвращаемые при запросах к API ЕПГУ"
//
// Пример JSON-ответа от ЕПГУ при ошибке:
//
// {
// "code": "order_access",
// "message": "У пользователя нет прав для работы с текущим заявлением"
// }
var (
// Ошибка ЕПГУ: code = access_denied_person_permissions
ErrCodeAccessDeniedPersonPermissions = errors.New("пользователь не дал согласие Вашей системе на выполнение данной операции")
// Ошибка ЕПГУ: code = access_denied_service
ErrCodeAccessDeniedService = errors.New("доступ ВИС к запрашиваемой услуге запрещен")
// Ошибка ЕПГУ: code = access_denied_system
ErrCodeAccessDeniedSystem = errors.New("доступ запрещен для ВИС, отправляющей запрос")
// Ошибка ЕПГУ: code = access_denied_user
ErrCodeAccessDeniedUser = errors.New("доступ запрещен для данного типа пользователя")
// Ошибка ЕПГУ: code = access_denied_user_legal
ErrCodeAccessDeniedUserLegal = errors.New("попытка создать заявления с использованием токена, полученного для организации, которая не является владельцем ВИС, отправляющей данный запрос")
// Ошибка ЕПГУ: code = bad_delegation
ErrCodeBadDelegation = errors.New("нет необходимых полномочий для создания заявления")
// Ошибка ЕПГУ: code = bad_request
ErrCodeBadRequest = errors.New("ошибка в параметрах запроса")
// Ошибка ЕПГУ: code = cancel_not_allowed
ErrCodeCancelNotAllowed = errors.New("отмена заявления в текущем статусе невозможна")
// Ошибка ЕПГУ: code = config_delegation
ErrCodeConfigDelegation = errors.New("полномочие для создания и подачи заявления по заданной услуги не существует")
// Ошибка ЕПГУ: code = internal_error
ErrCodeInternalError = errors.New("ошибка в обработке заявления, причины которой можно выяснить при анализе инцидента")
// Ошибка ЕПГУ: code = limitation_exception
ErrCodeLimitationException = errors.New("превышение установленных ограничений, указанных в Приложении 3 к Спецификации")
// Ошибка ЕПГУ: code = not_found
ErrCodeNotFound = errors.New("заявление не найдено")
// Ошибка ЕПГУ: code = order_access
ErrCodeOrderAccess = errors.New("у пользователя нет прав для работы с текущим заявлением")
// Ошибка ЕПГУ: code = push_denied
ErrCodePushDenied = errors.New("нет прав для отправки заявления. Отправить заявление может только руководитель организации или сотрудник с доверенностью")
// Ошибка ЕПГУ: code = service_not_found
ErrCodeServiceNotFound = errors.New("не найдена услуга, заданная кодом serviceCode в запросе")
// Ошибка ЕПГУ: неизвестное значение code
ErrCodeUnexpected = errors.New("неожиданный код ошибки")
// Ошибка ЕПГУ: code не указан
ErrCodeNotSpecified = errors.New("код ошибки не указан")
)
// responseError возвращает ошибку из HTTP-ответа от API ЕПГУ.
// Пример сообщения об ошибке:
//
// HTTP 403 Forbidden: доступ запрещен: доступ запрещен для ВИС, отправляющей запрос [code='access_denied_system', message='ValidationCommonError.notAllowed']
func responseError(res *http.Response) error {
if res == nil || (res.StatusCode != 204 && res.StatusCode < 400) {
return nil
}
switch res.StatusCode {
case 400, 403, 409, 500:
return fmt.Errorf("HTTP %s: %w: %w", res.Status, httpStatusError(res.StatusCode), bodyError(res))
default:
return fmt.Errorf("HTTP %s: %w", res.Status, httpStatusError(res.StatusCode))
}
}
func httpStatusError(statusCode int) error {
switch statusCode {
case 204:
return ErrStatusOrderNotFound
case 400:
return ErrStatusBadRequest
case 401:
return ErrStatusUnauthorized
case 403:
return ErrStatusForbidden
case 404:
return ErrStatusURLNotFound
case 409:
return ErrStatusUnableToHandleRequest
case 429:
return ErrStatusTooManyRequests
case 500:
return ErrStatusInternalError
case 502:
return ErrStatusBadGateway
case 503:
return ErrStatusServiceUnavailable
case 504:
return ErrStatusGatewayTimeout
default:
return ErrStatusUnexpected
}
}
func bodyError(res *http.Response) error {
body, err := io.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("%w: %w", ErrRequest, err)
}
ct := res.Header.Get("Content-Type")
if strings.HasPrefix(ct, "application/json") {
return jsonError(body)
}
return fmt.Errorf("%w: '%s'", ErrUnexpectedContentType, ct)
}
func jsonError(body []byte) error {
errResponse := &dtoErrorResponse{}
err := json.Unmarshal(body, errResponse)
if err != nil {
return fmt.Errorf("%w: %w", ErrJSONUnmarshal, err)
}
switch errResponse.Code {
case "access_denied_person_permissions":
err = ErrCodeAccessDeniedPersonPermissions
case "access_denied_service":
err = ErrCodeAccessDeniedService
case "access_denied_system":
err = ErrCodeAccessDeniedSystem
case "access_denied_user":
err = ErrCodeAccessDeniedUser
case "access_denied_user_legal":
err = ErrCodeAccessDeniedUserLegal
case "bad_delegation":
err = ErrCodeBadDelegation
case "bad_request":
err = ErrCodeBadRequest
case "cancel_not_allowed":
err = ErrCodeCancelNotAllowed
case "config_delegation":
err = ErrCodeConfigDelegation
case "internal_error":
err = ErrCodeInternalError
case "limitation_exception":
err = ErrCodeLimitationException
case "not_found":
err = ErrCodeNotFound
case "order_access":
err = ErrCodeOrderAccess
case "push_denied":
err = ErrCodePushDenied
case "service_not_found":
err = ErrCodeServiceNotFound
case "":
err = ErrCodeNotSpecified
default:
err = ErrCodeUnexpected
}
return fmt.Errorf("%w [code='%s', message='%s']", err, errResponse.Code, errResponse.Message)
}
func dictError(dictResponseError dtoDictResponseError) error {
if dictResponseError.Code == 0 {
return nil
}
return fmt.Errorf("%w [code='%d', message='%s']", ErrDictResponse, dictResponseError.Code, dictResponseError.Message)
}