Skip to content

Conversation

ilCollez
Copy link

@ilCollez ilCollez commented Oct 8, 2025

This PR adds Protocol Buffer (proto3) message generation to the types plugin, enabling developers to generate both Go types and protobuf definitions from a single Goa DSL source. This provides a unified approach to type definition across Go services and protobuf-based systems.

Motivation

The types plugin currently generates Go types and validations, which is great for Go-based microservices. However, many systems need to interoperate with:

  • Non-Go services (Python, Java, C++, etc.)
  • gRPC-based communication
  • Binary serialization formats
  • Cross-language schema definitions

By adding protobuf generation, the types plugin becomes a single source of truth for both Go and protobuf type definitions, eliminating the need to maintain parallel type systems.

Features

Complete Type Mapping Support

Goa DSL Type Go Type Proto Type
Boolean bool bool
Int, Int32 int, int32 int32
Int64 int64 int64
UInt, UInt32 uint, 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>

Advanced Features

  • Nested types: Recursively generates messages for user types
  • Arrays: Maps to repeated fields
  • Maps: Native proto3 map support
  • Any type: Automatically imports google/protobuf/any.proto
  • Optional fields: Uses optional modifier for non-required fields
  • Documentation: Preserves descriptions as proto comments
  • Aliases: Properly unwraps to underlying types
  • Field numbering: Sequential numbering (1, 2, 3, ...)

Example

Input: Goa DSL

var _ = Type("User", func() {
    Description("A user account")
    Attribute("id", Int64, "User ID")
    Attribute("email", String, "Email address")
    Attribute("tags", ArrayOf(String), "User tags")
    Attribute("metadata", MapOf(String, Any), "Custom data")
    Required("id", "email")
})

Output 1: Go Types (gen/types/types.go)

// A user account
type User struct {
    // User ID
    ID int64
    // Email address
    Email string
    // User tags
    Tags []string
    // Custom data
    Metadata map[string]any
}

Output 2: Proto Messages (gen/types/types.proto)

import "google/protobuf/any.proto";

// A user account
message User {
  // User ID
  int64 id = 1;
  // Email address
  string email = 2;
  // User tags
  repeated string tags = 3;
  // Custom data
  map<string, google.protobuf.Any> metadata = 4;
}

Usage

Simply import the types plugin as before:

import (
  . "goa.design/goa/v3/dsl"
  _ "goa.design/plugins/v3/types"
)

Run goa gen and you'll get both:

  • gen/types/types.go (Go types + validation)
  • gen/types/types.proto (Protocol Buffer messages)

Use Cases

  1. Microservices Architecture: Share type definitions across Go services
  2. Cross-Language Integration: Use proto files with Python, Java, C++, etc.
  3. Message Queues: Serialize messages with protobuf for Kafka, SQS, etc.

Compatibility

  • No breaking changes to existing functionality
  • All existing tests pass
  • Proto generation is automatic when types plugin is imported
  • Proto files follow proto3 syntax

Documentation

The README has been updated with:

  • Complete feature overview
  • Type mapping reference table
  • Examples for arrays, maps, nested types, and Any type
  • Instructions for compiling proto files with protoc
  • Use case descriptions

@raphael
Copy link
Member

raphael commented Oct 10, 2025

Looks great, one question I see that the timestamp type isn't really supported but there's still code that refer to it:

        needsTimestamp := false
        ....
	if needsTimestamp {
		buf.WriteString("import \"google/protobuf/timestamp.proto\";\n\n")
	}

Would you mind cleaning that up before we merge? thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants