Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions proxy/middlewear/proxy/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: Apache-2.0

package proxy

import (
"github.com/luraproject/lura/v2/config"
"github.com/luraproject/lura/v2/logging"
"github.com/luraproject/lura/v2/sd"
)

// Factory creates proxies based on the received endpoint configuration.
//
// Both, factories and backend factories, create proxies but factories are designed as a stack makers
// because they are intended to generate the complete proxy stack for a given frontend endpoint
// the app would expose and they could wrap several proxies provided by a backend factory
type Factory interface {
New(cfg *config.EndpointConfig) (Proxy, error)
}

// FactoryFunc type is an adapter to allow the use of ordinary functions as proxy factories.
// If f is a function with the appropriate signature, FactoryFunc(f) is a Factory that calls f.
type FactoryFunc func(*config.EndpointConfig) (Proxy, error)

// New implements the Factory interface
func (f FactoryFunc) New(cfg *config.EndpointConfig) (Proxy, error) { return f(cfg) }

// DefaultFactory returns a default http proxy factory with the injected logger
func DefaultFactory(logger logging.Logger) Factory {
return NewDefaultFactory(httpProxy, logger)
}

// DefaultFactoryWithSubscriber returns a default proxy factory with the injected logger and subscriber factory
func DefaultFactoryWithSubscriber(logger logging.Logger, sF sd.SubscriberFactory) Factory {
return NewDefaultFactoryWithSubscriber(httpProxy, logger, sF)
}

// NewDefaultFactory returns a default proxy factory with the injected proxy builder and logger
func NewDefaultFactory(backendFactory BackendFactory, logger logging.Logger) Factory {
sf := func(remote *config.Backend) sd.Subscriber {
return sd.GetRegister().Get(remote.SD)(remote)
}
return NewDefaultFactoryWithSubscriber(backendFactory, logger, sf)
}

// NewDefaultFactoryWithSubscriber returns a default proxy factory with the injected proxy builder,
// logger and subscriber factory
func NewDefaultFactoryWithSubscriber(backendFactory BackendFactory, logger logging.Logger, sF sd.SubscriberFactory) Factory {
return defaultFactory{backendFactory, logger, sF}
}

type defaultFactory struct {
backendFactory BackendFactory
logger logging.Logger
subscriberFactory sd.SubscriberFactory
}

// New implements the Factory interface
func (pf defaultFactory) New(cfg *config.EndpointConfig) (p Proxy, err error) {
switch len(cfg.Backend) {
case 0:
err = ErrNoBackends
case 1:
p, err = pf.newSingle(cfg)
default:
p, err = pf.newMulti(cfg)
}
if err != nil {
return
}

p = NewPluginMiddleware(pf.logger, cfg)(p)
p = NewStaticMiddleware(pf.logger, cfg)(p)
return
}

func (pf defaultFactory) newMulti(cfg *config.EndpointConfig) (p Proxy, err error) {
backendProxy := make([]Proxy, len(cfg.Backend))
for i, backend := range cfg.Backend {
backendProxy[i] = pf.newStack(backend)
}
p = NewMergeDataMiddleware(pf.logger, cfg)(backendProxy...)
p = NewFlatmapMiddleware(pf.logger, cfg)(p)
return
}

func (pf defaultFactory) newSingle(cfg *config.EndpointConfig) (Proxy, error) {
return pf.newStack(cfg.Backend[0]), nil
}

func (pf defaultFactory) newStack(backend *config.Backend) (p Proxy) {
p = pf.backendFactory(backend)
p = NewBackendPluginMiddleware(pf.logger, backend)(p)
p = NewGraphQLMiddleware(pf.logger, backend)(p)
p = NewFilterHeadersMiddleware(pf.logger, backend)(p)
p = NewLoadBalancedMiddlewareWithSubscriberAndLogger(pf.logger, pf.subscriberFactory(backend))(p)
if backend.ConcurrentCalls > 1 {
p = NewConcurrentMiddlewareWithLogger(pf.logger, backend)(p)
}
p = NewRequestBuilderMiddlewareWithLogger(pf.logger, backend)(p)
// we need to filter the input query strings before the request is constructed
// so the query strings are properly added to the URL:
p = NewFilterQueryStringsMiddleware(pf.logger, backend)(p)
return
}
19 changes: 19 additions & 0 deletions proxy/middlewear/proxy/registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package middleware

import "github.com/luraproject/lura/proxy"

// ProxyMiddleware wraps a proxy function
type ProxyMiddleware func(proxy.Proxy) proxy.Proxy

var registry = map[string]ProxyMiddleware{}

// Register allows custom middlewares to be added
func Register(name string, mw ProxyMiddleware) {
registry[name] = mw
}

// Get retrieves a middleware by name
func Get(name string) (ProxyMiddleware, bool) {
mw, ok := registry[name]
return mw, ok
}