go-proto-http

module
v0.0.0-...-2848160 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 10, 2020 License: MIT

README

protoc-gen-go-http

This protobuf code generator generates Go HTTP bindings for RPC services defined in .proto files. It uses Google API HTTP protobuf extension to resolve HTTP parameters (path, method etc) for each method and creates Go http.Handler to apply routing, marshalling and unmarshalling.

Only few basic features of Google API HTTP annotations are supported at the moment:

  • All HTTP methods including custom
  • Simple URL parameters for example get=/users/{user_id}/comments/{comment_id}
  • Simple request body parsing (no body, body='*' and body='argument_name')
  • Basic query parameters of type: string, int, float
  • GRPC to HTTP status code mapping
  • Additional bindings (additional_binding annotation to define more than one HTTP binding)

This code generator does not intend to generate perfect RESTful API (use all of the Status Codes, Headers, Query parameters, Content Type Negotiation etc). The idea of this code generator is to provide "good enough" HTTP API on backed by the very same server implementation used by GRPC server, so you can have one server implementation and multiple network bindings.

Installation

go install github.com/eolymp/go-proto-http/cmd/protoc-gen-go-http

Usage

Just like with any other code generator you need to run protoc with go-http_out flag. This code generator requires data structures and interfaces generated by go and go-grpc code generators, so they should be enabled too.

protoc --go_out=build  --go-grpc_out=build --go-http_out=build your.proto

You can find full example in /example folder

Let's say we have proto file which defines following UserManager service:

service UserManager {
    rpc CreateUser (CreateUserInput) returns (CreateUserOutput) {
        option (google.api.http) = { post: "/users" body: "*" };
    }

    rpc DeleteUser (DeleteUserInput) returns (DeleteUserOutput) {
        option (google.api.http) = { delete: "/users/{user_id}" };
    }

    rpc GetComments (GetCommentsInput) returns (GetCommentsOutput) {
        option (google.api.http) = { get: "/users/{user_id}/comments" };
    }

    rpc CreateComment (CreateCommentInput) returns (CreateCommentOutput) {
        option (google.api.http) = { post: "/users/{user_id}/comments" body: "comment" };
    }
}

From annotations in this file protoc-gen-go-http will generate an http.Handler which would handler routing (using mux package) and converting http.Request into corresponding protobuf data structures.

Generated code looks something like this:

// ...

// NewUserManagerHandler constructs new http.Handler for UserManagerServer
func NewUserManagerHandler(srv UserManagerServer) http.Handler {
	router := mux.NewRouter()
	router.Handle("/users", _UserManager_CreateUser_HTTP_Handler(srv)).Methods("POST")
	router.Handle("/users/{user_id}", _UserManager_DeleteUser_HTTP_Handler(srv)).Methods("DELETE")
	router.Handle("/users/{user_id}/comments", _UserManager_GetComments_HTTP_Handler(srv)).Methods("GET")
	router.Handle("/users/{user_id}/comments", _UserManager_CreateComment_HTTP_Handler(srv)).Methods("POST")
	return router
}

// ...

func _UserManager_CreateComment_HTTP_Handler(srv UserManagerServer) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		in := &CreateCommentInput{}

		in.Comment = &Comment{}
		if err := _UserManager_HTTPReadRequestBody(r, in.Comment); err != nil {
			_UserManager_HTTPWriteErrorResponse(w, err)
			return
		}

		vars := mux.Vars(r)
		in.UserId = vars["user_id"]

		out, err := srv.CreateComment(r.Context(), in)
		if err != nil {
			_UserManager_HTTPWriteErrorResponse(w, err)
			return
		}

		_UserManager_HTTPWriteResponse(w, out)
	})
}

Then, generated HTTP handler can be used in your application with HTTP server:

router := mux.NewRouter()

router.PathPrefix("/users").
	Handler(userspb.NewUserManagerHandler(users.NewServer(db.DB)))

srv := &http.Server{
	Addr:    ":8080",
	Handler: router,
}

if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
	log.Fatal("HTTP api has failed:", err)
}

Directories

Path Synopsis
cmd
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL