README
¶
protoc-gen-ginx
protoc-gen-ginx is a protoc plugin that generates HTTP server code from .proto files. It is designed to inspect
service definitions within your protobuf files and automatically generate corresponding HTTP handlers based on Google
API annotations and a specified template. Inspired
by protoc-gen-go-http.
Installation
To install protoc-gen-ginx, use the following command:
go install github.com/go-sphere/protoc-gen-ginx@latest
Flags
The behavior of protoc-gen-ginx can be customized with the following parameters:
version: Print the current plugin version and exit. (Default:false)omitempty: Omit file generation ifgoogle.api.httpoptions are not found. (Default:true)omitempty_prefix: A file path prefix. If set,omitemptywill only apply to files with this prefix. (Default:"")template_file: Path to a custom Go template file. If not provided, the default internal template is used.swagger_auth_header: The comment for the authorization header in generated Swagger documentation. (Default:// @Param Authorization header string false "Bearer token")router_type: The fully qualified Go type for the router (e.g.,github.com/gin-gonic/gin;IRouter). (Default:github.com/gin-gonic/gin;IRouter)context_type: The fully qualified Go type for the request context (e.g.,github.com/gin-gonic/gin;Context). (Default:github.com/gin-gonic/gin;Context)data_resp_type: The fully qualified Go type for the data response model, which must support generics. (Default:github.com/go-sphere/sphere/server/ginx;DataResponse)error_resp_type: The fully qualified Go type for the error response model. (Default:github.com/go-sphere/sphere/server/ginx;ErrorResponse)server_handler_func: The wrapper function for handling server responses. (Default:github.com/go-sphere/sphere/server/ginx;WithJson)parse_header_func: The function used to parse header parameters. (Default:github.com/go-sphere/sphere/server/ginx;ShouldBindHeader)parse_json_func: The function used to parse JSON request bodies. (Default:github.com/go-sphere/sphere/server/ginx;ShouldBindJSON)parse_uri_func: The function used to parse URI parameters. (Default:github.com/go-sphere/sphere/server/ginx;ShouldBindUri)parse_form_func: The function used to parse form data/query parameters. (Default:github.com/go-sphere/sphere/server/ginx;ShouldBindQuery)
Usage with Buf
To use protoc-gen-ginx with buf, you can configure it in your buf.gen.yaml file. Here is an example configuration:
version: v2
managed:
enabled: true
disable:
- file_option: go_package_prefix
module: buf.build/googleapis/googleapis
- file_option: go_package_prefix
module: buf.build/bufbuild/protovalidate
override:
- file_option: go_package_prefix
value: github.com/go-sphere/sphere-layout/api
plugins:
- local: protoc-gen-ginx
out: api
opt:
- paths=source_relative
- swagger_auth_header=// @Security ApiKeyAuth
Prerequisites
You need to have the following dependencies in your project. Add them to your buf.yaml:
deps:
- buf.build/googleapis/googleapis
- buf.build/bufbuild/protovalidate
- buf.build/go-sphere/binding
Proto Definition Example
Here's how to define services with HTTP annotations in your .proto files:
syntax = "proto3";
package shared.v1;
import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "sphere/binding/binding.proto";
service TestService {
rpc RunTest(RunTestRequest) returns (RunTestResponse) {
option (google.api.http) = {
post: "/api/test/{path_test1}/second/{path_test2}"
body: "*"
};
}
// test comment line1
// test comment line2
// test comment line3
rpc BodyPathTest(BodyPathTestRequest) returns (BodyPathTestResponse) {
option (google.api.http) = {
post: "/api/test/body_path_test"
body: "request"
response_body: "response"
};
}
}
message RunTestRequest {
string field_test1 = 1;
int64 field_test2 = 2;
string path_test1 = 3 [(sphere.binding.location) = BINDING_LOCATION_URI];
int64 path_test2 = 4 [(sphere.binding.location) = BINDING_LOCATION_URI];
string query_test1 = 5 [
(buf.validate.field).required = true,
(sphere.binding.location) = BINDING_LOCATION_QUERY
];
int64 query_test2 = 6 [(sphere.binding.location) = BINDING_LOCATION_QUERY];
}
message RunTestResponse {
string field_test1 = 1;
int64 field_test2 = 2;
string path_test1 = 3;
int64 path_test2 = 4;
string query_test1 = 5;
int64 query_test2 = 6;
}
Generated Code
The plugin generates Go code with HTTP handlers, route registration, and Swagger documentation. Here's what gets generated:
HTTP Handler Functions
// @Summary RunTest
// @Tags shared.v1,shared.v1.TestService
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param path_test1 path string true "path_test1"
// @Param path_test2 path integer true "path_test2"
// @Param query_test1 query string true "query_test1"
// @Param query_test2 query integer false "query_test2"
// @Param request body RunTestRequest true "request body"
// @Success 200 {object} ginx.DataResponse[RunTestResponse]
// @Failure 400,401,403,500,default {object} ginx.ErrorResponse
// @Router /api/test/{path_test1}/second/{path_test2} [post]
func _TestService_RunTest0_HTTP_Handler(srv TestServiceHTTPServer) func(ctx *gin.Context) {
return ginx.WithJson(func(ctx *gin.Context) (*RunTestResponse, error) {
var in RunTestRequest
if err := ginx.ShouldBindJSON(ctx, &in); err != nil {
return nil, err
}
if err := ginx.ShouldBindQuery(ctx, &in); err != nil {
return nil, err
}
if err := ginx.ShouldBindUri(ctx, &in); err != nil {
return nil, err
}
if err := protovalidate.Validate(&in); err != nil {
return nil, err
}
out, err := srv.RunTest(ctx, &in)
if err != nil {
return nil, err
}
return out, nil
})
}
Service Interface
type TestServiceHTTPServer interface {
// BodyPathTest test comment line1
// test comment line2
// test comment line3
BodyPathTest(context.Context, *BodyPathTestRequest) (*BodyPathTestResponse, error)
RunTest(context.Context, *RunTestRequest) (*RunTestResponse, error)
}
Route Registration
func RegisterTestServiceHTTPServer(route gin.IRouter, srv TestServiceHTTPServer) {
r := route.Group("/")
r.POST("/api/test/:path_test1/second/:path_test2", _TestService_RunTest0_HTTP_Handler(srv))
r.POST("/api/test/body_path_test", _TestService_BodyPathTest0_HTTP_Handler(srv))
}
Constants and Endpoints
const OperationTestServiceRunTest = "/shared.v1.TestService/RunTest"
const OperationTestServiceBodyPathTest = "/shared.v1.TestService/BodyPathTest"
var EndpointsTestService = [...][3]string{
{OperationTestServiceRunTest, "POST", "/api/test/:path_test1/second/:path_test2"},
{OperationTestServiceBodyPathTest, "POST", "/api/test/body_path_test"},
}
Usage in Code
Implementing the Service
type testService struct {
// your dependencies
}
func (s *testService) RunTest(ctx context.Context, req *sharedv1.RunTestRequest) (*sharedv1.RunTestResponse, error) {
// your business logic
return &sharedv1.RunTestResponse{
FieldTest1: req.FieldTest1,
FieldTest2: req.FieldTest2,
PathTest1: req.PathTest1,
PathTest2: req.PathTest2,
QueryTest1: req.QueryTest1,
QueryTest2: req.QueryTest2,
}, nil
}
func (s *testService) BodyPathTest(ctx context.Context, req *sharedv1.BodyPathTestRequest) (*sharedv1.BodyPathTestResponse, error) {
// your business logic
return &sharedv1.BodyPathTestResponse{
Response: []*sharedv1.BodyPathTestResponse_Response{
{
FieldTest1: req.Request.FieldTest1,
FieldTest2: req.Request.FieldTest2,
},
},
}, nil
}
Registering Routes
func main() {
r := gin.New()
srv := &testService{}
sharedv1.RegisterTestServiceHTTPServer(r, srv)
r.Run(":8080")
}
Features
- Automatic HTTP Handler Generation: Creates Gin handlers from protobuf service definitions
- Request Binding: Automatically binds JSON body, query parameters, and URI parameters
- Validation Integration: Integrates with
protovalidatefor request validation - Swagger Documentation: Generates Swagger/OpenAPI comments for each endpoint
- Response Body Customization: Supports custom response body fields via
response_bodyoption - Flexible Binding: Works with sphere binding annotations for fine-grained control
- Error Handling: Integrates with sphere error handling framework
- Route Constants: Generates operation constants and endpoint arrays for easy reference
HTTP Annotations Support
The plugin supports the following Google API HTTP annotations:
get,post,put,patch,delete: HTTP methodsbody: Specifies the request body field (*for entire message)response_body: Specifies the response body field- Path parameters:
{field_name}in the URL path - Additional bindings: Multiple HTTP rules for the same RPC
Binding Locations
Fields can be bound to different parts of the HTTP request using sphere binding annotations:
BINDING_LOCATION_BODY: JSON request body (default)BINDING_LOCATION_QUERY: Query parametersBINDING_LOCATION_URI: Path parametersBINDING_LOCATION_HEADER: HTTP headers
Customization Options
All the configuration flags allow you to customize the generated code to work with different frameworks and response types. The default configuration is optimized for the sphere framework with Gin router.
Documentation
¶
There is no documentation for this package.