The types plugin is a Goa plugin
that generates Go data types, validation functions, and Protocol Buffer message
definitions for all user types defined in a Goa design package.
Given the following design:
var _ = Type("MyType", func() {
Description("My type")
Attribute("age", Int, "Age", func() {
Minimum(0)
})
Attribute("name", String, "Name")
Required("age", "name")
})The plugin generates two files:
package types
import goa "goa.design/goa/v3/pkg"
type (
// My type
MyType struct {
// Age
Age int
// Name
Name string
}
)
// ValidateMyType runs the validations defined on MyType
func ValidateMyType(v *MyType) (err error) {
if v.Age < 0 {
err = goa.MergeErrors(err, goa.InvalidRangeError("v.age", v.Age, 0, true))
}
return
}syntax = "proto3";
package types;
option go_package = "<your-module>/types";
// My type
message MyType {
// Age
int32 age = 1;
// Name
string name = 2;
}This plugin makes it possible to share data types between Goa microservices and
other Go based processes such as daemons or adapters. A prototypical use case is
a data pipeline where messages are sent to queues (AWS SQS, AWS Kinesis, Kafka,
etc.) to be consumed by an adapter. The adapter can use the data structures
generated by the types plugin to decode and validate messages. The adapter can
then make requests to a Goa microservice whose design package imports the
original design package defining the data types thus guaranteeing compatibility.
The protobuf definitions enable:
- Cross-language compatibility with protobuf-based systems
- Efficient binary serialization
- gRPC service integration
- Schema evolution with backwards compatibility
To enable the plugin simply import both the types package as follows:
import (
. "goa.design/goa/v3/dsl"
_ "goa.design/plugins/v3/types"
)Note the use of blank identifier to import the types package which is
necessary as the package is imported solely for its side-effects
(initialization).
Enabling the plugin changes the behavior of the gen command of the goa tool.
The command generates two additional files under the gen/types folder:
types.go- containing the Go type definitions and validationstypes.proto- containing the Protocol Buffer message definitions
The plugin maps Goa types to both Go and Protocol Buffer types:
| Goa Type | Go Type | Proto Type |
|---|---|---|
| Boolean | bool | bool |
| Int | int | int32 |
| Int32 | int32 | int32 |
| Int64 | int64 | int64 |
| UInt | uint | uint32 |
| UInt32 | uint32 | uint32 |
| UInt64 | uint64 | uint64 |
| Float32 | float32 | float |
| Float64 | float64 | double |
| String | string | string |
| Bytes | []byte | bytes |
| Any | interface{} | google.protobuf.Any |
| ArrayOf(T) | []T | repeated T |
| MapOf(K,V) | map[K]V | map<K, V> |
The plugin handles complex nested structures:
var _ = Type("Order", func() {
Attribute("items", ArrayOf("OrderItem"))
})
var _ = Type("OrderItem", func() {
Attribute("name", String)
Attribute("quantity", Int)
})Generates:
message OrderItem {
string name = 1;
int32 quantity = 2;
}
message Order {
repeated OrderItem items = 1;
}The plugin supports map types:
var _ = Type("Config", func() {
Attribute("settings", MapOf(String, String))
})Generates:
message Config {
map<string, string> settings = 1;
}The plugin supports the Any type for dynamic content:
var _ = Type("Envelope", func() {
Attribute("metadata", MapOf(String, Any))
})Generates:
import "google/protobuf/any.proto";
message Envelope {
map<string, google.protobuf.Any> metadata = 1;
}To compile the generated .proto files to Go code, use the Protocol Buffer compiler:
protoc --go_out=. --go_opt=paths=source_relative \
gen/types/types.protoThis generates gen/types/types.pb.go which can be used alongside the Goa-generated
gen/types/types.go for maximum interoperability.