Spec

API Directive Specification

API Interface Extension User Manual — map protobuf service rpc to HTTP RESTful API and generate OpenAPI/Swagger documentation.

Map protobuf service rpc to HTTP RESTful API and generate OpenAPI/Swagger documentation.

  • Extension Package: apihug/protobuf/swagger/swagger.proto
  • Scope: Service/Method(rpc)/Message/Field
  • Scenarios: HTTP API, OpenAPI documentation, frontend-backend coordination

Forbidden Rules

1. Forbid file-level option

NEVER add any file-level option declarations in proto files:

Proto
// 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.

2. Forbid cross-layer reference

API layer (api/) must not reference Domain entities:

Proto
// Forbidden to reference domain layer entities
import "com/example/domain/entities/user.proto";  // Wrong!

message CreateUserRequest {
  UserEntity user = 1;  // Wrong!
}

Correct approach:

Proto
// Allow referencing constant layer (infra/)
import "com/example/infra/settings/user_constant.proto";
// Allow referencing other API messages
import "com/example/api/common/response.proto";

message CreateUserRequest {
  string user_name = 1;  // Use basic types
  UserStatusEnum status = 2;  // Enums can be shared
  CommonResponse response = 3;  // API internal reference
}

1. Import and Syntax

1.1 Import

Proto
import "apihug/protobuf/swagger/annotations.proto";

Optional import (only when Mock data is needed):

Proto
import "apihug/protobuf/mock/mock.proto";

1.2 Four-layer Extension Points

From apihug/protobuf/swagger/annotations.proto:

Levelproto ElementExtension PointExtension #Function
Serviceservice(hope.swagger.svc)1044Define service base path, description
Methodrpc(hope.swagger.operation)1042Define HTTP method, path, permissions
Messagemessage(hope.swagger.schema)1042Define request/response description
Fieldfield(hope.swagger.field)1042Define field constraints, examples
Enumenum(hope.swagger.enm)1042Enum title and description

2. Service-level Extension

2.1 ServiceSchema Syntax

Proto
service ServiceName {
  option (hope.swagger.svc) = {
    path: "/base_path";
    description: "Service description";
  };
}

2.2 Real Case

Proto
syntax = "proto3";
package com.example.pet.service;

import "apihug/protobuf/swagger/annotations.proto";

service PetService {
  option (hope.swagger.svc) = {
    path: "/pet";
    description: "Pet Manager service";
  };

  rpc GetPet (...) returns (...) {
    // Method definition...
  }
}

2.3 Field Description

path (string)

Base path prefix for the service. Use resource names (/user, /order, /pet).

description (string)

Business description of the service.


3. Operation-level Extension (Core)

3.1 HTTP Methods and Paths

Proto
rpc MethodName (RequestType) returns (ResponseType) {
  option (hope.swagger.operation) = {
    post: "/path";  // or get/put/patch/delete
    description: "Method description";
  };
}
MethodUse CaseExample Path
getQuery resourcesget: "/users"
postCreate resources, complex queriespost: "/users"
putFull update resourcesput: "/users/{id}"
patchPartial update resourcespatch: "/users/{id}"
deleteDelete resourcesdelete: "/users/{id}"

Path Variables

Proto
option (hope.swagger.operation) = {
  get: "/pet/{id}";
};

3.2 Real Case Collection

Case 1: File Upload (multipart/form-data)

Proto
rpc UploadMeta (OpenApiMetaUploadRequest) returns (google.protobuf.Empty) {
  option (hope.swagger.operation) = {
    post: "/upload-meta";
    description: "Open platform upload API metadata";
    tags: "open";
    group: TENANT;
    authorization: {
      low_limit_risky_mode: ANONYMOUS
    };
    priority: HIGH;
    consumes: "multipart/form-data";
  };
}

Case 2: Paginated Query

Proto
rpc ReturnPageable (Customer) returns (Pet) {
  option (hope.swagger.operation) = {
    post: "/batch-user-pet";
    pageable: true;
    description: "Return pageable data based on request";
    tags: "user";
    tags: "pet";
    request_name: "pet";
  };
}

Case 3: Path Parameters + Query Parameters

Proto
rpc UpdateByPath (google.protobuf.Empty) returns (google.protobuf.Empty) {
  option (hope.swagger.operation) = {
    post: "/update-by-path/{user-id}/try-more/{user-name}";
    description: "Test two path parameters";
    tags: "other";
    parameters: {
      parameter: {
        name: "user-id";
        in: PATH;
        schema: {
          format: INTEGER;
          maximum: 12345
        };
      };
      parameter: {
        name: "user-name";
        in: PATH;
        schema: {
          format: STRING;
          empty: false;
          pattern: "^[A-Za-z0-9+_.-]+@(.+)$";
          max_length: 64
        };
      }
    }
  };
}

Case 4: With Permission Validation

Proto
rpc PlaceOrder (google.protobuf.Empty) returns (PlaceOrderRequest) {
  option (hope.swagger.operation) = {
    post: "/place-order";
    description: "Place order operation";
    summary: "Place order detailed operation";
    tags: "user";
    tags: "pet";
    security: {
      security_requirement: {
        key: "jwt";
        value: {
          scope: "pet:read";
          scope: "pet:write";
        };
      }
    }
  };
}

4. Operation Field Details

4.1 Basic Description

FieldTypeDescription
descriptionstringInterface functionality description
summarystringBrief summary (under 120 chars)
tagsrepeated stringInterface grouping tags
operation_idstringUnique identifier for code generation

4.2 Request and Response Configuration

request_name (string)

Request body parameter name.

pageable (optional bool)

Enable paginated query. Request auto-adds page, size, sort; response wrapped as Page<T>.

input_repeated / output_repeated (optional bool)

Mark request/response as list.

Deprecated: Use input_repeated instead of input_plural; use output_repeated instead of out_plural.

raw (optional bool)

Do not wrap response (return raw type directly).

session (optional bool)

Pass HttpSession through to the generated Java controller when the endpoint needs servlet-session access.

request_schema / response_schema

Use these to attach swagger-specific JSON-schema metadata directly at the operation level when request or response payload documentation needs to be more explicit than the raw message type alone.

Proto
option (hope.swagger.operation) = {
  post: "/register";
  request_schema: {
    title: "RegisterPayload";
    description: "Validated registration body";
  };
};

body_empty (bool)

Allow response body to be empty.

body_empty, response_schema, and operation-level mock are mutually exclusive response customization paths in the source oneof ResponseCustomized.

4.3 Media Types

consumes / produces (repeated string)

Content-Type accepted/returned by the interface.

response_media_type (MediaType enum)

Selected common values (from Operation.MediaType in swagger.proto):

Enum ValueMIME TypeUse Case
APPLICATION_JSONapplication/jsonJSON response (default)
TEXT_PLAINtext/plainPlain text
TEXT_HTMLtext/htmlHTML page
APPLICATION_PDFapplication/pdfPDF file
APPLICATION_ZIPapplication/zipZip archive
APPLICATION_VND_OPEN_XML_FORMATS_XLSXapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetExcel
IMAGE_PNGimage/pngPNG image
MULTIPART_FORM_DATAmultipart/form-dataFile upload
APPLICATION_OCTET_STREAMapplication/octet-streamBinary download
TEXT_CSVtext/csvCSV data
APPLICATION_XMLapplication/xmlXML data
Proto
response_media_type: APPLICATION_PDF;

The source enum is broader than this quick table and also includes office formats, YAML, audio, video, and additional multipart variants.

4.4 Parameter Definition

parameters (Parameters message)

Mandatory rules: All path/query/header/cookie/session parameters must be declared.

FieldTypeDescription
namestringParameter name
inIN enumLocation
schemaJSONSchemaParameter constraints
is_repeatedboolMark the parameter as an array/list

plural still exists in source as a deprecated compatibility field. Prefer is_repeated.

For Java controller generation, session: true is a separate operation-level flag. It indicates servlet-session access and should not be confused with declaring a SESSION parameter in the OpenAPI parameter list.

IN Enum Values:

Enum ValueMeaning
QUERYQuery parameter (?key=value)
PATHPath parameter (/{id})
HEADERHTTP header
COOKIECookie
SESSIONSession
Proto
parameters: {
  parameter: {
    name: "user-id";
    in: QUERY;
    is_repeated: true;
    schema: {
      format: INTEGER;
      description: "user id";
    }
  };
}

4.5 Permission Control

authorization (Authorization message)

Method 1: Low-level risk mode

Proto
authorization: {
  low_limit_risky_mode: ANONYMOUS  // or LOGIN / ACTIVE
}
Enum ValueMeaning
ANONYMOUSNo login required
LOGINLogin required
ACTIVELogin required and account activated

Method 2: RBAC

Proto
authorization: {
  rbac: {
    roles: {
      roles: ["ROLE_ADMIN", "ROLE_USER"]
    };
    authorities: ["USER_CREATE", "USER_DELETE"];
    combinator: AND;  // or OR
  }
}

Method 3: SpEL Expression

Proto
authorization: {
  expression: "hasRole('ADMIN') and #userId == authentication.principal.id"
}

group (Group enum)

Enum ValueMeaning
CUSTOMERUser-side (C-side)
TENANTTenant management side (B-side)
PLATFORMPlatform operation side

4.6 Priority and Visibility

priority (Priority enum, from source)

Enum ValueValueMeaning
NA0Not set
LOW1Low priority
MIDDLE4Medium (team lead approval)
HIGH8High (project manager approval)
CRITICAL16Critical (VP approval)
FATAL32May affect business (CTO approval)

internal / hide / deprecated (bool)

Mark as internal, hidden from docs, or deprecated.

multipart / multiple

  • multipart: current flag for multipart request handling
  • multiple: deprecated compatibility alias retained in the source proto

Prefer multipart.

4.7 AI-friendly Fields

questions (repeated string)

Natural language questions for LLM understanding:

Proto
questions: [
  "How to get user order list?",
  "Query the most recent page of order data"
];

5. Message-level Extension

5.1 Schema Syntax

Proto
message MessageName {
  option (hope.swagger.schema) = {
    json_schema: {
      title: "Object title";
      description: "Object description";
    };
  };
}

5.2 Real Case

Proto
message PlaceOrderRequest {
  option (hope.swagger.schema) = {
    json_schema: {
      title: "PlaceOrder";
      description: "Place order request";
    };
    external_docs: {
      url: "https://example.com/order-design";
      description: "Order design detailed information"
    }
  };

  uint64 id = 1 [(hope.swagger.field) = {
    description: "Request ID";
    empty: false;
    maximum: 12345;
    example: "1111";
  }];
}

6. Field-level Extension (JSONSchema)

6.1 Basic Fields

FieldTypeDescription
descriptionstringField description
examplestringExample value
titlestringField title
defaultstringDefault value

6.2 Empty Value Control (choose one — oneof EmptyConstraint)

FieldApplicableFunction
empty (bool)All typesNot null/empty string/collection size > 0
blank (bool)String onlyCannot be blank (no spaces)
nullable (bool)Non-stringCannot be null

Selection:

Code
String → empty: false
String (no spaces) → blank: false
Number/Date → nullable: false
Collection → empty: false

6.3 Length Constraints

Proto
max_length: 100;    // uint64
min_length: 1;
max_items: 50;      // collection element count
min_items: 1;
max_properties: 20; // object property count
min_properties: 1;

6.4 Numeric Constraints

Proto
maximum: 12345;     // double
minimum: 1;
exclusive_maximum: true;  // open interval
exclusive_minimum: true;
multiple_of: 10;          // must be multiple

6.5 Pattern and Enum

Proto
pattern: "^[A-Za-z0-9+_.-]+@(.+)$";  // regex
enum: ["PENDING", "APPROVED", "REJECTED"];

6.6 Format Specification (format — JSONSchemaFormat enum)

Enum ValueTypeUse Case
STRINGstringString
INTEGERint32Integer
LONGint64Long integer
DOUBLEdoubleFloat
BOOLEANboolBoolean
DATELocalDateDate
DATE_TIMELocalDateTimeDateTime
TIMELocalTimeTime
UUIDUUIDUUID string
EMAILstringEmail
PASSWORDstringPassword
BINARYbytesBinary data

field_configuration.path_param_name

Use field_configuration.path_param_name when a field is used in a path template and the generated placeholder name should be overridden explicitly.

Proto
string owner_id = 1 [(hope.swagger.field) = {
  field_configuration: {
    path_param_name: "owner-id";
  };
}];

6.7 Date and Time Constraints

time_constraint_type (TimeConstraintType enum)

Enum ValueMeaningJakarta Annotation
NANo restriction-
FUTUREMust be future@Future
FUTURE_OR_PRESENTFuture or present@FutureOrPresent
PASTMust be past@Past
PAST_OR_PRESENTPast or present@PastOrPresent

date_format (DateFormat enum)

Enum ValueFormatExample
BASIC_ISO_DATEyyyyMMdd20231225
ISO_LOCAL_DATEyyyy-MM-dd2023-12-25
ISO_TIMEHH:mm:ss.SSSSSSS10:15:30.123
ISO_LOCAL_TIMEHH:mm:ss10:15:30
YYYY_MM_DD_HH_MM_SSyyyy-MM-dd HH:mm:ss2023-12-25 10:15:30
YYYY_MM_DD_HH_MM_SS_SSSyyyy-MM-dd HH:mm:ss:SSS2023-12-25 10:15:30:123

Custom format: customized_date_format: "yyyy/MM/dd";

6.8 Advanced Validation

Proto
email: true;                // email validation
assert: true;               // must be true/false
digits_integer: 3;          // integer part digits
digits_fraction: 2;         // decimal part digits
decimal_max: "999.99";      // string form
decimal_min: "0.01";

7. Mock Data Configuration

Mock data is configured via the mock field inside hope.swagger.field. See the Mock Data Specification for full details.

7.1 Field-level Mock

Proto
string phone = 1 [(hope.swagger.field) = {
  description: "Phone number";
  mock: {
    nature: CN_PHONE
  };
}];

7.2 Operation-level Mock

Proto
option (hope.swagger.operation) = {
  post: "/ping";
  mock: {
    nature: GUID
  };
};

7.3 Quick Mock Reference

Use CaseMock Config
Emailmock: { nature: EMAIL }
Phonemock: { nature: CN_PHONE }
UUIDmock: { nature: GUID }
Namemock: { nature: NAME }
Enum valuesmock: { string_rule: { candidates: ["A", "B"] } }
Pricemock: { number_rule: { min: 1; max: 9999; max_fraction: 2 } }

8. Key Type Identification

8.1 bool vs string

Wrong:

Proto
empty: "false"  // String, wrong!
nullable: "true"
is_repeated: "false"

Correct:

Proto
empty: false  // bool type
nullable: true
is_repeated: false

8.2 uint32/uint64/int64/double vs wrapper types

Wrong (old syntax):

Proto
length: {value: 32}  // Old syntax!
max_length: {value: 100}
maximum: {value: 12345}

Correct:

Proto
length: 32  // uint32
max_length: 100  // uint64
maximum: 12345  // double

8.3 optional bool vs bool

optional bool for three-state boolean (not set/true/false):

Proto
optional bool pageable = 51;
optional bool raw = 52;
  • bool: Default false (two-state)
  • optional bool: Can be not set (three-state)

9. Complete Examples

9.1 Complete Service Example

Proto
syntax = "proto3";
package com.example.pet.service;

import "com/example/pet/bean/request.proto";
import "swagger/annotations.proto";
import "google/protobuf/empty.proto";

service PetService {
  option (hope.swagger.svc) = {
    path: "/pet";
    description: "Pet management service";
  };

  rpc UploadFile (UploadRequest) returns (google.protobuf.Empty) {
    option (hope.swagger.operation) = {
      post: "/upload";
      description: "Upload pet photo";
      tags: "pet";
      consumes: "multipart/form-data";
      multipart: true;
      authorization: {
        low_limit_risky_mode: LOGIN
      };
    };
  };

  rpc ListPets (PetQueryRequest) returns (Pet) {
    option (hope.swagger.operation) = {
      post: "/list";
      description: "Paginated query pet list";
      tags: "pet";
      pageable: true;
      authorization: {
        rbac: {
          authorities: ["PET_VIEW"];
        }
      };
    };
  };

  rpc GetPetById (google.protobuf.Empty) returns (Pet) {
    option (hope.swagger.operation) = {
      get: "/pets/{id}";
      description: "Get pet details by ID";
      tags: "pet";
      parameters: {
        parameter: {
          name: "id";
          in: PATH;
          schema: {
            format: LONG;
            minimum: 1;
          };
        }
      };
      authorization: {
        low_limit_risky_mode: ANONYMOUS
      };
    };
  };

  rpc DeletePet (google.protobuf.Empty) returns (google.protobuf.Empty) {
    option (hope.swagger.operation) = {
      delete: "/pets/{id}";
      description: "Delete pet";
      tags: "pet";
      priority: HIGH;
      parameters: {
        parameter: {
          name: "id";
          in: PATH;
          schema: {
            format: LONG;
          };
        }
      };
      authorization: {
        rbac: {
          roles: {roles: ["ROLE_ADMIN"]};
          authorities: ["PET_DELETE"];
          combinator: AND;
        }
      };
    };
  };
}

9.2 Complete Message Example

Proto
syntax = "proto3";
package com.example.pet.bean;

import "swagger/annotations.proto";
import "com/example/pet/enumeration/constants.proto";

message PlaceOrderRequest {
  option (hope.swagger.schema) = {
    json_schema: {
      title: "PlaceOrderRequest";
      description: "Place order request object";
    };
  };

  uint64 id = 1 [(hope.swagger.field) = {
    description: "Request ID";
    empty: false;
    maximum: 12345;
    example: "1111";
  }];

  uint64 pet_id = 2 [(hope.swagger.field) = {
    description: "Pet ID";
    empty: false;
    minimum: 1;
    maximum: 999999;
    example: "1985";
  }];

  uint32 quantity = 3 [(hope.swagger.field) = {
    description: "Purchase quantity";
    empty: false;
    minimum: 1;
    maximum: 100;
    example: "5";
  }];

  com.example.pet.enumeration.OrderStatus order_status = 4 [(hope.swagger.field) = {
    description: "Order status";
  }];

  string ship_date = 5 [(hope.swagger.field) = {
    description: "Shipping date";
    example: "2023-12-25";
    date_format: ISO_LOCAL_DATE;
    time_constraint_type: FUTURE;
    empty: false;
  }];

  bool complete = 6 [(hope.swagger.field) = {
    description: "Is completed";
    example: "false";
  }];

  string phone = 7 [(hope.swagger.field) = {
    description: "Contact phone";
    example: "13800138000";
    pattern: "^1[3-9]\\d{9}$";
    mock: {nature: CN_PHONE};
  }];

  string email = 8 [(hope.swagger.field) = {
    description: "Contact email";
    email: true;
    empty: false;
    mock: {nature: EMAIL};
  }];

  string remark = 9 [(hope.swagger.field) = {
    description: "Remark";
    max_length: 500;
    mock: {
      chinese_rule: {
        type: SENTENCE;
        max: 50;
      }
    };
  }];
}

10. Common Errors

10.1 Type Confusion

Wrong:

Proto
empty: "false"  // String
max_length: {value: 100}  // Old syntax
pageable: "false"  // String

Correct:

Proto
empty: false  // bool type
max_length: 100  // uint64 type
pageable: true  // optional bool

10.2 oneof Conflict

Wrong: empty: false; blank: false; (both set!) Correct: Set only one: empty: false;

10.3 Deprecated Fields

Wrong: input_plural: true; / out_plural: true; Correct: input_repeated: true; / output_repeated: true;


11. Best Practices

11.1 HTTP Method Selection

Code
Query single resource -> GET /resources/{id}
Query list -> GET /resources or POST /resources/search
Create resource -> POST /resources
Full update -> PUT /resources/{id}
Partial update -> PATCH /resources/{id}
Delete resource -> DELETE /resources/{id}

11.2 Path Design

Code
Resource collection -> /pets
Specific resource -> /pets/{id}
Sub-resource -> /pets/{id}/photos
Action -> /pets/{id}/activate
Complex query -> POST /pets/search

11.3 Permission Design

Code
Public interface -> low_limit_risky_mode: ANONYMOUS
Login required -> low_limit_risky_mode: LOGIN
Role required -> rbac.roles
Permission required -> rbac.authorities
Complex rules -> rbac.combinator: AND

12. Quick Reference

Service Template

Proto
service ServiceName {
  option (hope.swagger.svc) = {
    path: "/path";
    description: "Description";
  };

  rpc MethodName (...) returns (...) {
    option (hope.swagger.operation) = {
      post: "/path";
      description: "Description";
    };
  }
}

Operation Template

Proto
option (hope.swagger.operation) = {
  post: "/path";
  description: "Description";
  tags: "tag";
  authorization: {
    low_limit_risky_mode: LOGIN
  };
};

Field Template

Proto
string field_name = sequence [(hope.swagger.field) = {
  description: "Description";
  example: "Example";
  empty: false;
}];
Copyright © 2026 ApiHug·AI-native Enterprise Architecture Factory