# Better gRPC with Connect: A Go Application Migration

Our digital cognitive behavioral therapy app [Awarefy](https://www.awarefy.com/app/en) has been developing and operating its backend system using Go + gRPC / Protocol Buffers since April 2022. Due to the ongoing web app development and the need to switch to connect-go, we have migrated from `grpc-go` to `connect-go`.

## What is Connect?

**Connect** is best understood as a Better gRPC.

* [https://connect.build/docs/go/getting-started/](https://connect.build/docs/go/getting-started/?ref=awarefy.dev)
    

> *Connect is a slim library for building browser- and gRPC-compatible HTTP APIs.*

Connect is developed by Buf, an organization that is passionate about gRPC.

%[https://buf.build/] 

Buf has been providing tools for building and maintaining Protocol Buffers schema files and a schema registry even before Connect.

Their commitment to creating a more strict and comprehensible specification can be seen in their efforts.

%[https://buf.build/blog/protobuf-language-specification] 

Buf announced the concept of Connect in January 2022.

%[https://buf.build/blog/connect-a-better-grpc/] 

Buf's recent focus is on Connect, which is already at the center of development experiences using gRPC / Protocol Buffers.

## What are the benefits of using Connect?

The benefits of using Connect include:

1. Supporting gRPC, Connect, and `grpc-web` with a single codebase
    
2. Resolving issues with gRPC when using JavaScript in a browser as a client (`grpc-web`)
    
3. gRPC compatibility allows client code incompatible with Connect to work.
    
4. Easier debugging compared to gRPC as it accepts traditional RESTful API / JSON (`application/json`) requests (although only for POST)
    

For more details, refer to the official documentation.

* [https://connect.build/docs/introduction/](https://connect.build/docs/introduction/)
    

## Support for Connect in various languages

Buf supports Go, Kotlin, Swift, Web（Client-side JavaScript）, and Node.js.

These are for Connect support and other languages, Connect is not used; instead, gRPC is used for processing due to backward compatibility.

Awarefy's app is developed using Flutter, so Dart support is awaited. Advantageously, the Flutter / Dart side code does not need to be changed if it is non-Connect gRPC.

## connect-go

`connect-go` is a library for developing client/server applications with Connect support in the Go language.

%[https://github.com/bufbuild/connect-go] 

Before Connect, `grpc-go` was practically essential for developing gRPC web servers in the Go language.

%[https://github.com/grpc/grpc-go] 

`grpc-go` required adherence to `grpc-go` conventions, which had some differences from RESTful API development knowledge. Connect can be said to have fewer differences.

A demo app using connect-go is available.

%[https://github.com/bufbuild/connect-demo] 

This should give you a good sense of the overall implementation.

## Development flow with Connect

The development flow with Connect is as follows:

1. Write Protocol Buffers definitions
    
2. Generate code with the Buf command
    
3. Implement the backend
    

This development flow is no different from that of gRPC.

An example of `buf.gen.yaml` is as follows:

```yaml
version: v1
managed:
  enabled: true
plugins:
  - name: go
    out: gen
    opt: paths=source_relative
  - name: connect-go
    out: gen
    opt: paths=source_relative
```

## Tips for migrating from `grpc-go` to `connect-go`

Here are some tips for migrating from `grpc-go` to `connect-go`. Since the code is only shown in fragments, please compare it with the demo app mentioned earlier and proceed.

An official migration guide is also available.

### HTTP Server

This might be the most significant difference.

```go
s := grpc.NewServer()
```

The part that depended on `grpc-go` is no longer needed, and the code is changed to use `http.Server`.

```go
mux := http.NewServeMux()

srv := &http.Server{
    Addr: fmt.Sprintf(":%v", port),
    Handler: h2c.NewHandler(
        mux,
        &http2.Server{},
    ),
}
```

in this sense, switching to Connect brings the development closer to standard web app development.

### Request / Response

For request and response handling, simply wrap the request with `connect.Request` and the response with `connect.Response`. This can be done with a simple find and replace.

```go
type healthCheckController struct{}

func NewHealthCheckServiceServer() svc.HealthCheckServiceHandler {
	return &healthCheckController{}
}

func (h healthCheckController) Check(
	context.Context,
	*connect.Request[pb.HealthCheckRequest],
) (
	*connect.Response[pb.HealthCheckResponse],
	error,
) {
	return connect.NewResponse(&pb.HealthCheckResponse{}), nil
}
```

*Note: The code starts with* `svc.` *and* `pb.` *are imports from files automatically generated by the* `buf` *command.*

Error Codes As mentioned earlier, since Connect is gRPC-compatible, you can use the [google.golang.org/grpc/status](https://pkg.go.dev/google.golang.org/grpc/status) library for expressing errors in gRPC.

However, it is better to switch to Connect's error-related features, as they are almost mechanically interchangeable.

```go
connect.NewError(connect.CodeUnauthenticated, errors.New("failed to get a token"))
```

### Interceptor (Middleware)

Interceptor (Middleware) is another area with significant changes.

The example below is a logging interceptor.

```go
func NewLoggingInterceptor() connect.UnaryInterceptorFunc {
	interceptor := func(next connect.UnaryFunc) connect.UnaryFunc {
		return connect.UnaryFunc(func(
			ctx context.Context,
			req connect.AnyRequest,
		) (connect.AnyResponse, error) {
			Logger.Info(
				"Request",
				zap.String("Procedure", req.Spec().Procedure),
				zap.String("Protocol", req.Peer().Protocol),
				zap.String("Addr", req.Peer().Addr),
			)
			return next(ctx, req)
		})
	}
	return connect.UnaryInterceptorFunc(interceptor)
}
```

The code above `next()` processes the request, and the code below processes the response.

Interceptors need to be registered and used.

```go
mux := http.NewServeMux()
mux.Handle(cg.NewHealthCheckServiceHandler(
	controller.NewHealthCheckServiceServer(),
	connect.WithInterceptors(
		interceptor.NewLoggingInterceptor(),
	),
))
```

* [https://connect.build/docs/go/interceptors/](https://connect.build/docs/go/interceptors/)
    

## Wrapping Up

The development experience with Connect is truly amazing, so we highly recommend giving it a try. In the future, we plan to share the validation results of Connect-Web, so stay tuned.
