🖍 Http server with Connectrpc, Gin and std package

This memo shows how ServeMux of golang is possible to serve multi features such as the connectrpc, gin and standard http func

Overview 

This example shows how to serve multiple communication protocols by a single port. The buf command generates the boilerplate code. The connect RPC protocol serves the gRPc function. Also, http/1 GET and Gin, which satisfy the standard ServeHTTP function, are served.

Prerequirement 

These tools and a protcol is used.

Example Dir Structure 

Example dirs and files are here.

Makefile
go.mod
go.sum
api/
    buf.yml                    ... buf configuration files
    buf.gen.yml
    proto/hello/v1
            hello.proto        ... grpc and protobuf definitions

rpc/hello/v1/                  ... generated codes
          hello.pb.go
          v1connect/
             hello.connect.go

cmd/
   main.go                     ... example code
 main.go
package main

import (
	"context"
	"fmt"
	"log"
	"net/http"

	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c"

	"connectrpc.com/connect"
	"github.com/gin-gonic/gin"

	helo "example.com/connrpcothr/rpc/hello/v1"
	conn "example.com/connrpcothr/rpc/hello/v1/v1connect"
)

type Server struct{}

func (s *Server) Greet(c context.Context, in *connect.Request[helo.Request]) (*connect.Response[helo.Response], error) {
	return connect.NewResponse(&helo.Response{Msg: fmt.Sprintf("Greet :%v", in.Msg.Text)}), nil
}

func main() {
	mux := http.NewServeMux()

	// connectrpc
	s := &Server{}
	path, hdr := conn.NewHeloServiceHandler(s)
	mux.Handle(path, hdr)
	log.Printf("HeloService Path: %v", path)

	// std
	ptn := "GET /std/n/{num}"
	mux.Handle(ptn, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		txt := r.PathValue("num")
		w.Header().Set("Content-Type", "plain/text")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(fmt.Sprintf("std: %s", txt)))
	}))
	log.Printf("Std : %s", ptn)

	// gin
	egn := gin.Default()
	api := egn.Group("api/v1")

	api.GET("/h/:text", func(c *gin.Context) {
		txt := c.Param("text")
		c.JSON(http.StatusOK, gin.H{
			"msg": fmt.Sprintf("gin: %s", txt),
		})
	})
	mux.Handle("/", egn)

	if err := http.ListenAndServe("localhost:8080", h2c.NewHandler(mux, &http2.Server{})); err != nil {
		log.Fatalf("down: %v", err)
	}
}

Confirmation 

This example code confirms whether it’s possible to serve each protocol such as connectrpc, grpc and rest.

gRPC proto 

syntax = "proto3";

package hello.v1;

option go_package = "example.com/connrpcothr/rpc/hello/v1";

message Request {
  string text = 1;
}

message Response {
  string msg = 1;
}

service HeloService {
  rpc Greet(Request) returns (Response) {}
}

Connectrpc 

type Server struct{}

func (s *Server) Greet(c context.Context, in *connect.Request[helo.Request])
 (*connect.Response[helo.Response], error) {
	return connect.NewResponse(&helo.Response{Msg: fmt.Sprintf("Greet :%v", in.Msg.Text)}), nil
}

Standard Package 

ptn := "GET /std/n/{num}"
mux.Handle(ptn, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    txt := r.PathValue("num")
    w.Header().Set("Content-Type", "plain/text")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte(fmt.Sprintf("std: %s", txt)))
}))
log.Printf("Std : %s", ptn)

Gin 

egn := gin.Default()
api := egn.Group("api/v1")

api.GET("/h/:text", func(c *gin.Context) {
    txt := c.Param("text")
    c.JSON(http.StatusOK, gin.H{
        "msg": fmt.Sprintf("gin: %s", txt),
    })
})
mux.Handle("/", egn)

Call Each Endpoints 

To call each endpoint, boot the exmple server.

go run ./cmd/main.go
2025/01/11 19:25:38 HeloService Path: /hello.v1.HeloService/
2025/01/11 19:25:38 Std : GET /std/n/{num}
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /api/v1/h/:text           --> main.main.func2 (3 handlers)

Http   Connectrpc   Gin   net/http  

Memo / Api / Http server with Connectrpc, Gin and std package