go-zero icon indicating copy to clipboard operation
go-zero copied to clipboard

how to pass errors in rpc services back into api services?

Open titherman opened this issue 1 year ago • 7 comments

在写rpc 的时候, 我想把 rpc的某个业务流程方面的错误返回给api. return xx.Reply, errorx.CodeError() 这个errorx.CodeError()对象到api 的时候,类型就不在是 CodeError类型的error了. 现在只能在 reply里面定义code 和msg 我想问下, 好的go-zero项目 关于 rpc返回业务流程错误是怎么做的? 求求大佬给一个好的建议. (业务流程的错误可能有几种)

titherman avatar Sep 16 '22 03:09 titherman

Try using type assertions

gitsang avatar Sep 16 '22 05:09 gitsang

Try using type assertions

好像是没有办法断言的 在到达api层的时候,他的类型已经不是errorx.CodeErr了

titherman avatar Sep 16 '22 06:09 titherman

Refer to Google's error handling method: https://cloud.google.com/apis/design/errors#error_model

Use status.Status.WithDetails(details ...proto.Message) to return detailed business errors to the client.

chenquan avatar Sep 16 '22 11:09 chenquan

You should not use errorx.CodeError in your svc or biz layer. errorx.CodeError is design for api.

I think that each layer of the program should handle and wrap errors individually, and should not throw errors >2 layers, otherwise the error will become un-enumerable when the upper layer handles errors.

Bad

// db layer
var ErrNotFound = errors.New("not found")
func Find() error {
    return ErrNotFound
}

// svc layer
func Find() error {
    return db.Find()
}

// logic layer
func FindLogic() (int, interface{}) {
    err := svc.Find()
    if err != nil {
        if errors.Is(db.ErrNotFound, err) { // logic layer should not handle error from db layer
            return 404, "fail"
        } else {
            return 200, "success"
        }
    }
}

Bad

// db layer
var ErrNotFound = errors.New("not found")
func Find() (int, error) {
    return 404, ErrNotFound // logic layer should not consider about api error
}

// svc layer
func Find() (int, error) {
    return db.Find()
}

// logic layer
func FindLogic() (int, interface{}) {
    return svc.Find() // api should not expose db error to user
}

Good

// db layer
var ErrNotFound = errors.New("not found")
func Find() error {
    return ErrNotFound
}

// svc layer
var ErrNotFound = errors.New("not found") // wrap the error
func Find() error {
    err := db.Find()
    if err != nil {
        if errors.Is(db.ErrNotFound, err) {
            return ErrNotFound
        } else {
            return nil
        }
    }
}

// logic layer
func FindLogic() (int, interface{}) {
    err := svc.Find()
    if err != nil {
        if errors.Is(svc.ErrNotFound, err) { // should only handle svc error
            return 404, "fail"
        } else {
            return 200, "success"
        }
    }
}

gitsang avatar Sep 18 '22 03:09 gitsang

Try using type assertions

好像是没有办法断言的 在到达api层的时候,他的类型已经不是errorx.CodeErr了

errorx.CodeErr is the implement of error. It should be possible to be asserted

gitsang avatar Sep 18 '22 03:09 gitsang

参考肝王的looklook吧,这种方式前端看不到错误信息https://github.com/Mikaelemmmm/go-zero-looklook

jsonMark avatar Sep 21 '22 09:09 jsonMark

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


Please refer to Live King's looklook, this way you can't see the error message on the front end https://github.com/Mikaelemmmm/go-zero-looklook

Issues-translate-bot avatar Sep 21 '22 09:09 Issues-translate-bot