Tip
The feature for generating code based on custom templates and Protobuf is only supported in sponge versions v1.11.0
and above.
Combining custom templates with Protobuf allows for generating code for various custom scenarios. You only need to provide proto files and template directory paths as the main parameters. Multiple proto files can be specified for batch code generation.
Applicable scenarios:
- gRPC service code.
- Test cases for gRPC server and client.
- HTTP service code, such as API, router, service, etc.
Preparation
Before starting, please ensure the following:
- Install sponge.
- Prepare the Protobuf files. If your proto file depends on other proto files, store the dependencies in a separate directory.
Open the terminal and start the sponge UI service:
sponge run
Access the sponge code generation UI at http://localhost:24631 in your browser.
Below is an example of a user.proto
Protobuf file with the following content:
syntax = "proto3";
package api.user.v1;
import "google/api/annotations.proto";
import "validate/validate.proto";
option go_package = "user/api/user/v1;v1";
service User {
rpc Login(LoginRequest) returns (LoginReply) {
option (google.api.http) = {
post: "/api/v1/auth/login"
body: "*"
};
}
}
message LoginRequest {
string email = 1 [(validate.rules).string.email = true];
string password = 2 [(validate.rules).string.min_len = 6];
}
message LoginReply {
uint64 id = 1;
string token = 2;
}
Fixed Fields and Custom Fields
The code generation feature supports two types of fields:
- Fixed Fields
- Custom Fields
Both fixed and custom fields correspond to placeholders in the template code.
Fixed Fields: These fields are automatically parsed from Protobuf files and cannot be modified. For example, fixed fields parsed from a user.proto
file might look like this:
{
"Proto": {
"FileDir": "api/user/v1",
"FileName": "user.proto",
"FileNamePrefix": "user",
"FileNamePrefixCamel": "User",
"GoPackage": "\"user/api/user/v1\"",
"GoPkgName": "userV1",
"ImportPkgMap": {
"userV1": "userV1 \"user/api/user/v1\""
},
"FieldImportPkgMap": {
"userV1": "userV1 \"user/api/user/v1\""
},
"Package": "api.user.v1",
"Services": [
{
"GoPkgName": "userV1",
"Methods": [
{
"Comment": "// Login",
"HTTPRequestBody": "",
"HTTPRequestMethod": "POST",
"HTTPRouter": "/api/v1/auth/login",
"InvokeType": "unary_call",
"IsIgnoreGinBind": false,
"IsPassGinContext": false,
"MethodName": "Login",
"ReplyFields": [
{
"Comment": "",
"FieldType": "uint64",
"GoType": "uint64",
"GoTypeCrossPkg": "uint64",
"ImportPkgName": "",
"ImportPkgPath": "",
"Name": "Id"
}
],
"ReplyImportPkgName": "userV1",
"ReplyName": "LoginReply",
"RequestFields": [
{
"Comment": "",
"FieldType": "string",
"GoType": "string",
"GoTypeCrossPkg": "string",
"ImportPkgName": "",
"ImportPkgPath": "",
"Name": "Email"
}
],
"RequestImportPkgName": "userV1",
"RequestName": "LoginRequest"
}
],
"ServiceName": "User",
"ServiceNameCamel": "User",
"ServiceNameCamelFCL": "user",
"ServiceNamePluralCamel": "Users",
"ServiceNamePluralCamelFCL": "users"
}
]
}
}
Custom Fields: These fields are optional and should be defined in a JSON file only if required by the template. For example, create a file named fields.json
with the following content:
{
"ModuleName": "user",
"PackageName": "service",
"ServerName": "grpc",
"Port": 8282
}
Note
Avoid using Proto
as a field name in custom fields, as it conflicts with the fixed field name.
Create Custom Template Code
Template code is the core of code generation, implemented based on Go's text/template
library. It is recommended to familiarize yourself with its basic syntax rules first, it is simple and can be familiarized in a few minutes. Click here to learn more: Go text/template Basic Syntax Rules.
The template filename should use a variable format (e.g., {{.Proto.FileNamePrefix}}.go.tmpl
) to avoid naming conflicts when processing multiple proto files. Below is an example of a gRPC service template:
package service
import (
"context"
"google.golang.org/grpc"
{{- range $pkgName, $pkgPath := .Proto.ImportPkgMap }}
{{$pkgPath}}
{{- end }}
)
// 注册 gRPC 服务
func Register{{.Proto.FileNamePrefixCamel}}Server(server *grpc.Server) {
{{- range .Proto.Services }}
{{.GoPkgName}}.Register{{.ServiceNameCamel}}Server(server, New{{.ServiceNameCamel}}Server())
{{- end }}
}
{{- range .Proto.Services }}
type {{.ServiceNameCamelFCL}} struct {
{{.GoPkgName}}.Unimplemented{{.ServiceNameCamel}}Server
}
// 创建服务实例
func New{{.ServiceNameCamel}}Server() {{.GoPkgName}}.{{.ServiceNameCamel}}Server {
return &{{.ServiceNameCamelFCL}}{}
}
{{- range .Methods }}
// {{.Comment}}
func (s *{{.ServiceNameCamelFCL}}) {{.MethodName}}(ctx context.Context, req *{{.RequestImportPkgName}}.{{.RequestName}}) (*{{.ReplyImportPkgName}}.{{.ReplyName}}, error) {
return &{{.ReplyImportPkgName}}.{{.ReplyName}}{}, nil
}
{{- end }}
{{- end }}
Store the template files in a directory (e.g., template
), which can contain multiple template files and subdirectories.
Generate Code
Follow these steps in the sponge UI to generate code:
- Access the Interface: Navigate to Generate custom code -> Protobuf in the left menu.
- Fill in Parameters (hover over the
?
icon next to each parameter for more details):- Template Directory Path: e.g.,
/template/grpc/service
- Proto File Path: e.g.,
user.proto
- Dependent Proto File Directory (optional): Specify directories for additional Protobuf imports.
- Custom Fields JSON File (optional): e.g.,
fields.json
.
- Template Directory Path: e.g.,
- Click the Download Code button to generate the code, as shown below.
Interface Example
Below is an example of the UI operation:
Tip
Equivalent command: sponge template protobuf --tpl-dir=/template/grpc/service --proto-file=user.proto --fields=fields.json
Tip
Clicking the Show Info
button allows you to view field information. These fields correspond to the placeholders in the template, making it easier to write template code.