Skip to content

A tool for easy generating transport and model code from .proto files.

Notifications You must be signed in to change notification settings

balduser/easypbgen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

easypbgen

An easy code generating tool for transport and model files out from a .proto file.

Русская версия

Example of usage

  1. Create a folder, e.g. pbgen
  2. Put there a .proto file, e.g. service.proto
  3. Create a file (e.g. pbgen.go) with the following content:
package main

import (
  "github.com/balduser/easypbgen"
  "fmt"
  "os"
)

func main() {
  pbgen, err := easypbgen.ParseFile(os.Args[1], nil)
  if err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  easypbgen.PrintAll(pbgen)          // необязательно
  easypbgen.GenerateTransport(pbgen)
  easypbgen.GenerateModel(pbgen)
}
  1. Move to this folder in CLI.
  2. Create a module pbgen:
    go mod init pbgen
  3. Install easypbgen from github:
    go mod tidy
  4. Launch code generation with a command
    go run pbgen.go -service.proto

Files will appear in the same folder.


Tips

  • You should have at least one Service in your file
  • Service should be defined before it's messages

Configuration and templates

It's impossible to create an ultimate tool for any task, so the code generated by easypbgen may not be optimal. Some parts of generated code may not satisfy project's requirements. So to have the proper code generation and the opportunity to launch code generation few times without editing same parts every time it is possible to determine correct parts of code manually and place it in variables of main script or in the config file. To place them in the launching script boby you have to make map[string]string, and the pointer to in must be given as a second argument to the ParseFile() function. Following keys are valid:

Parameters of generated files:

  • <service_name>TransportFile - uri of the transport code file to be generated

  • <service_name>ModelFile - uri of the model code file to be generated

Hardcoding some parts of code

  • model<service_name>Message<message_name> - code of a distinct message

  • transport<service_name><method_name> - code of a distinct method in transport layer (adapter)

  • transport<service_name>Decode<message_name> - code of a distinct decoder

  • transport<service_name>Encode<message_name> - code of a distinct encoder

  • model<service_name>Ending - text or a code for inserting in the end of model file

Overriding existing templates

  • transportHeading - generated transport file heading
  • templateG - transport layer adapter template
  • templateDec - transport layer decoder template
  • templateEnc - transport layer encoder template
  • encFieldTypeTemplate - encoder's "type" field template
  • modelHeading - generated model file heading
  • modelTemplate - generated model file stucture template
Examples
  • some message code
"modelBlogpostAPIServiceMessageCreatePostRequest":
`type CreatePostRequest struct {
  userID         uint32
  postText       string
  hellobug       float64
}

`
  • some transport layer method (adapter) code
func (g grpcTransport) CreatePost(ctx context.Context, request *pb.CreatePostRequest) (*pb.CreatePostResponse, error) {
  _, response, err := g.createPost.ServeGRPC(ctx, request)
  if err != nil {
    g.log.Error().Err(err).Msg("WE LOVE BUGS!")
    return nil, err
  }
  resp := response.(*pb.CreatePostResponse)
  return resp, nil
}
  • some decoder code
func decodeCreatePost(ctx context.Context, grpcRequest interface{}) (interface{}, error) {
  req := grpcRequest.(*pb.CreatePostRequest)
  result := &model.CreatePostRequest{
    UserID:         req.UserID,
    PostText:       req.PostText,
    hellobug:       float64,
  }
  return result, nil
}
  • some encoder code
func encodeCreatePost(ctx context.Context, grpcResponse interface{}) (interface{}, error) {
  resp := grpcResponse.(*model.CreatePostResponse)
  response := &pb.CreatePostResponse{
    CreatePostSuccess: resp.CreatePostSuccess,
    ErrorText:         resp.ErrorText,
    hellobug:          0,
  }
  return response, nil
}

Default templates may be seen in templates.go

Example of a script with the configuration parameters in the body
package main

import (
  "github.com/balduser/easypbgen"
  "fmt"
  "os"
)

func main() {
  config := map[string]string {
    "transportHeading": `package transport
// Hello there!
`,
    "modelBlogpostAPIServiceEnding":
`type CreatePostRequest struct {
    myPrettyFieldName    bug64
}
`,
  }

  pbgen, err := easypbgen.ParseFile(os.Args[1], &config)
  if err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  easypbgen.GenerateTransport(pbgen)
  easypbgen.GenerateModel(pbgen)
}

Moving code templates to the configuration file

For encreasing the readability of a launching script some parts of a code may be moved to the configuration file, which is a .go file placed in the script's folder. It must have package main and it should contain map[string]string instead of a launching script. The pointer to this map must anyway be given to the ParseFile() as a second argument In case if configuration file is used, the project must be built with go build before the code generation.


Model code generation

Sometimes your model should implement more structures than the transport code. In this case you may place special comments for the data model in a .proto file. This can be done with symbols /*# and #*/ in separate (necessary) lines e.g.:

...
// Protocol buffers code

/*#
message LikePostRequest {
  uint32 postID = 1;
}

message LikeCommentRequest {
  uint32 commentID = 1;
}

message SuccessResponse {
  bool Success = 1; // true for success, false for failure
  string errorText = 2;
}
#*/

Not yet implemented

About

A tool for easy generating transport and model code from .proto files.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages