Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var ClientEncodeTemplate = `` /* 3222-byte string literal not displayed */
ClientEncodeTemplate is the template for generating the client-side encoding function for a particular Binding.
View Source
var ClientTemplate = `
// Code generated by truss. DO NOT EDIT.
// Rerunning truss will overwrite this file.
// Version: {{.Version}}
// Version Date: {{.VersionDate}}
// Package http provides an HTTP client for the {{.Service.Name}} service.
package http
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
"context"
{{ if len .HTTPHelper.Methods -}}
"github.com/gogo/protobuf/jsonpb"
{{- end }}
"github.com/go-kit/kit/endpoint"
httptransport "github.com/go-kit/kit/transport/http"
"github.com/pkg/errors"
// This Service
"{{.ImportPath -}} /svc"
pb "{{.PBImportPath -}}"
)
var (
_ = endpoint.Chain
_ = httptransport.NewClient
_ = fmt.Sprint
_ = bytes.Compare
_ = ioutil.NopCloser
_ = io.EOF
)
// New returns a service backed by an HTTP server living at the remote
// instance. We expect instance to come from a service discovery system, so
// likely of the form "host:port".
func New(instance string, options ...httptransport.ClientOption) (pb.{{.Service.Name}}Server, error) {
if !strings.HasPrefix(instance, "http") {
instance = "http://" + instance
}
u, err := url.Parse(instance)
if err != nil {
return nil, err
}
_ = u
{{if not .HTTPHelper.Methods -}}
panic("No HTTP Endpoints, this client will not work, define bindings in your proto definition")
{{- end}}
{{range $method := .HTTPHelper.Methods}}
{{ if $method.Bindings -}}
{{ with $binding := index $method.Bindings 0 -}}
var {{$binding.Label}}Endpoint endpoint.Endpoint
{
{{$binding.Label}}Endpoint = httptransport.NewClient(
"{{$binding.Verb | ToUpper}}",
copyURL(u, "{{$binding.BasePath}}"),
EncodeHTTP{{$binding.Label}}Request,
DecodeHTTP{{$method.Name}}Response,
options...,
).Endpoint()
}
{{- end}}
{{- end}}
{{- end}}
return svc.Endpoints{
{{range $method := .HTTPHelper.Methods -}}
{{ if $method.Bindings -}}
{{ with $binding := index $method.Bindings 0 -}}
{{$method.Name}}Endpoint: {{$binding.Label}}Endpoint,
{{end}}
{{- end}}
{{- end}}
}, nil
}
func copyURL(base *url.URL, path string) *url.URL {
next := *base
next.Path = path
return &next
}
// CtxValuesToSend configures the http client to pull the specified keys out of
// the context and add them to the http request as headers. Note that keys
// will have net/http.CanonicalHeaderKey called on them before being send over
// the wire and that is the form they will be available in the server context.
func CtxValuesToSend(keys ...string) httptransport.ClientOption {
return httptransport.ClientBefore(func(ctx context.Context, r *http.Request) context.Context {
for _, k := range keys {
if v, ok := ctx.Value(k).(string); ok {
r.Header.Set(k, v)
}
}
return ctx
})
}
// HTTP Client Decode
{{range $method := .HTTPHelper.Methods}}
// DecodeHTTP{{$method.Name}}Response is a transport/http.DecodeResponseFunc that decodes
// a JSON-encoded {{GoName $method.ResponseType}} response from the HTTP response body.
// If the response has a non-200 status code, we will interpret that as an
// error and attempt to decode the specific error message from the response
// body. Primarily useful in a client.
func DecodeHTTP{{$method.Name}}Response(_ context.Context, r *http.Response) (interface{}, error) {
defer r.Body.Close()
buf, err := ioutil.ReadAll(r.Body)
if err == io.EOF {
return nil, errors.New("response http body empty")
}
if err != nil {
return nil, errors.Wrap(err, "cannot read http body")
}
if r.StatusCode != http.StatusOK {
return nil, errors.Wrapf(errorDecoder(buf), "status code: '%d'", r.StatusCode)
}
var resp pb.{{GoName $method.ResponseType}}
if err = jsonpb.UnmarshalString(string(buf), &resp); err != nil {
return nil, errorDecoder(buf)
}
return &resp, nil
}
{{end}}
// HTTP Client Encode
{{range $method := .HTTPHelper.Methods}}
{{range $binding := $method.Bindings}}
{{$binding.GenClientEncode}}
{{end}}
{{end}}
func errorDecoder(buf []byte) error {
var w errorWrapper
if err := json.Unmarshal(buf, &w); err != nil {
const size = 8196
if len(buf) > size {
buf = buf[:size]
}
return fmt.Errorf("response body '%s': cannot parse non-json request body", buf)
}
return errors.New(w.Error)
}
type errorWrapper struct {
Error string ` + "`" + `json:"error"` + "`" + `
}
`
View Source
var ServerDecodeTemplate = `` /* 1464-byte string literal not displayed */
ServerDecodeTemplate is the template for generating the server-side decoding function for a particular Binding.
View Source
var ServerTemplate = `
// Code generated by truss. DO NOT EDIT.
// Rerunning truss will overwrite this file.
// Version: {{.Version}}
// Version Date: {{.VersionDate}}
package svc
// This file provides server-side bindings for the HTTP transport.
// It utilizes the transport/http.Server.
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
"io"
"github.com/gogo/protobuf/jsonpb"
"github.com/gogo/protobuf/proto"
"context"
"github.com/gorilla/mux"
"github.com/pkg/errors"
httptransport "github.com/go-kit/kit/transport/http"
// This service
pb "{{.PBImportPath -}}"
)
const contentType = "application/json; charset=utf-8"
var (
_ = fmt.Sprint
_ = bytes.Compare
_ = strconv.Atoi
_ = httptransport.NewServer
_ = ioutil.NopCloser
_ = pb.New{{.Service.Name}}Client
_ = io.Copy
_ = errors.Wrap
)
// MakeHTTPHandler returns a handler that makes a set of endpoints available
// on predefined paths.
func MakeHTTPHandler(endpoints Endpoints, responseEncoder httptransport.EncodeResponseFunc, options ...httptransport.ServerOption) http.Handler {
if responseEncoder == nil {
responseEncoder = EncodeHTTPGenericResponse
}
{{- if .HTTPHelper.Methods}}
serverOptions := []httptransport.ServerOption{
httptransport.ServerBefore(headersToContext),
httptransport.ServerErrorEncoder(errorEncoder),
httptransport.ServerAfter(httptransport.SetContentType(contentType)),
}
serverOptions = append(serverOptions, options...)
{{- end }}
m := mux.NewRouter()
{{range $method := .HTTPHelper.Methods}}
{{range $binding := $method.Bindings}}
m.Methods("{{$binding.Verb | ToUpper}}").Path("{{$binding.PathTemplate}}").Handler(httptransport.NewServer(
endpoints.{{$method.Name}}Endpoint,
DecodeHTTP{{$binding.Label}}Request,
responseEncoder,
serverOptions...,
))
{{- end}}
{{- end}}
return m
}
// ErrorEncoder writes the error to the ResponseWriter, by default a content
// type of application/json, a body of json with key "error" and the value
// error.Error(), and a status code of 500. If the error implements Headerer,
// the provided headers will be applied to the response. If the error
// implements json.Marshaler, and the marshaling succeeds, the JSON encoded
// form of the error will be used. If the error implements StatusCoder, the
// provided StatusCode will be used instead of 500.
func errorEncoder(_ context.Context, err error, w http.ResponseWriter) {
body, _ := json.Marshal(errorWrapper{Error: err.Error()})
if marshaler, ok := err.(json.Marshaler); ok {
if jsonBody, marshalErr := marshaler.MarshalJSON(); marshalErr == nil {
body = jsonBody
}
}
w.Header().Set("Content-Type", contentType)
if headerer, ok := err.(httptransport.Headerer); ok {
for k := range headerer.Headers() {
w.Header().Set(k, headerer.Headers().Get(k))
}
}
code := http.StatusInternalServerError
if sc, ok := err.(httptransport.StatusCoder); ok {
code = sc.StatusCode()
}
w.WriteHeader(code)
w.Write(body)
}
type errorWrapper struct {
Error string ` + "`" + `json:"error"` + "`" + `
}
// httpError satisfies the Headerer and StatusCoder interfaces in
// package github.com/go-kit/kit/transport/http.
type httpError struct {
error
statusCode int
headers map[string][]string
}
func (h httpError) StatusCode() int {
return h.statusCode
}
func (h httpError) Headers() http.Header {
return h.headers
}
// Server Decode
{{range $method := .HTTPHelper.Methods}}
{{range $binding := $method.Bindings}}
{{$binding.GenServerDecode}}
{{end}}
{{end}}
// EncodeHTTPGenericResponse is a transport/http.EncodeResponseFunc that encodes
// the response as JSON to the response writer. Primarily useful in a server.
func EncodeHTTPGenericResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
marshaller := jsonpb.Marshaler{
EmitDefaults: false,
OrigName: true,
}
return marshaller.Marshal(w, response.(proto.Message))
}
// Helper functions
func headersToContext(ctx context.Context, r *http.Request) context.Context {
for k := range r.Header {
// The key is added both in http format (k) which has had
// http.CanonicalHeaderKey called on it in transport as well as the
// strings.ToLower which is the grpc metadata format of the key so
// that it can be accessed in either format
ctx = context.WithValue(ctx, k, r.Header.Get(k))
ctx = context.WithValue(ctx, strings.ToLower(k), r.Header.Get(k))
}
// Tune specific change.
// also add the request url
ctx = context.WithValue(ctx, "request-url", r.URL.Path)
ctx = context.WithValue(ctx, "transport", "HTTPJSON")
return ctx
}
`
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.