For Go developers working with Protocol Buffers, ensuring data integrity is crucial. While Protobufs guarantee type safety, they don’t enforce semantic rules out of the box. This is where protocheck comes in, a lightweight and powerful tool for adding validation logic to your Protobuf messages.
This blog post will explore the design choices behind protocheck, focusing on its simplicity of declaration and code generation. We’ll also compare it to bufbuild/protovalidate to help you choose the right tool for your project.
Algorithm for drawing a 2D ring shape using OpenGL bindings in Go (from the firespark project).
Go package forest was created to simplify the code needed to write real tests of a REST api. Such tests need to setup Http Requests, send them and inspect Http Responses. The Go standard library has all that is needed to achieve this flow but the required amount of code, especially the error handling, makes tests harder to read and longer to write.
Testing github
Let's create a few tests that examine the response of the public github API call.
package main
import (
"net/http"
"testing"
. "github.com/emicklei/forest"
)
var github = NewClient("https://api.github.com", new(http.Client))
func TestForestProjectExists(t *testing.T) {
cfg := NewConfig("/repos/emicklei/{repo}", "forest").Header("Accept", "application/json")
r := github.GET(t, cfg)
ExpectStatus(t, r, 200)
}
The package variable github (line 10) is a forest Http client wrapper and provides the api to send Http requests (such as GET). On line 13, the cfg variable is a RequestConfig value that is used to build a http.Request with method,url,headers,body. The variable r is a *http.Response. The ExpectStatus function checks the status code. If the code does not match, then the following will be reported.
Artreyu is an open-source command line tool for software build pipelines that need to create artifacts which are composed of multiple versioned build parts. The design of this tool is inspired by the Apache Maven project which provides assembly support for Java projects. I created Artreyu to support a project that delivers compositions of many non-Java artifacts of which some are operating system dependent.
Artreyu works with a repository to archive, fetch and assemble artifacts. To support remote repositories such as Artifactory and Nexus, Artreyu has a simple plugin architecture ; each plugin is just a binary that gets invoked by the artreyu tool. Sources for the nexus plugin is on github.com/emicklei/artreyu-nexus.
Today, I needed to keep track of the linenumber while scanning table driven tests. The standard Go bufio.Scanner does not provide such information. Fortunately, in Go you can create your own by embedding the standard type and overriding the right function. That’s it.
import (
"bufio"
"io"
)
type linescanner struct {
*bufio.Scanner
line int
}
func newScanner(reader io.Reader) *linescanner {
return &linescanner{bufio.NewScanner(reader), 0}
}
func (l *linescanner) Scan() bool {
ok := l.Scanner.Scan()
if ok {
l.line++
}
return ok
}
I needed a simple solution to notify components about changes in some global settings.
In my Java days, I have been using the Guava Eventbus to solve similar problems, so I decided to cook something that does the basics.
From Guava: “The EventBus allows publish-subscribe-style communication between components requiring the components to explicitly register with one another (and thus be aware of each other).”
The Java implementation uses annotations to register components and subscribe its methods to event types. In my Go version, with lack of such annotations, I decided to keep it simpler; just subscribe a function to an event by name. The singleton EventBus value will be an exposed package variable.
package main
import "fmt"
type intSlice []int
func (i intSlice) collect(block func(i int) int) intSlice {
r := make(intSlice, len(i))
for j, v := range i {
r[j] = block(v)
}
return r
}
func main() {
numbers := intSlice{1, 2, 3}
squared := func(i int) int { return i * i }
fmt.Printf("%v", numbers.collect(squared))
}
Try it.
Implementations of select,inject,detect are left as an excercise for the reader.
Today, I was playing with Otto and hacked together a small command-line-interface program in Go.
package main
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/robertkrimen/otto"
)
var Otto = otto.New()
func main() {
fmt.Println("otto\n")
loop()
}
func dispatch(entry string) string {
if len(entry) == 0 {
return entry
}
value, err := Otto.Run(entry)
if err != nil {
return err.Error()
} else {
return fmt.Sprintf("%v", value)
}
}
func loop() {
for {
fmt.Print("> ")
in := bufio.NewReader(os.Stdin)
entered, err := in.ReadString('\n')
if err != nil {
fmt.Println(err)
break
}
entry := strings.TrimLeft(entered[:len(entered)-1], "\t ") // without tabs,spaces and newline
output := dispatch(entry)
if len(output) > 0 {
fmt.Println(output)
}
}
}
One cool feature of Otto is the ability to expose your own Go functions in the Javascript namespace.
This example below adds the function log to print its arguments using the standard log package.
These are the results of exploring one aspect of the Go language; functions can return multiple values.
Consider the following simple function:
func ab() (a,b int) {
a,b = 1,2
return
}
Clearly, this function cannot be used in other function calls that expect a single value.
fmt.Printf("%v\n",ab())
The compiler will help you: “multiple-value ab() in single-value context”.
Now suppose you want to take only the first value without introducing an intermediate variable.
One possible solution might be to create this helper function:
Update: Based on several comments posted on the Google+ Go community, I rewrote the solution presented here. See past the Conclusion section.
Recently, I was asked to write a small program for collecting product promotion information for a large collection of products. Given an input file of product identifiers, the following tasks had to be done:
- read all identifiers from an input file
- for each identifier, fetch product offer information in XML
- parse the offer XML into in a DOM document
- extract all promotions from the offer document
- for each promotion, export its data into a CSV record
A straightforward implementation is to write a function for each task and call them in a nested loop. For this program, I created functions such that the basic flow is quite simple.
Hopwatch is an experimental tool that can help debugging Go programs. Unlike most debuggers, hopwatch requires you to insert function calls at points of interest in your program. At these program locations, you can tell Hopwatch to display variable values and suspend the program (or goroutine). Hopwatch uses Websockets to exchange commands between your program and the debugger running in a HTML5 page.
Using Hopwatch
Basically, there are two functions Display and Break. Calling Display will print the variable,value pairs in the debugger page. Calling Break will suspend the program until you tell the debugger to Resume. The Display function takes one or more pairs of (variable name,value). The Break function takes one or more boolean values to be conditionally. Below is a test example.
package main
import "github.com/emicklei/hopwatch"
func main() {
for i := 0; i < 6; i++ {
hopwatch.Display("i",i)
j := i * i
hopwatch.Display("i",i, "j", j ).Break(j > 10)
hopwatch.Break()
}
}
Starting your Go program that includes a Hopwatch function call waits for a connection to the debugger page.
You can disable Hopwatch by passing the command line parameters -hopwatch false.
In an earlier post, I discussed an example of using plain functions as objects. Today, I investigated solutions for using Methods as objects. As I understand it, Go methods are functions that are “bound” to a named type that is not a pointer or an interface.
package main
import "fmt"
type T struct {
S string
}
func (t T) GetS1() string {
return t.S
}
func (t *T) GetS2() string {
return t.S
}
func main() {
t := T{"hello"}
f := (*T).GetS1
g := (T).GetS1
h := (*T).GetS2
// i := (T).GetS2 // invalid method expression T.GetS2 (needs pointer receiver: (*T).GetS2)
fmt.Printf("%v, %v %v, who is there?", f(&t) ,g(t), h(&t))
}
Run it yourself.
In a previous post, I discussed the design of go-restful which is a package for building REST-style WebServices using the Google Go programming language.
Today, I completed the implementation of that package which provides the basics:
- Creating a WebService with Routes (mapping between Http Request and a Go function)
- Each Route requires information about the Http method (GET,POST,...), URL Path (/users..), Mime-types and the function it binds to
- Functions get passed in a Request and a Response
- The Request is used to access Path and Query parameters , Headers and request content (XML, JSON,...)
- The Response is used to set Status, Headers, and response content
- Both Request and Response can Unmarshal and Marshal objects to and from XML,JSON using the standard packages
All of this can best be illustrated with a small example ; a Webservice for CRUD operations on User objects.
We start by creating the file userservice.go inside its own folder userservice.
package userservice
import (
"github.com/emicklei/go-restful"
"log"
)
type User struct {
Id, Name string
}
Type User represents our domain object.
Today, I played with functions as objects in the Go programming language. If functions are first class citizens in Go then it must be possible to store them in fields of a struct, pass them as arguments to other functions and use them as return values of other functions.
So I visited play.golang.org for putting together a simple program that demonstrates this.
package main
import "fmt"
func CallWith(f func(string), who string) {
f(who)
}
type FunctionHolder struct {
Function func(string)
}
func main() {
holder := FunctionHolder{ func(who string) { fmt.Println("Hello,", who) }}
CallWith(holder.Function,"ernest")
}
- The CallWith function takes a one string parameter function f and a string parameter who. The body of the CallWith function evaluates the function parameter with the string parameter.
- The FunctionHolder is a struct type with a field called Function which must be a function with a string parameter.
- In the main function, a FunctionHolder is created initializing the Function field with a function that prints an Hello message.
- Next in the main function, the CallWith function is called with the Function value of the holder and a string value.
On play.golang.org can run this program yourself
I have been using JAX-RS for many REST-based service implementations in Java.
As part of my journey into the Google Go programming language, I am exploring designs for such REST support using the standard net/http package in Go.
JAX-RS provides a set of Annotation classes which can be used to add meta-data to classes, methods and method arguments. In JAX-RS these annotation are used to specify the mapping between a Http Request to a Java method and its arguments.