Результат gRPC-вызова передаётся через код состояния, а не через привычный HTTP-статус. Клиент по нему решает, что делать дальше.
Коды
InvalidArgument- неверный запрос;NotFound- объект отсутствует;AlreadyExists- конфликт создания;PermissionDenied- нет права;Unauthenticated- не аутентифицирован;FailedPrecondition- состояние не позволяет операцию;ResourceExhausted- квота или лимит;DeadlineExceeded- истёк дедлайн;Unavailable- временная недоступность;Internal- внутренняя ошибка.
Повторять по умолчанию стоит только временные ошибки, причём операция должна быть идемпотентной.
status.New
st := status.New(codes.InvalidArgument, "Заказ не проходит проверку")
st, err := st.WithDetails(&errdetails.BadRequest{
FieldViolations: []*errdetails.BadRequest_FieldViolation{
{Field: "items", Description: "пустой заказ"},
},
})
if err != nil {
return nil, status.Error(codes.Internal, "cannot build details")
}
return nil, st.Err()
BadRequest передаёт нарушения по полям. ErrorInfo добавляет машинную причину и домен, RetryInfo - рекомендуемую задержку перед повтором.
На клиенте status.Convert(err) даёт код, сообщение и детали. Внутренний стек и секреты в сообщение не кладут.
Как читать ошибку клиенту
Не всякое сообщение стоит показывать пользователю. Клиент сначала смотрит код и машинную причину, затем решает, что делать: исправить поле, повторить позже или показать общий сбой.
st := status.Convert(err)
for _, detail := range st.Details() {
if info, ok := detail.(*errdetails.ErrorInfo); ok {
log.Printf("reason=%s domain=%s", info.Reason, info.Domain)
}
}
ErrorInfo.Reason должен быть устойчивой строкой вроде ORDER_NOT_FOUND, а не русским предложением, которое меняется от версии к версии. Для повтора используют RetryInfo, но сначала проверяют идемпотентность и общий бюджет времени. Если сервер не прислал причину, деталей не выдумывают: остаются код и общее сообщение.
Коротко
- Код выбирается по смыслу ошибки, а не по удобству.
Unavailableвременный,FailedPreconditionтребует изменения состояния.- Детали делают ошибку машиночитаемой: поле, причина, повтор.
- Секреты и внутренний стек клиенту не отдают.