Skip to content

lyouthzzz/protoc-gen-go-errors

Repository files navigation

protoc-gen-go-errors

1. 功能

  • 扩展 errors.proto,使用proto来定义“错误message”
  • 完全兼容 kratos errors

2. 安装

go install github.com/lyouthzzz/protoc-gen-go-errors

3. 使用说明

3.1 errors.proto文件放在项目中引用

syntax = "proto3";

package errors;

option go_package = "github.com/go-kratos/kratos/v2/errors;errors";
option java_multiple_files = true;
option java_package = "com.github.kratos.errors";
option objc_class_prefix = "KratosErrors";

import "google/protobuf/descriptor.proto";

extend google.protobuf.EnumOptions {
  int32 default_code = 1108;
  string default_message = 2108;
}

extend google.protobuf.EnumValueOptions {
  int32 code = 1109;
  string message = 2109;
}

3.2 定义错误码

syntax = "proto3";

package example;

import "errors/errors.proto";

option go_package = "github.com/lyouthzzz/protoc-gen-go-errors/examples";

enum ErrorReason {
  // 设置缺省错误码
  option (errors.default_code) = 500;
  // 设置缺省错误信息
  option (errors.default_message) = "未知错误";

  // 参数错误
  ERROR_REASON_INVALID_PARAM = 0 [(errors.code) = 400, (errors.message) = "参数错误"];
  // 用户未授权
  ERROR_REASON_USER_UNAUTHORIZED = 1 [(errors.code) = 401, (errors.message) = "用户未授权"];
  // 用户无权限
  ERROR_REASON_USER_FORBIDDEN = 2 [(errors.code) = 403, (errors.message) = "用户无权限"];
  // 409 业务错误:xxx状态冲突
  ERROR_REASON_STATUS_CONFLICT = 3 [(errors.code) = 409, (errors.message) = "xxx状态冲突"];
}

3.3 生成打桩代码

生成代码:make errors

protoc --proto_path=. \
       --go_out=paths=source_relative:. \
       --go-errors_out=paths=source_relative:. \
       $(EXAMPLE_PROTO_FILES)
// Code generated by protoc-gen-go-errors. DO NOT EDIT.

package examples

import (
	fmt "fmt"
	errors "github.com/go-kratos/kratos/v2/errors"
)

// This is a compile-time assertion to ensure that this generated file
// is compatible with the kratos package it is being compiled against.
const _ = errors.SupportPackageIsVersion1

// 参数错误
func IsErrorReasonInvalidParam(err error) bool {
	if err == nil {
		return false
	}
	e := errors.FromError(err)
	return e.Reason == ErrorReason_ERROR_REASON_INVALID_PARAM.String() && e.Code == 400
}

// 参数错误
func ErrorErrorReasonInvalidParam(format string, args ...interface{}) *errors.Error {
	return errors.New(400, ErrorReason_ERROR_REASON_INVALID_PARAM.String(), fmt.Sprintf(format, args...))
}

// 参数错误
func ErrorMessageErrorReasonInvalidParam() *errors.Error {
	return errors.New(400, ErrorReason_ERROR_REASON_INVALID_PARAM.String(), "参数错误")
}

// 用户未授权
func IsErrorReasonUserUnauthorized(err error) bool {
	if err == nil {
		return false
	}
	e := errors.FromError(err)
	return e.Reason == ErrorReason_ERROR_REASON_USER_UNAUTHORIZED.String() && e.Code == 401
}

// 用户未授权
func ErrorErrorReasonUserUnauthorized(format string, args ...interface{}) *errors.Error {
	return errors.New(401, ErrorReason_ERROR_REASON_USER_UNAUTHORIZED.String(), fmt.Sprintf(format, args...))
}

// 用户未授权
func ErrorMessageErrorReasonUserUnauthorized() *errors.Error {
	return errors.New(401, ErrorReason_ERROR_REASON_USER_UNAUTHORIZED.String(), "用户未授权")
}

// 用户无权限
func IsErrorReasonUserForbidden(err error) bool {
	if err == nil {
		return false
	}
	e := errors.FromError(err)
	return e.Reason == ErrorReason_ERROR_REASON_USER_FORBIDDEN.String() && e.Code == 403
}

// 用户无权限
func ErrorErrorReasonUserForbidden(format string, args ...interface{}) *errors.Error {
	return errors.New(403, ErrorReason_ERROR_REASON_USER_FORBIDDEN.String(), fmt.Sprintf(format, args...))
}

// 用户无权限
func ErrorMessageErrorReasonUserForbidden() *errors.Error {
	return errors.New(403, ErrorReason_ERROR_REASON_USER_FORBIDDEN.String(), "用户无权限")
}

// 409 业务错误:xxx状态冲突
func IsErrorReasonStatusConflict(err error) bool {
	if err == nil {
		return false
	}
	e := errors.FromError(err)
	return e.Reason == ErrorReason_ERROR_REASON_STATUS_CONFLICT.String() && e.Code == 409
}

// 409 业务错误:xxx状态冲突
func ErrorErrorReasonStatusConflict(format string, args ...interface{}) *errors.Error {
	return errors.New(409, ErrorReason_ERROR_REASON_STATUS_CONFLICT.String(), fmt.Sprintf(format, args...))
}

// 409 业务错误:xxx状态冲突
func ErrorMessageErrorReasonStatusConflict() *errors.Error {
	return errors.New(409, ErrorReason_ERROR_REASON_STATUS_CONFLICT.String(), "xxx状态冲突")
}

3.4 业务中使用错误码

// 第一种:使用proto定义错误信息
func A() error {
    return ErrorMessageErrorReasonInvalidParam()
}
// 第二种:覆盖proto错误信息(以前用法)
func B() error {
    return ErrorErrorReasonInvalidParam("用户ID不能为空")
}
// 第三种:使用错误携带信息,携带根因,携带元数据
func C() error {
    return ErrorMessageErrorReasonStatusConflict().
        WithCause(fmt.Errorf("status has already updated")).
        WithMetadata(map[string]string{"uid": "xxxxxxxxx"})
}