Skip to content

proto2 extensions #271

@oxyii

Description

@oxyii

As we know, Proto3 does not support extensions (except for declaring custom options). Extensions are fully supported in proto2 and editions though (link).

For common tasks (such a CRUD) we can create the following definition:

syntax = "proto2"; // proto2 !!!

package proto;

import "google/protobuf/timestamp.proto";

// common model

message Model {
  optional string id = 1001;
  optional string version = 1002;

  optional google.protobuf.Timestamp created_at = 10001;
  optional google.protobuf.Timestamp updated_at = 10002;
  optional google.protobuf.Timestamp deleted_at = 10003;

  extensions 100000 to 999999; // mount points for extensions
}

// define messages

message Person {
  required string first_name = 1;
  required string last_name = 2;
}

// mount messages to common model

extend Model {
  optional Person person = 100001;
}

After executing protoc for Golang (protoc-gen-go), I see that the following construction was created for Golang:

var file_experimant_proto_extTypes = []protoimpl.ExtensionInfo{
    {
        ExtendedType:  (*Model)(nil),
        ExtensionType: (*Person)(nil),
        Field:         100001,
        Name:          "proto.person",
        Tag:           "bytes,100001,opt,name=person",
        Filename:      "experimant.proto",
    },
}

// Extension fields to Model.
var (
    // optional proto.Person person = 100001;
    E_Person = &file_experimant_proto_extTypes[0]
)

So, I can register extensions on client-side then extract it on server-side, or vise versa:

import "google.golang.org/protobuf/proto"

// SET EXTENSION

id := "123"
m := &Model{Id: &id}

fn := "First"
ln := "Name"
p := &Person{FirstName: &fn, LastName: &ln}

proto.SetExtension(m, E_Person, p)

// GET EXTENSION

person := proto.GetExtension(m, E_Person)
// or
proto.RangeExtensions(m, func(t protoreflect.ExtensionType, value any) bool {
    if t.TypeDescriptor().FullName() == E_Person.TypeDescriptor().FullName() {
        person := value.(*Person)
    }
    return true
})

protoc-gen-ts does not generate (and does not registered them in Model class) an object(s) of classes ExtensionFieldInfo and ExtensionFieldBinaryInfo that is equivalent to Golang's protoimpl.ExtensionInfo.

In addition, as I can see from generated code, model serializer will still ignore extension fields even if I bind it manually, because the generated code explicitly loops through known fields, without knowing anything about extensions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions