{"id":13740770,"url":"https://github.com/bold-commerce/protoc-gen-struct-transformer","last_synced_at":"2025-05-08T20:32:36.406Z","repository":{"id":37734438,"uuid":"218851382","full_name":"bold-commerce/protoc-gen-struct-transformer","owner":"bold-commerce","description":"Transformation functions generator for Protocol Buffers.","archived":false,"fork":false,"pushed_at":"2021-08-30T02:42:58.000Z","size":2612,"stargazers_count":201,"open_issues_count":5,"forks_count":31,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-08-04T04:07:00.350Z","etag":null,"topics":["go","golang","grpc","grpc-go","proto","protobuf","protoc-gen","protocol-buffers","transformer"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bold-commerce.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-31T20:04:47.000Z","updated_at":"2024-06-25T02:12:59.000Z","dependencies_parsed_at":"2022-09-16T06:13:25.739Z","dependency_job_id":null,"html_url":"https://github.com/bold-commerce/protoc-gen-struct-transformer","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bold-commerce%2Fprotoc-gen-struct-transformer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bold-commerce%2Fprotoc-gen-struct-transformer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bold-commerce%2Fprotoc-gen-struct-transformer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bold-commerce%2Fprotoc-gen-struct-transformer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bold-commerce","download_url":"https://codeload.github.com/bold-commerce/protoc-gen-struct-transformer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224765554,"owners_count":17366135,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","grpc","grpc-go","proto","protobuf","protoc-gen","protocol-buffers","transformer"],"created_at":"2024-08-03T04:00:52.034Z","updated_at":"2025-05-08T20:32:36.363Z","avatar_url":"https://github.com/bold-commerce.png","language":"Go","funding_links":[],"categories":["Language-Specific"],"sub_categories":["Go"],"readme":"# Transformation function generator for gRPC.\n\n[![GoDoc](https://godoc.org/github.com/bold-commerce/protoc-gen-struct-transformer?status.svg)](https://godoc.org/github.com/bold-commerce/protoc-gen-struct-transformer)\n[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/bold-commerce/protoc-gen-struct-transformer?sort=semver)](https://github.com/bold-commerce/protoc-gen-struct-transformer/releases)\n[![BSD-3-Clause](https://img.shields.io/github/license/bold-commerce/protoc-gen-struct-transformer)](./LICENSE)\n\n\u003c!-- vim-markdown-toc GFM --\u003e\n\n* [Quick presentation](#quick-presentation)\n* [Overview](#overview)\n* [How to use](#how-to-use)\n  * [Installation](#installation)\n    * [Homebrew](#homebrew)\n    * [go get](#go-get)\n  * [Add options to *.proto file](#add-options-to-proto-file)\n  * [Run protoc](#run-protoc)\n  * [Use generated functions in your gRPC server implementation.](#use-generated-functions-in-your-grpc-server-implementation)\n  * [CLI parameters](#cli-parameters)\n* [Troubleshooting](#troubleshooting)\n  * [make generate returns an error](#make-generate-returns-an-error)\n    * [\"protobuf@v1.3.1/gogoproto/gogo.proto\" was not found or had errors.](#protobufv131gogoprotogogoproto-was-not-found-or-had-errors)\n\n\u003c!-- vim-markdown-toc --\u003e\n\n## Quick presentation\n[Speakerdeck](https://speakerdeck.com/ekhabarov/protoc-gen-struct-transformer)\n\n## Overview\n[Protocol buffers complier](https://github.com/protocolbuffers/protobuf) `protoc` generated structures based on message\ndefinition in `*.proto` file. It's possible to use these generated structures\ndirectly, but it's better to have clear separation between transport level\n(gRPC) and business logic with its own structures. In this case you have to\nconvert protobuf structures into business logic structures and vice versa.\n\n`protoc-gen-struct-transformer` is a plugin for `protoc` which generates functions\nfor structure transformation.\n\nLet's look at simple example.\n\nSource proto file:\n```proto\n// message.proto\nsyntax = \"proto3\";\npackage messages;\n\nmessage Product {\n  int32 id = 1;\n  string name = 2;\n}\n```\n\nCommand `protoc --gogofaster_out=. message.proto` will generate `message.pb.go` with\nfollowing structure:\n```go\ntype Product struct {\n  Id   int32  `protobuf:\"varint,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n  Name string `protobuf:\"bytes,2,opt,name=name,json=name,proto3\" json:\"name,omitempty\"`\n}\n```\nand let's suppose you service has as `repo` package with `ProductModel` struct inside:\n\n```go\ntype ProductModel struct {\n  ID   int    `db:\"id\" json:\"id\"`\n  Name string `db:\"name\" json:\"name\"`\n}\n```\nIn order to publish data from the repo to API you have to convert `ProductModel`\nto `Product`, for saving data which hit API you have to make back transformation.\n\n```go\nfunc ProductModelToProduct(m repo.ProductModel) proto.Product {\n return proto.Product {\n    Id:   m.ID,\n    Name: m.Name,\n  }\n}\n\nfunc ProductToProductModel(p proto.Product) repo.ProductModel {\n  return repo.ProductModel {\n      ID:   p.Id,\n      Name: p.Name,\n  }\n}\n```\nList of function type should be generated:\n\nSource   | Destination | Suffix name\n---------|-------------|---\n*proto   | *model      | `Ptr`\n[]*proto | []*model    | `PtrList`\n*proto   | model       | `PtrVal`\n[]*proto | []model     | `PtrValList`\nproto    | model       |\nproto    | \\*model     | `ValPtr`\n[]proto  | []model     | `ValList`\n*model   | *proto      | `Ptr`\n[]*model | []*proto    | `PtrList`\n*model   | proto       | `PtrVal`\n[]*model | []proto     | `PtrValList`\nmodel    | proto       |\nmodel    | \\*proto     | `ValPtr`\n[]model  | []proto     | `ValList`\n\nfunction name has a format `\u003cSource\u003eTo\u003cDestination\u003e\u003cSuffix\u003e`.\n\nFor instance, function which converts list of pointers to Product into list of\nProduct values will be named `PbToProductPtrValList`,\nwhere\n* `Pb` is a replacement for proto message\n* `Products` is a name of model structure\n* `PtrValList` is a suffix pointed that convertion is made from slice of pointer to slice of values.\n\nFull set of function for Product message will be as:\n```go\nfunc PbToProductPtr(src *example.Product, opts ...TransformParam) *model.Product\nfunc PbToProductPtrList(src []*example.Product, opts ...TransformParam) []*model.Product\nfunc PbToProductPtrVal(src *example.Product, opts ...TransformParam) model.Product\nfunc PbToProductPtrValList(src []*example.Product, opts ...TransformParam) []model.Product\nfunc PbToProductList(src []*example.Product, opts ...TransformParam) []model.Product\nfunc PbToProduct(src example.Product, opts ...TransformParam) model.Product\nfunc PbToProductValPtr(src example.Product, opts ...TransformParam) *model.Product\nfunc PbToProductValList(src []example.Product, opts ...TransformParam) []model.Product\nfunc ProductToPbPtr(src *model.Product, opts ...TransformParam) *example.Product\nfunc ProductToPbPtrList(src []*model.Product, opts ...TransformParam) []*example.Product\nfunc ProductToPbPtrVal(src *model.Product, opts ...TransformParam) example.Product\nfunc ProductToPbValPtrList(src []model.Product, opts ...TransformParam) []*example.Product\nfunc ProductToPbList(src []model.Product, opts ...TransformParam) []*example.Product\nfunc ProductToPb(src model.Product, opts ...TransformParam) example.Product\nfunc ProductToPbValPtr(src model.Product, opts ...TransformParam) *example.Product\nfunc ProductToPbValList(src []model.Product, opts ...TransformParam) []example.Product\n```\n\nwhere\n* `example` is a package generated by `protoc-gen-go` or `protoc-gen-gogo` plugin\n* `model` is a package which contains manually created models structures.\n\nFull example you can find in [example](./example) directory.\n\n## How to use\n\n### Installation\nI assume you already have `protoc` installed.\n\nFirst of all, it's necessary to install plugin itself, it's just a binary file,\nwhich should be placed into $PATH to be available for `protoc`.\n\n#### Homebrew\n\n```shell\n% brew tap bold-commerce/tap\n% brew install protoc-gen-struct-transformer\n```\n\n#### go get\nIf you're going to make changes to plugin, use `go get ...` or `git clone ...`\n\n```shell\n% export GO111MODULE=on\n% go get -u -d github.com/bold-commerce/protoc-gen-struct-transformer\n% cd $GOPATH/src/github.com/bold-commerce/protoc-gen-struct-transformer\n// make changes\n% go install\n```\n\nNext, we need `protoc-gen-go` plugin (or `protoc-gen-gogofaster` if you use\n`gogo` specific options) which creates `*.pb.go` file.\n```shell\ngo get -u github.com/golang/protobuf/protoc-gen-go\n// or\ngo get -u github.com/gogo/protobuf/protoc-gen-gogofaster\n```\n\n### Add options to *.proto file\nTo configure plugin you have to use **file level** options listed below. The\nplugin will not process file without these options.\n```proto\n// This import allows to use this options.\n// Relatively to import_path: github.com/bold-commerce/protoc-gen-struct-transformer.\n// See Makefile for mapping details.\nimport \"options/annotations.proto\";\n\n// Go package name which contains business logic structures.\noption (transformer.go_repo_package) = \"models\";\n// Go package name with protobuf generated srtuctures. Could be equal to\n// options go_package.\noption (transformer.go_protobuf_package) = \"example\";\n// Path to source file with Go structures which will be used as destination.\noption (transformer.go_models_file_path) = \"example/model/model.go\";\n```\nas well as **message level** option\n```proto\n// Name of structure from business logic package. This option links business\n// logic and generated structure.\nmessage Product {\n  option (transformer.go_struct) = \"ProductModel\";\n  // ...\n}\n```\noptions above are minimal requirement for use this plugin.\n\nAlso plugin has additional **field level** options:\n\n```proto\nmessage Product {\n  // SomeField will not be added to transformation function.\n  string some_field = 4 [ (transformer.skip) = true ];\n  // \"map_as\" option is used in cases when protoc-gen-go* plugin creates\n  // \"unpredictable\" field name, i.e. by default protoc-gen-go* converts\n  // protobuf named writen in snake_case into CamelCase, but for fields like\n  // map_field_1 this rule has aa exception, in pb.go file it will be\n  // \"MapField_1\" instead of \"MapField1\".\n  // \"map_to\" options is used when you need to map current message field to\n  // field in model with arbitrary name.\n  // Both options \"map_as\" and \"map_to\" can be used independently.\n  string map_field_1 = 6 [ (transformer.map_as) = \"MapField_1\", (transformer.map_to) = \"MapField1\"];\n  // \"custom\" allows to use custom transformers for fields, which require extended transformation\n  // The plugin won't generate methods for this field,\n  // but rather expect it to be in the same package with the transformer file\n  CustomType custom_field [(transformer.custom) = true]\n}\n```\n### Run protoc\n```shell\nprotoc \\\n  --proto_path=github.com/gogo:. \\\n  --go_out=Moptions/annotations.proto=github.com/bold-commerce/protoc-gen-struct-transformer/options,plugins=grpc:. \\\n  --struct-transformer_out=package=transform:. \\\n  ./message.proto\n```\nthis command generates two files:\n* `message.pb.go` contains auto-generated structures.\n* `transform/message_transformer.go` contains transformation functions.\n\nby default `message_transformer.go` does not contain imports. To add imports\nrun `protoc` with:\n```shell\n  --struct-transformer_out=package=transform,goimports=true:. \\\n```\n\n### Use generated functions in your gRPC server implementation.\n```go\nfunc (s *server) CreateProduct(ctx context.Context, req *pb.Request) (*pb.Response, error) {\n\tp, err := s.svc.Create(ctx, transform.PbToProduct(req.Product))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn \u0026pb.Response{\n\t\tProduct: transform.ProductToPb(p),\n\t}, nil\n}\n```\n\n### CLI parameters\n```\nUsage of protoc-gen-struct-transformer:\n  -debug\n        Add debug information to generated file.\n  -goimports\n        Perform goimports on generated file.\n  -helper-package string\n        Package name for helper functions.\n  -package string\n        Package name for generated functions. (default \"fallback\")\n  -use-package-in-path\n        If true, package parameter will be used in path for output file. (default true)\n  -version\n        Print current version.\n```\n## Troubleshooting\n\n### make generate returns an error\n#### \"protobuf@v1.3.1/gogoproto/gogo.proto\" was not found or had errors.\n`gogo.proto` file which is used for gogo-specific options is imported from\ngo modules cache. In order to fill out the cache run:\n\n```shell\n% export GO111MODULE=on\n% go build\n```\nand run `make generate` again.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbold-commerce%2Fprotoc-gen-struct-transformer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbold-commerce%2Fprotoc-gen-struct-transformer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbold-commerce%2Fprotoc-gen-struct-transformer/lists"}