Grpc-gateway offers solutions for customizing response body using google.api.HttpBody
(non-json content type like text/plain
, application/xml
, etc), however, this proto message cannot deal with request body.
Asked
Active
Viewed 978 times
1

alter_igel
- 6,899
- 3
- 21
- 40

vincenthuangwz
- 21
- 3
-
Does this address your question https://github.com/googleapis/googleapis/blob/869d32e2f0af2748ab530646053b23a2b80d9ca5/google/api/http.proto#L61-L87 – San P Jul 27 '22 at 18:40
-
@SanP Nope. It only addresses how to read request parameters. – vincenthuangwz Jul 28 '22 at 04:47
1 Answers
0
Inspired by johanbrandhorst' comment, I came up with a solution with a customized marshaler. I implemented interfaces of runtime.marshaler to create my own marshaler.
Custiomized marshaler
package marshaler
import (
"errors"
"io"
"io/ioutil"
"log"
"reflect"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/genproto/googleapis/api/httpbody"
)
type XMLMarshaler struct {
runtime.Marshaler
}
func (x XMLMarshaler) ContentType(_ interface{}) string {
return "application/xml"
}
func (x XMLMarshaler) Marshal(v interface{}) ([]byte, error) {
log.Println("xml marshal")
log.Printf("param: %+v", v)
// return xml.Marshal(v)
if httpBody, ok := v.(*httpbody.HttpBody); ok {
return httpBody.Data, nil
}
return x.Marshaler.Marshal(v)
}
func (x XMLMarshaler) NewDecoder(r io.Reader) runtime.Decoder {
log.Println("xml new decoder")
return runtime.DecoderFunc(func(p interface{}) error {
buffer, err := ioutil.ReadAll(r)
if err != nil {
return err
}
pType := reflect.TypeOf(p)
if pType.Kind() == reflect.Ptr {
v := reflect.Indirect(reflect.ValueOf(p))
if v.Kind() == reflect.String {
v.Set(reflect.ValueOf(string(buffer)))
return nil
}
}
return errors.New("value type error")
})
}
starting grpc-gateway
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// Register gRPC server endpoint
// Note: Make sure the gRPC server is running properly and accessible
mux := runtime.NewServeMux(
runtime.WithMarshalerOption("application/xml", marshaler.XMLMarshaler{}),
)
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
err := gw.RegisterBotServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)
if err != nil {
return err
}
// Start HTTP server (and proxy calls to gRPC server endpoint)
return http.ListenAndServe(":8080", mux)
}
Then, for all requests with content type specified as "application/xml", grpc-gateway
will assign the XML body data to google.api.HttpBody.Data. And, for non-json responses, grpc-gateway
will assign google.api.HttpBody.Data to response body.

vincenthuangwz
- 21
- 3