github.com/Augustu/go-micro/v2@v2.9.3/api/handler/api/api.go (about)

     1  // Package api provides an http-rpc handler which provides the entire http request over rpc
     2  package api
     3  
     4  import (
     5  	"net/http"
     6  
     7  	goapi "github.com/Augustu/go-micro/v2/api"
     8  	"github.com/Augustu/go-micro/v2/api/handler"
     9  	api "github.com/Augustu/go-micro/v2/api/proto"
    10  	"github.com/Augustu/go-micro/v2/client"
    11  	"github.com/Augustu/go-micro/v2/client/selector"
    12  	"github.com/Augustu/go-micro/v2/errors"
    13  	"github.com/Augustu/go-micro/v2/util/ctx"
    14  )
    15  
    16  type apiHandler struct {
    17  	opts handler.Options
    18  	s    *goapi.Service
    19  }
    20  
    21  const (
    22  	Handler = "api"
    23  )
    24  
    25  // API handler is the default handler which takes api.Request and returns api.Response
    26  func (a *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    27  	bsize := handler.DefaultMaxRecvSize
    28  	if a.opts.MaxRecvSize > 0 {
    29  		bsize = a.opts.MaxRecvSize
    30  	}
    31  
    32  	r.Body = http.MaxBytesReader(w, r.Body, bsize)
    33  	request, err := requestToProto(r)
    34  	if err != nil {
    35  		er := errors.InternalServerError("go.micro.api", err.Error())
    36  		w.Header().Set("Content-Type", "application/json")
    37  		w.WriteHeader(500)
    38  		w.Write([]byte(er.Error()))
    39  		return
    40  	}
    41  
    42  	var service *goapi.Service
    43  
    44  	if a.s != nil {
    45  		// we were given the service
    46  		service = a.s
    47  	} else if a.opts.Router != nil {
    48  		// try get service from router
    49  		s, err := a.opts.Router.Route(r)
    50  		if err != nil {
    51  			er := errors.InternalServerError("go.micro.api", err.Error())
    52  			w.Header().Set("Content-Type", "application/json")
    53  			w.WriteHeader(500)
    54  			w.Write([]byte(er.Error()))
    55  			return
    56  		}
    57  		service = s
    58  	} else {
    59  		// we have no way of routing the request
    60  		er := errors.InternalServerError("go.micro.api", "no route found")
    61  		w.Header().Set("Content-Type", "application/json")
    62  		w.WriteHeader(500)
    63  		w.Write([]byte(er.Error()))
    64  		return
    65  	}
    66  
    67  	// create request and response
    68  	c := a.opts.Client
    69  	req := c.NewRequest(service.Name, service.Endpoint.Name, request)
    70  	rsp := &api.Response{}
    71  
    72  	// create the context from headers
    73  	cx := ctx.FromRequest(r)
    74  	// create strategy
    75  	so := selector.WithStrategy(strategy(service.Services))
    76  
    77  	if err := c.Call(cx, req, rsp, client.WithSelectOption(so)); err != nil {
    78  		w.Header().Set("Content-Type", "application/json")
    79  		ce := errors.Parse(err.Error())
    80  		switch ce.Code {
    81  		case 0:
    82  			w.WriteHeader(500)
    83  		default:
    84  			w.WriteHeader(int(ce.Code))
    85  		}
    86  		w.Write([]byte(ce.Error()))
    87  		return
    88  	} else if rsp.StatusCode == 0 {
    89  		rsp.StatusCode = http.StatusOK
    90  	}
    91  
    92  	for _, header := range rsp.GetHeader() {
    93  		for _, val := range header.Values {
    94  			w.Header().Add(header.Key, val)
    95  		}
    96  	}
    97  
    98  	if len(w.Header().Get("Content-Type")) == 0 {
    99  		w.Header().Set("Content-Type", "application/json")
   100  	}
   101  
   102  	w.WriteHeader(int(rsp.StatusCode))
   103  	w.Write([]byte(rsp.Body))
   104  }
   105  
   106  func (a *apiHandler) String() string {
   107  	return "api"
   108  }
   109  
   110  func NewHandler(opts ...handler.Option) handler.Handler {
   111  	options := handler.NewOptions(opts...)
   112  	return &apiHandler{
   113  		opts: options,
   114  	}
   115  }
   116  
   117  func WithService(s *goapi.Service, opts ...handler.Option) handler.Handler {
   118  	options := handler.NewOptions(opts...)
   119  	return &apiHandler{
   120  		opts: options,
   121  		s:    s,
   122  	}
   123  }