templates

package
v0.0.0-...-21e04d4 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2019 License: MIT Imports: 0 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ClientEncodeTemplate = `` /* 2197-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/ioutil"
	"net/http"
	"net/url"
	"strings"
	"context"

	"github.com/go-kit/kit/endpoint"
	httptransport "github.com/go-kit/kit/transport/http"
	"github.com/pkg/errors"

	{{range $i := .ExternalMessageImports}}
	{{$i}}
	{{- end}}

	// This Service
	"{{.ImportPath -}} /svc"
	pb "{{.PBImportPath -}}"
)

var (
	_ = endpoint.Chain
	_ = httptransport.NewClient
	_ = fmt.Sprint
	_ = bytes.Compare
	_ = ioutil.NopCloser
)

// 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 ...ClientOption) (pb.{{.Service.Name}}Server, error) {
	var cc clientConfig

	for _, f := range options {
		err := f(&cc)
		if err != nil {
			return nil, errors.Wrap(err, "cannot apply option") }
	}

	{{ if .HTTPHelper.Methods }}
		clientOptions := []httptransport.ClientOption{
			httptransport.ClientBefore(
				contextValuesToHttpHeaders(cc.headers)),
		}
	{{ end }}

	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,
						clientOptions...,
					).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
}

type clientConfig struct {
	headers []string
}

// ClientOption is a function that modifies the client config
type ClientOption func(*clientConfig) error

// 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) ClientOption {
	return func(o *clientConfig) error {
		o.headers = keys
		return nil
	}
}

func contextValuesToHttpHeaders(keys []string) httptransport.RequestFunc {
	return 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) {
		buf, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return nil, errors.Wrap(err, "cannot read http body")
		}

		if len(buf) == 0 {
			return nil, errors.New("response http body empty")
		}

		if r.StatusCode != http.StatusOK {
			return nil, errors.Wrapf(errorDecoder(buf), "status code: '%d'", r.StatusCode)
		}

		var resp {{PackageName $method.ResponseType}}.{{GoName $method.ResponseType}}
		if err = json.Unmarshal(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 = `` /* 1696-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"
	"compress/gzip"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"io"

	"context"

    "github.com/rs/cors"
	"github.com/gorilla/mux"
	"github.com/pkg/errors"
	"github.com/json-iterator/go"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/tracing/opentracing"

	stdopentracing "github.com/opentracing/opentracing-go"
	httptransport "github.com/go-kit/kit/transport/http"

	{{range $i := .ExternalMessageImports}}
	{{$i}}
	{{- end}}

	// 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, tracer stdopentracing.Tracer, logger log.Logger) http.Handler {
	{{- if .HTTPHelper.Methods}}
		serverOptions := []httptransport.ServerOption{
			httptransport.ServerBefore(headersToContext),
			httptransport.ServerErrorEncoder(errorEncoder),
			httptransport.ServerErrorLogger(logger),
			httptransport.ServerAfter(httptransport.SetContentType(contentType)),
		}
	{{- end }}
	m := mux.NewRouter()
	
	addTracerOption := func(methodName string) []httptransport.ServerOption {
	    if tracer != nil {
	        return append(serverOptions, httptransport.ServerBefore(opentracing.HTTPToContext(tracer, methodName, logger)))
	    }
	    return serverOptions
	}

	{{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,
				EncodeHTTPGenericResponse,
				addTracerOption("{{$method.SnakeName}}")...,
				//append(serverOptions, httptransport.ServerBefore(opentracing.HTTPToContext(tracer, "{{$method.SnakeName}}", logger)))...,
			))
		{{- end}}
	{{- end}}
    return cors.AllowAll().Handler(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 {
	encoder := jsoniter.ConfigFastest.NewEncoder(w)
	encoder.SetEscapeHTML(false)
	return encoder.Encode(response)
}

// 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))
	}

	// add the access key to context
	accessKey := r.URL.Query().Get("access_key")
	if len(accessKey) > 0{
		ctx = context.WithValue(ctx, "access_key", accessKey)
	}

	// 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.

Jump to

Keyboard shortcuts

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