Spec/Constant
Spec
Enum and Error Extension User Manual — add business codes, multi-language messages, and error metadata to enum values.
Add business codes, multi-language messages, and error metadata to enum values.
apihug/protobuf/extend/constant.protoapihug/protobuf/swagger/annotations.proto when you also want enum display metadata via (hope.swagger.enm)NEVER add any file-level option declarations in proto files:
// Forbidden to use the following options (rely on default code generation configuration)
option java_package = "...";
option java_multiple_files = true;
option go_package = "...";
All code generation configurations are automatically managed by the build system. Strictly forbidden to manually add any file-level options.
import "apihug/protobuf/extend/constant.proto";
ENUM_NAME = sequence [(hope.constant.field) = {
code: business_code; // int32
message: "English"; // string
message2: "Chinese"; // string
}];
syntax = "proto3";
package com.example.order;
import "apihug/protobuf/extend/constant.proto";
enum OrderStatusEnum {
PLACED = 0 [(hope.constant.field) = {
code: 1,
message: "Placed",
message2: "已经下单"
}];
APPROVED = 1 [(hope.constant.field) = {
code: 2,
message: "Approved",
message2: "已经审批"
}];
DELIVERED = 2 [(hope.constant.field) = {
code: 4,
message: "Delivered",
message2: "已经发货"
}];
}
| Field | Type | Required | Description |
|---|---|---|---|
code | int32 | Yes | Business code, unique within the same enum |
message | string | Yes | Primary language message (English), defaults to enum name |
message2 | string | No | Secondary language message (Chinese) |
error | Error message | No | Error extension info (only for error codes) |
Note: cn_message (field=3) was deprecated on 2024-05-08, please use message2
From apihug/protobuf/extend/constant.proto:
message Meta {
int32 code = 1;
string message = 2;
string message2 = 4;
Error error = 5;
}
The extension is registered on google.protobuf.EnumValueOptions at field number 37020.
error: {
title: "Error title"; // string
tips: "Handling tips"; // string
http_status: HTTP status enum; // Enum name (NOT_FOUND)
phase: Layer enum; // CONTROLLER/SERVICE/DOMAIN
severity: Severity enum; // LOW/WARN/ERROR/FATAL
}
import "apihug/protobuf/extend/constant.proto";
enum UserError {
USER_NOT_FOUND = 1 [(hope.constant.field) = {
code: 10001,
message: "user_not_found",
message2: "用户不存在"
error: {
title: "User Not Found",
tips: "检查用户ID是否正确",
http_status: NOT_FOUND,
phase: SERVICE,
severity: ERROR
}
}];
}
| Field | Type | Values | Description |
|---|---|---|---|
title | string | - | Error title |
tips | string | - | Handling suggestion |
http_status | HttpStatus enum | NOT_FOUND/BAD_REQUEST/... | HTTP status code (write enum name) |
phase | Phase enum | CONTROLLER/SERVICE/DOMAIN | Error layer |
severity | Severity enum | LOW/WARN/ERROR/FATAL | Severity level |
The HttpStatus enum in constant.proto maps directly to HTTP status codes. The table below is still only a selected reference, but it now includes the common extended 4xx and 5xx values present in source:
4xx Client Errors:
| Enum Value | Code | Description |
|---|---|---|
BAD_REQUEST | 400 | Bad Request |
UNAUTHORIZED | 401 | Unauthorized |
PAYMENT_REQUIRED | 402 | Payment Required |
FORBIDDEN | 403 | Forbidden |
NOT_FOUND | 404 | Not Found |
METHOD_NOT_ALLOWED | 405 | Method Not Allowed |
NOT_ACCEPTABLE | 406 | Not Acceptable |
PROXY_AUTHENTICATION_REQUIRED | 407 | Proxy Authentication Required |
REQUEST_TIMEOUT | 408 | Request Timeout |
CONFLICT | 409 | Conflict |
GONE | 410 | Gone |
PAYLOAD_TOO_LARGE | 413 | Payload Too Large |
UNPROCESSABLE_ENTITY | 422 | Unprocessable Entity |
LOCKED | 423 | Locked |
FAILED_DEPENDENCY | 424 | Failed Dependency |
TOO_MANY_REQUESTS | 429 | Too Many Requests |
5xx Server Errors:
| Enum Value | Code | Description |
|---|---|---|
INTERNAL_SERVER_ERROR | 500 | Internal Server Error |
NOT_IMPLEMENTED | 501 | Not Implemented |
BAD_GATEWAY | 502 | Bad Gateway |
SERVICE_UNAVAILABLE | 503 | Service Unavailable |
GATEWAY_TIMEOUT | 504 | Gateway Timeout |
NETWORK_AUTHENTICATION_REQUIRED | 511 | Network Authentication Required |
Phase (Error.Phase):
| Enum Value | Description |
|---|---|
CONTROLLER | Form/controller layer |
SERVICE | Service layer |
DOMAIN | Domain layer |
Severity (Error.Severity):
| Enum Value | Description |
|---|---|
LOW | No impact |
WARN | Retryable business error |
ERROR | Business cannot proceed |
FATAL | Data corruption / catastrophic |
| Syntax | Type | Wrong Example | Correct Example |
|---|---|---|---|
code | int32 | - | code: 10001 |
message | string | - | message: "user_not_found" |
http_status | enum | http_status: 404 | http_status: NOT_FOUND |
phase | enum | phase: "SERVICE" | phase: SERVICE |
severity | enum | severity: 2 | severity: ERROR |
syntax = "proto3";
package com.example.user;
import "apihug/protobuf/extend/constant.proto";
import "apihug/protobuf/swagger/annotations.proto";
// Authority enum
enum Authority {
option (hope.swagger.enm) = {
title: "Authority enum";
description: "System permissions";
};
USER_CREATE = 0 [(hope.constant.field) = {
code: 1001,
message: "user:create",
message2: "创建用户"
}];
USER_DELETE = 1 [(hope.constant.field) = {
code: 1002,
message: "user:delete",
message2: "删除用户"
}];
}
// Error code enum
enum UserError {
USER_NOT_FOUND = 0 [(hope.constant.field) = {
code: 10001,
message: "user_not_found",
message2: "用户不存在"
error: {
title: "User Not Found",
tips: "检查用户ID是否正确",
http_status: NOT_FOUND,
phase: SERVICE,
severity: ERROR
}
}];
PASSWORD_INVALID = 1 [(hope.constant.field) = {
code: 10002,
message: "password_invalid",
message2: "密码错误"
error: {
title: "Invalid Password",
tips: "密码错误次数过多将锁定账户",
http_status: UNAUTHORIZED,
phase: CONTROLLER,
severity: WARN
}
}];
}
Wrong:
error: {
http_status: 404, // Don't write numbers
phase: "SERVICE", // Don't add quotes
severity: 2 // Don't write sequence numbers
}
Correct:
error: {
http_status: NOT_FOUND, // Enum name
phase: SERVICE,
severity: ERROR
}
Wrong:
enum UserError {
ERROR_1 = 0 [(hope.constant.field) = {code: 10001}];
ERROR_2 = 1 [(hope.constant.field) = {code: 10001}]; // Duplicate code
}
Correct:
enum UserError {
ERROR_1 = 0 [(hope.constant.field) = {code: 10001}];
ERROR_2 = 1 [(hope.constant.field) = {code: 10002}]; // Unique code
}
syntax = "proto3";
package your_package_name;
import "apihug/protobuf/extend/constant.proto";
enum EnumName {
VALUE_NAME = sequence [(hope.constant.field) = {
code: business_code,
message: "English",
message2: "Chinese"
}];
}
enum ErrorEnumName {
ERROR_NAME = sequence [(hope.constant.field) = {
code: error_code,
message: "identifier",
message2: "Chinese description"
error: {
title: "Title",
tips: "Tips",
http_status: HTTP_STATUS,
phase: PHASE,
severity: SEVERITY
}
}];
}