Skip to content

Commit

Permalink
Merge pull request #40 from tgracchus/add_new_http_proxy_detailed
Browse files Browse the repository at this point in the history
Add NewHttpProxyDetailed method so it's easier to inject custom respo…
  • Loading branch information
kpacha authored Sep 8, 2017
2 parents 090c9cd + f0085ce commit 8c47f9e
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 10 deletions.
10 changes: 10 additions & 0 deletions proxy/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ type EntityFormatter interface {
Format(entity Response) Response
}

// EntityFormatterFunc holds the formatter function
type EntityFormatterFunc struct {
Func func(Response) Response
}

// Format implements the EntityFormatter interface
func (e EntityFormatterFunc) Format(entity Response) Response {
return e.Func(entity)
}

type propertyFilter func(entity *Response)

type entityFormatter struct {
Expand Down
65 changes: 55 additions & 10 deletions proxy/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/devopsfaith/krakend/config"
"github.com/devopsfaith/krakend/encoding"
"io"
)

// ErrInvalidStatusCode is the error returned by the http proxy when the received status code
Expand Down Expand Up @@ -49,9 +50,59 @@ func NewHTTPProxy(remote *config.Backend, clientFactory HTTPClientFactory, decod
}

// NewHTTPProxyWithHTTPExecutor creates a http proxy with the injected configuration, HTTPRequestExecutor and Decoder
func NewHTTPProxyWithHTTPExecutor(remote *config.Backend, requestExecutor HTTPRequestExecutor, decode encoding.Decoder) Proxy {
formatter := NewEntityFormatter(remote.Target, remote.Whitelist, remote.Blacklist, remote.Group, remote.Mapping)
func NewHTTPProxyWithHTTPExecutor(remote *config.Backend, requestExecutor HTTPRequestExecutor, dec encoding.Decoder) Proxy {
ef := NewEntityFormatter(remote.Target, remote.Whitelist, remote.Blacklist, remote.Group, remote.Mapping)
return NewHTTPProxyDetailed(remote, requestExecutor, DefaultHTTPStatusHandler, DefaultHTTPResponseParserFactory(HTTPResponseParserConfig{dec, ef}))
}

// HTTPResponseParser defines how of the response is parsed from http.Response to Response object
type HTTPResponseParser func(context.Context, *http.Response) (*Response, error)

// DefaultHTTPResponseParserConfig defines a default HTTPResponseParserConfig
var DefaultHTTPResponseParserConfig = HTTPResponseParserConfig{
func(r io.Reader, v *map[string]interface{}) error { return nil },
EntityFormatterFunc{func(entity Response) Response { return entity }},
}

// HTTPResponseParserConfig contains the config for a given HttpResponseParser
type HTTPResponseParserConfig struct {
dec encoding.Decoder
ef EntityFormatter
}

// DefaultHTTPResponseParserFactory creates HTTPResponseParser from a given HTTPResponseParserConfig
type HTTPResponseParserFactory func(HTTPResponseParserConfig) HTTPResponseParser

// DefaultHTTPResponseParserFactory is the default implementation of HTTPResponseParserFactory
func DefaultHTTPResponseParserFactory(cfg HTTPResponseParserConfig) HTTPResponseParser {
return func(ctx context.Context, resp *http.Response) (*Response, error) {
var data map[string]interface{}
err := cfg.dec(resp.Body, &data)
resp.Body.Close()
if err != nil {
return nil, err
}

newResponse := Response{Data: data, IsComplete: true}
newResponse = cfg.ef.Format(newResponse)
return &newResponse, nil
}
}

// HTTPStatusHandler defines how we tread the http response code
type HTTPStatusHandler func(context.Context, *http.Response) (*http.Response, error)

// DefaultHTTPCodeHandler is the default implementation of HTTPStatusHandler
func DefaultHTTPStatusHandler(ctx context.Context, resp *http.Response) (*http.Response, error) {
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
return nil, ErrInvalidStatusCode
}

return resp, nil
}

// NewHTTPProxyDetailed creates a http proxy with the injected configuration, HTTPRequestExecutor, Decoder and HTTPResponseParser
func NewHTTPProxyDetailed(remote *config.Backend, requestExecutor HTTPRequestExecutor, ch HTTPStatusHandler, rp HTTPResponseParser) Proxy {
return func(ctx context.Context, request *Request) (*Response, error) {
requestToBakend, err := http.NewRequest(request.Method, request.URL.String(), request.Body)
if err != nil {
Expand All @@ -69,19 +120,13 @@ func NewHTTPProxyWithHTTPExecutor(remote *config.Backend, requestExecutor HTTPRe
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
return nil, ErrInvalidStatusCode
}

var data map[string]interface{}
err = decode(resp.Body, &data)
resp.Body.Close()
resp, err = ch(ctx, resp)
if err != nil {
return nil, err
}

r := formatter.Format(Response{Data: data, IsComplete: true})
return &r, nil
return rp(ctx, resp)
}
}

Expand Down

0 comments on commit 8c47f9e

Please sign in to comment.