hz client code generation
Introduction
Based on IDL, it generates RPC-like http requests code with a single click, which can block the tedious operation of creating and initializing hertz client and interoperate directly with the server code generated by hz.
Generated code examples can be found at code .
Usage
$ hz client -h
NAME:
hz client - Generate hertz client based on IDL
USAGE:
hz client [command options] [arguments...]
OPTIONS:
--idl value [ --idl value ] Specify the IDL file path. (.thrift or .proto)
--module value, --mod value Specify the Go module name.
--base_domain value Specify the request domain.
--model_dir value Specify the model relative path (based on "out_dir").
--client_dir value Specify the client path. If not specified, IDL generated path is used for 'client' command; no client code is generated for 'new' command
--use value Specify the model package to import for handler.
--force_client_dir value Specify the client path, and won't use namespaces as subpaths
--proto_path value, -I value [ --proto_path value, -I value ] Add an IDL search path for includes. (Valid only if idl is protobuf)
--thriftgo value, -t value [ --thriftgo value, -t value ] Specify arguments for the thriftgo. ({flag}={value})
--protoc value, -p value [ --protoc value, -p value ] Specify arguments for the protoc. ({flag}={value})
--no_recurse Generate master model only. (default: false)
--enable_extends Parse 'extends' for thrift IDL (default: false)
--json_enumstr Use string instead of num for json enums when idl is thrift. (default: false)
--unset_omitempty Remove 'omitempty' tag for generated struct. (default: false)
--pb_camel_json_tag Convert Name style for json tag to camel(Only works protobuf). (default: false)
--snake_tag Use snake_case style naming for tags. (Only works for 'form', 'query', 'json') (default: false)
--exclude_file value, -E value [ --exclude_file value, -E value ] Specify the files that do not need to be updated.
--customize_package value Specify the path for package template.
--protoc-plugins value [ --protoc-plugins value ] Specify plugins for the protoc. ({plugin_name}:{options}:{out_dir})
--thrift-plugins value [ --thrift-plugins value ] Specify plugins for the thriftgo. ({plugin_name}:{options})
--help, -h show help (default: false)
When generating code, simply use the following five options:
- idl: Specify the idl path
- module: Specify the go module of the project, if not specified, it defaults to the path relative to the “go path”.
- model_dir: Specify the path to the model generated by the project, default is “biz/model”
- client_dir: Specify the path to generate the client stub code, default is “biz/model/{Namespace}”
- base_domain: Specify the domain to be accessed, it can be domain name, IP:PORT, service name (with service discovery), or can be declared in IDL by annotation
hz client --idl=../idl/psm.thrift --model_dir=hertz_gen -t=template=slim --client_dir=hz_client
Example
Generate client based on thrift IDL
Define IDL
The definition and semantics of the IDL are exactly the same as the current definition, so it is basically possible to generate client code without modifying the original IDL But for the client scenario, two annotations have been added api.file_name: Specify the file api.base_domain: specifies the default request domain to access
namespace go toutiao.middleware.hertz_client
struct FormReq {
1: string FormValue (api.form="form1"); // form annotation is used to declare the form parameter ("multipart/form-data")
2: string FileValue (api.file_name="file1"); // file_name is used to declare the key of the file to be uploaded, its actual value is the file name
}
struct QueryReq {
1: string QueryValue (api.query="query1"); // query annotation is used to declare the query parameters of the request
}
struct PathReq {
1: string PathValue (api.path="path1"); // path annotation is used to declare the routing parameters in the url
}
struct BodyReq {
1: string BodyValue (api.body="body"); // body annotation sets the entire structure to the body as a json, regardless of whether it is declared or not.
2: string QueryValue (api.query="query2");
}
struct Resp {
1: string Resp;
}
service HelloService {
// api.post is used to declare the route of the request
Resp FormMethod(1: FormReq request) (api.post="/form", api.handler_path="post");
Resp QueryMethod(1: QueryReq request) (api.get="/query", api.handler_path="get");
Resp PathMethod(1: PathReq request) (api.post="/path:path1", api.handler_path="post");
Resp BodyMethod(1: BodyReq request) (api.post="/body", api.handler_path="post");
}(
// api.base_domain is used to specify the default domain for client requests
api.base_domain="http://127.0.0.1:8888";
)
Generate client code
hz client --mod=a/b/c --idl=../idl/psm.thrift --model_dir=model --client_dir=hertz_client -t=template=slim
Advanced Settings
Request-level configuration
Take the code generated by thrift IDL as an example
func main() {
generatedClient, err := hello_service.NewHelloServiceClient(
"http://toutiao.hertz.testa",
)
// The request level configuration can be specified when the call is initiated
resp, rawResp, err := generatedClient.QueryMethod(
context.Background(),
QueryReq,
config.WithSD(true), // Specify the request level setting to enable service discovery
config.WithReadTimeout(), // Specify the request read timeout
)
if err != nil {
fmt.Println(err)
return
}
}
Set client middleware
Take the code generated by thrift IDL as an example
func main() {
generatedClient, err := hello_service.NewHelloServiceClient(
"http://toutiao.hertz.testa",
hello_service.WithHertzClientMiddleware(), // Specify the client's middleware
)
}
Set global header
Take the code generated by thrift IDL as an example
There are some generic header that may need to be carried in every request, or some header that cannot be defined in IDL, then we can inject these header with “WithHeader” so that every request sent will carry these header.
func main() {
generatedClient, err := hello_service.NewHelloServiceClient(
"http://toutiao.hertz.testa",
hello_service.WithHeader(), // Specify the header that needs to be carried for each request sent
)
}
Configure TLS
Take the code generated by thrift IDL as an example
Hertz client’s TLS goes through the standard network library, so you need to configure it for the standard network library when using the generated one-click calls
func main() {
generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"),
hello_service.WithHertzClientOption(
client.WithDialer(standard.NewDialer()), // Use of standard libraries
client.WithTLSConfig(clientCfg), // TLS Configuration
),
)
}