Overview

This post explains explains how to use protocol buffers in go from installing protocol buffer to actually using one.

Install Protocol Buffer

First of all, protocol buffer compiler protoc need to be installed.

$ sudo apt-get install protobuf-compiler

Install Protocol Buffer Go Plugin

After installing protocol buffer compiler protoc, we need to install protocol buffer go plugin to generate go source files and a library for runtime support.

The official README

This software has two parts: a ‘protocol compiler plugin’ that generates Go source files that, once compiled, can access and manage protocol buffers; and a library that implements run-time support for encoding (marshaling), decoding (unmarshaling), and accessing protocol buffers.

$ go get -u github.com/golang/protobuf/protoc-gen-go
$ go get -u github.com/golang/protobuf/proto

Use Protocol Buffer

Now we are ready to start using protocol buffer. Define a protocol buffer message and save it as person.proto

package main;

message Person {
  required string name = 1;
  required int32 age = 2;

  enum Gender {
    Male = 0;
    Female = 1;
  }

  optional Gender gender = 3 [default = Male];
}

Side note: The official doc warns that required keyword must be treaded carefully.

Protocol Buffers Language Guide

Required Is Forever You should be very careful about marking fields as required. If at some point you wish to stop writing or sending a required field, it will be problematic to change the field to an optional field – old readers will consider messages without this field to be incomplete and may reject or drop them unintentionally. You should consider writing application-specific custom validation routines for your buffers instead. Some engineers at Google have come to the conclusion that using required does more harm than good; they prefer to use only optional and repeated. However, this view is not universal.

Next generate go source files from person.proto. You should see a generated file named person.pb.go.

$ protoc --go_out=. *.proto

Finally try marshalling and unmarshalling the person message in main.go.

package main

import (
	"log"

	"github.com/golang/protobuf/proto"
)

func main() {
	p1 := &Person{
		Name: proto.String("Ken"),
		Age:  proto.Int32(27),
	}
	// (1)
	log.Println(p1.Gender)
	log.Println(p1.GetGender())

	m, err := proto.Marshal(p1)
	if err != nil {
		log.Fatalf("error marshalling person: %v", err)
	}

	p2 := &Person{}
	err = proto.Unmarshal(m, p2)
	if err != nil {
		log.Fatalf("error unmarshalling person: %v", err)
	}

	// (2)
	log.Println(p1)
	log.Println(p2)
}

In (1) you can see that p1.Gender returns nil (because it is raw property of person object) but p1.GetGender() returns default value Male which is because GetGender() is a getter method generated by protocol buffer. In (2) you can see that p1 and p2 have the same value.

Thanks for reading, happy hacking!

References