Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go Opaque API Migration #208

Open
tiagomelo opened this issue Dec 22, 2024 · 0 comments
Open

Go Opaque API Migration #208

tiagomelo opened this issue Dec 22, 2024 · 0 comments

Comments

@tiagomelo
Copy link

tiagomelo commented Dec 22, 2024

Hello there!

TL;DR: switching to HYBRID api and compiling an exising .proto file replaced all struct properties with pointers, so the exising Go code will break.


Original book.proto:

syntax = "proto3";

package books;
option go_package = "github.com/tiagomelo/go-templates/example-grpc-crud-service-opaqueapi/api/proto/gen/book";

// BookService provides CRUD operations for managing books.
service BookService {
    // GetAllBooks retrieves all books in the database.
    rpc GetAllBooks (GetAllBooksRequest) returns (GetAllBooksResponse);

    // GetBook retrieves a single book by its ID.
    rpc GetBook (GetBookRequest) returns (Book);

    // CreateBook adds a new book to the database.
    rpc CreateBook (CreateBookRequest) returns (Book);

    // UpdateBook modifies an existing book's details.
    rpc UpdateBook (UpdateBookRequest) returns (Book);

    // DeleteBook removes a book from the database by its ID.
    rpc DeleteBook (DeleteBookRequest) returns (DeleteBookResponse);
}

// GetAllBooksRequest is the request message for GetAllBooks RPC.
message GetAllBooksRequest {}

// Book represents a book with an ID, title, author, and number of pages.
message Book {
    int32 id = 1;       // Unique identifier for the book.
    string title = 2;   // Title of the book.
    string author = 3;  // Author of the book.
    int32 pages = 4;    // Number of pages in the book.
}

// GetAllBooksResponse is the response message for GetAllBooks RPC.
// It contains a list of books.
message GetAllBooksResponse {
    repeated Book books = 1; // List of books.
}

// GetBookRequest is the request message for GetBook RPC.
// It includes the ID of the book to retrieve.
message GetBookRequest {
    int32 id = 1; // ID of the book to retrieve.
}

// CreateBookRequest is the request message for CreateBook RPC.
// It includes the details of the book to create.
message CreateBookRequest {
    Book book = 1; // Details of the book to create.
}

// UpdateBookRequest is the request message for UpdateBook RPC.
// It includes the updated details of the book.
message UpdateBookRequest {
    Book book = 1; // Updated details of the book.
}

// DeleteBookRequest is the request message for DeleteBook RPC.
// It includes the ID of the book to delete.
message DeleteBookRequest {
    int32 id = 1; // ID of the book to delete.
}

// DeleteBookResponse is the response message for DeleteBook RPC.
// It confirms the deletion of the book by returning its ID.
message DeleteBookResponse {
    int32 id = 1; // ID of the book that was deleted.
}

And it was compiled to:

// Book represents a book with an ID, title, author, and number of pages.
type Book struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Id     int32  `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`        // Unique identifier for the book.
	Title  string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`   // Title of the book.
	Author string `protobuf:"bytes,3,opt,name=author,proto3" json:"author,omitempty"` // Author of the book.
	Pages  int32  `protobuf:"varint,4,opt,name=pages,proto3" json:"pages,omitempty"`  // Number of pages in the book.
}

Notice that Id, Title, Author and Pages properties are not pointers.

Example of Go code that uses it:

	newBook := &book.Book{
		Title:  "title",
		Author: "author",
		Pages:  100,
	}

It is said here (https://protobuf.dev/reference/go/opaque-migration/#setup) that after switching to the HYBRID API:

Your existing code will continue to build. The Hybrid API is a step between the Open and Opaque API which adds the new accessor methods but keeps struct fields visible.

But that's not what happened to me, at least.

What I did so far:

  1. replaced syntax = "proto3"; with edition = "2023"; in book.proto
  2. issued open2opaque setapi -api HYBRID $(find . -name "*.proto")
  3. recompiled it with protoc (notice that without --experimental_allow_proto3_optional, it won't work):
protoc \
		-I api/proto \
		--experimental_allow_proto3_optional \
		--go_out=api/proto/gen/book \
		--go_opt=paths=source_relative \
		--go-grpc_out=api/proto/gen/book \
		--go-grpc_opt=paths=source_relative \
		api/proto/book.proto
  1. then, all properties in Book were transformed to pointers:
// Book represents a book with an ID, title, author, and number of pages.
type Book struct {
	state         protoimpl.MessageState `protogen:"hybrid.v1"`
	Id            *int32                 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`        // Unique identifier for the book.
	Title         *string                `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"`   // Title of the book.
	Author        *string                `protobuf:"bytes,3,opt,name=author" json:"author,omitempty"` // Author of the book.
	Pages         *int32                 `protobuf:"varint,4,opt,name=pages" json:"pages,omitempty"`  // Number of pages in the book.
	unknownFields protoimpl.UnknownFields
	sizeCache     protoimpl.SizeCache
}
  1. then, naturally, my existing Go code will not compile anymore:

Screenshot from 2024-12-22 12-14-01

Because all properties are now pointers.


Since switching to HYBRID API is supposed to be an intermediary step to keep existing Go code compiling, it shouldn't replace any properties, but only create accessor methods, no? Properties are still visible, but they're converted to pointers.

If this is expected, I think that either the documentation should mention this or the HYBRID API shouldn't change the properties to pointers... what do you think?


EDIT: tried to run open2opaque rewrite -levels=red github.com/tiagomelo/go-templates/example-grpc-crud-service-with-opaqueapi/...,

PROCESSED 10 packages (total patterns: 14)
	Last package:         github.com/tiagomelo/go-templates/example-grpc-crud-service-opaqueapi/examples/client/create_book
	Total time:           468.852744ms
	Package profile:      TOTAL: 32.343866ms | start 483ns main/scheduled 32.328667ms fix/fixed 10.56µs fix/wrotefiles 831ns fix/donestats 443ns main/fixed 2.641µs main/gotresp 241ns done
	Failures:             0 (0.00%)
	Average time:         46.885274ms
	Estimated until done: 187.541096ms
	Estimated done at:    2024-12-22 12:21:52.607987212 -0300 -03 m=+0.730756366
	Error:                <nil>

and it was changed to

newBook := book.Book_builder{
		Title:  "title",
		Author: "author",
		Pages:  100,
	}.Build()

which will still fail to compile. I know that red is for human correction, but I would expect that the properties were not changed to pointers. I can be wrong, of course.

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

No branches or pull requests

1 participant