Custom Scaffold Template

Kitex provides the ability to customize templates, if the default templates can not meet your needs, you can use the function of this custom template provided by Kitex. Now, it supports rendering single file and circular rendering according to methodInfo.

How to Use

  1. The data used by the template is PackageInfo and we assume that this section contains all the metadata(e.g. methodInfo …). You only need to pass the template file, and the data in the template is PackageInfo data.

  2. Template rendering can only render a single file at a time. If there is a situation of sorting the file by methods and rendering it, you need to control them in your code.

  3. Templates are passed via the YAML folder and specified with the --template-dir command-line parameter. To avoid large files, templates are now organized into a dedicated directory.

  4. extensions.yaml in the YAML folder is a specific file. The content of this configuration file is extending the service code. If it exists, there is no need to pass the ‘template-extension’ parameter.

  5. There are currently four update options available: overwrite, skip, append or add files based on specified methods (loop_method is true). The behavior is determined by the key field in update_behavior, which can be skip, cover or append. When loop_method is enabled, append adds new files; otherwise, it appends to the end of the file, and the specified key during the update determines the behavior.

  6. The code generated by Kitex is divided into two parts, ‘kitex_gen’ and ‘mainPkg’ (including ‘main.go’, ‘handler.go’ …). ‘kitex_gen’ is immutable. Choosing between ‘mainPkg’ and ‘custom layout’ is a binary decision; specifying a ‘custom layout’ will prevent the generation of ‘mainPkg’.

Usage Scenarios

The default templates can not meet your needs. (e.g. want to generate ‘MVC Layout’,uniform error handling …)

Practice

kitex -module ${module_name} -template-dir ${template dir_path} idl/hello.thrift

YAML File

path: /a/main.go # specifies the path and name to the file. It will create the 'a' folder and 'main.go' file in the 'a' folder
update_behavior:
    type: skip / cover / append # specifies the update behavior, if 'loop_methor' is true, append is not supported.the default value is skip
    key: Test{{.Name}} # function name
    append_tpl: # the new tpl
    import_tpl: # the new import, it is a list and it can be rendered. Each item in the list supports rendering multiple imports in a loop, separated by spaces, such as: "\"a/b/c\" \"d/e/f\""
body: template content # tql content
--------------------------------
path: /handler/{{ .Name }}.go # The path will first undergo template rendering. If loop_service and loop_method are specified, it will be loop rendered. The data used for rendering is the current rendered single service (method).
update_is_skip: true # whether to skip this file when updating
loop_method: true # loop rendering supports method
loop_service: true # Multiple service support: If the "combine-service" command is set in the generation command and "loop_service: true" is specified in the template, the corresponding template file will be rendered in a loop according to the service during generation. It is the same format as loop_method, and will use the current template to loop render each service. It can be used simultaneously with loop_method.
body: ... # tql content

e.g. tql

https://github.com/cloudwego/cwgo/tree/main/tpl/kitex

Appendix

PackageInfo struct and some commonly used contents

type PackageInfo struct {
   Namespace    string            // idl namespace, It is recommended not to use under pb
   Dependencies map[string]string // package name => import path, used for searching imports
   *ServiceInfo                   // the target service

   Codec            string
   NoFastAPI        bool
   Version          string
   RealServiceName  string
   Imports          map[string]map[string]bool
   ExternalKitexGen string
   Features         []feature
   FrugalPretouch   bool
   Module           string // go module name
}

type ServiceInfo struct {
   PkgInfo
   ServiceName     string
   RawServiceName  string
   ServiceTypeName func() string
   Base            *ServiceInfo
   Methods         []*MethodInfo
   CombineServices []*ServiceInfo
   HasStreaming    bool
}

type PkgInfo struct {
   PkgName    string // the last paragraph of of namespace
   PkgRefName string
   ImportPath string // this method's req and resp's import path
}

type MethodInfo struct {
   PkgInfo
   ServiceName            string // this service's  name
   Name                   string // this method's name
   RawName                string // ditto
   Oneway                 bool
   Void                   bool
   Args                   []*Parameter // params' info, including name, import path, and type
   Resp                   *Parameter // response, including name, import path, and type
   Exceptions             []*Parameter
   ArgStructName          string
   ResStructName          string
   IsResponseNeedRedirect bool // int -> int*
   GenArgResultStruct     bool
   ClientStreaming        bool
   ServerStreaming        bool
}

// Parameter
type Parameter struct {
   Deps    []PkgInfo
   Name    string
   RawName string // StructB
   Type    string // *PkgA.StructB
}