Skip to content

curioswitch/go-docs-handler

Repository files navigation

go-docs-handler

go-docs-handler is a net/http handler that serves documentation for API services written in Go. The client is the same as the excellent Armeria docs client, with the server-side handling of specification requests reimplemented with net/http.

Setup

go-docs-handler aims to support different frameworks generically by using framework-specific plugins. Currently only gRPC using either Connect or official gRPC are supported.

Connect

Support for Connect is provided by the proto plugin, which reads definitions from the global protobuf registry. It does not actually have any dependencies on Connect itself and can be used with other implementations of protobuf-based RPC. If anyone has a framework that works with it, let us know so we can add docs and examples for it.

go get github.com/curioswitch/go-docs-handler/plugins/proto
import "github.com/curioswitch/go-docs-handler/plugins/proto"

func main() {
	mux := http.NewServeMux()
	
	// Register the connect handler as usual
	mux.Handle(greetconnect.NewGreetServiceHandler(&greetService{}))
	
	docsHandler, err := docshandler.New(protodocs.NewPlugin(greetconnect.GreetServiceName))
	if err != nil {
		panic(err)
	}
	
	// Register the docs handler onto the same mux. It's recommended to give it a prefix.
	mux.Handle("/docs/", http.StripPrefix("/docs", docsHandler))
	
	http.ListenAndServe(":8080", mux)
}

Documentation will be served on http://localhost:8080/docs/ and debug requests will be served by the registered handler. Note that services are registered to documentation by name as there is no way to introspect what connect services have been registered on a mux. If the service name(s) used when initializing the plugin do not match the actual handlers, documentation will be served for the unrelated service and debug requests will fail.

Also see a full example here.

gRPC

Support for gRPC is provided by the gRPC plugin, which reads registered services from a grpc.Server and uses the global registry to resolve their details. The gRPC server uses a custom HTTP stack and protocol and cannot be used to serve docs or debug requests. The docs handler should be registered on a separate HTTP port, which will also serve debug requests from the browser, proxying them to the gRPC server. Currently, the docs handler must be served at the root when using the gRPC plugin.

go get github.com/curioswitch/go-docs-handler/plugins/grpc
import "github.com/curioswitch/go-docs-handler/plugins/grpc"

func main() {
	server := grpc.NewServer()
	greet.RegisterGreetServiceServer(server, service{})
	
	mux := http.NewServeMux()
	
	
	docsHandler, err := docshandler.New(grpcdocs.NewPlugin(server))
	if err != nil {
		panic(err)
	}
	
	go func() {
		http.ListenAndServe(":8081", docsHandler)
	}

	list, _ := net.Listen("tcp", ":8080")
	server.Serve(list)
}

Documentation will be served on http://localhost:8081/ and debug requests will be served by the registered handler, proxied through the docs handler.

Also see a full example here.

Descriptor Set

The docs handler can utilize a serialized descriptor set to augment documentation with the comments from a proto source file. It is strongly recommended to do this to make the documentation more useful.

A descriptor set can be generated by protoc together with any other code. Source info and imports must be included.

protoc --descriptor_set_out=descriptors.pb --include_source_info --include_imports --proto_path=. --go_out=. greet.proto

The serialized descriptors can be loaded with the WithSerializedDescriptors option when initializing a plugin. It is recommended to go:embed them into the binary to ensure they are accessible.