Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send error response according to Backend response #31

Closed
ricmoreira opened this issue Aug 16, 2018 · 16 comments
Closed

Send error response according to Backend response #31

ricmoreira opened this issue Aug 16, 2018 · 16 comments
Labels

Comments

@ricmoreira
Copy link

Hello,

I'm finding difficult to get an working example for getting error responses according to backend response and not the default 500 error response.

I've implemented my Gateway according to your Gin example and, at the moment, it is like this:

package main

import (
	"flag"
	"log"
	"os"
	"time"

	"github.com/gin-gonic/gin"
	"gopkg.in/gin-contrib/cors.v1"

	"api_gateway_admin/middleware"

	"github.com/devopsfaith/krakend/config"
	"github.com/devopsfaith/krakend/logging"
	"github.com/devopsfaith/krakend/proxy"
	krakendgin "github.com/devopsfaith/krakend/router/gin"
)

func main() {
	port := flag.Int("p", 0, "Port of the service")
	logLevel := flag.String("l", "ERROR", "Logging level")
	debug := flag.Bool("d", false, "Enable the debug")
	configFile := flag.String("c", "{{path to file}}/configuration.json", "Path to the configuration filename")
	flag.Parse()

	parser := config.NewParser()
	serviceConfig, err := parser.Parse(*configFile)
	if err != nil {
		log.Fatal("ERROR:", err.Error())
	}
	serviceConfig.Debug = serviceConfig.Debug || *debug
	if *port != 0 {
		serviceConfig.Port = *port
	}

	logger, err := logging.NewLogger(*logLevel, os.Stdout, "[KRAKEND]")
	if err != nil {
		log.Println("ERROR:", err.Error())
		return
	}

	routerFactory := krakendgin.NewFactory(krakendgin.Config{
		Engine:         gin.Default(),
		ProxyFactory:   customProxyFactory{logger, proxy.DefaultFactory(logger)},
		Logger:         logger,
		HandlerFactory: krakendgin.EndpointHandler,
		Middlewares: []gin.HandlerFunc{
			cors.New(cors.Config{
				AllowOrigins: []string{"http://localhost:4200", "http://127.0.0.1:4200", "http://localhost:8089", "http://localhost:8069", "http://localhost:8080", "http://localhost:8099"},
				AllowMethods: []string{"PUT", "PATCH", "POST", "GET", "DELETE", "OPTIONS"},
				AllowHeaders: []string{"Accept",
					"Accept-Encoding",
					"Accept-Language",
					"access-control-allow-origin",
					"Access-Control-Request-Headers",
					"Access-Control-Request-Method",
					"authorization",
					"Cache-Control",
					"Connection",
					"Content-Type",
					"Host",
					"If-Modified-Since",
					"Keep-Alive",
					"Key",
					"Origin",
					"Pragma",
					"User-Agent",
					"X-Custom-Header"},
				ExposeHeaders:    []string{"Content-Length", "Content-Type"},
				AllowCredentials: true,
				MaxAge:           48 * time.Hour,
			}),
			middleware.JwtCheck(),
		},
	})

	routerFactory.New().Run(serviceConfig)
}

// customProxyFactory adds a logging middleware wrapping the internal factory
type customProxyFactory struct {
	logger  logging.Logger
	factory proxy.Factory
}

// New implements the Factory interface
func (cf customProxyFactory) New(cfg *config.EndpointConfig) (p proxy.Proxy, err error) {
	p, err = cf.factory.New(cfg)
	if err == nil {
		p = proxy.NewLoggingMiddleware(cf.logger, cfg.Endpoint)(p)
	}
	return
}

Could you please help me out on what should I change here?
Thank you.

@taik0
Copy link
Member

taik0 commented Aug 16, 2018

Hi @ricmoreira

Check this link for information about this behaviour:
http://www.krakend.io/docs/faq/#i-am-getting-a-500-status-when-the-backend-returns-anything-but-200-201-or-redirects.

Although now you can use the NoOpHTTPStatusHandler to send the same response of the backend.

@ricmoreira
Copy link
Author

Thank you for the quick response.
I've been through that documentation and I've understood that I've to inject my "own HTTPStatusHandler". In this case, as you said, the "NoOpHTTPStatusHandler" would solve my issue.
But where do I put it?

@taik0
Copy link
Member

taik0 commented Aug 16, 2018

You need to add your own custom BackendFactory if you are not using the default Factories.

NewHTTPProxyDetailed will allow you to add your custom status handler.

Check this link for an example:
luraproject/lura#102 (comment)

@ricmoreira
Copy link
Author

This is what I've done now:

(...)
	backendFactory := func(backendCfg *config.Backend) proxy.Proxy {

		ns := proxy.NoOpHTTPStatusHandler

		// the default request executor
		re := proxy.DefaultHTTPRequestExecutor(proxy. NewHTTPClient)
	
		// default entity formatter for the given backend
		ef := proxy.NewEntityFormatter(backendCfg)
	
		// the default response parser with the required config
		rp := proxy.DefaultHTTPResponseParserFactory(proxy.HTTPResponseParserConfig{backendCfg.Decoder, ef})
	
		// build and return the new backend proxy
		return proxy.NewHTTPProxyDetailed(backendCfg, re, ns, rp)
	}

	// build the pipes on top of the custom backend factory
	proxyFactory := proxy.NewDefaultFactory(backendFactory, logger)

	routerFactory := krakendgin.NewFactory(krakendgin.Config{
		Engine:         gin.Default(),
		ProxyFactory:   proxyFactory,

(...)

I've managed to get the response body but now an error response (e.g. 400) is transformed to a 200 response.

@kpacha
Copy link
Member

kpacha commented Aug 17, 2018

hi, @ricmoreira

the renders are responsible for the behaviour you're describing (as you can see here: https://github.com/devopsfaith/krakend/blob/master/router/gin/render.go#L90) but you can inject your own render at the router level by registering it with gin.RegisterRender and adding its name in the endpoint configuration (config.EndpointConfig.OutputEncoding).

your implementation should copy the proxy.Response.Metadata.StatusCode like in https://github.com/devopsfaith/krakend/blob/master/router/gin/render.go#L124

on the other hand, please notice you can use the CORS module already available in the master branch. the JOSE package is not ready yet, but we expect to finish it in a couple of weeks.

cheers!

@ricmoreira
Copy link
Author

Hello,

I have finally a working example:

package main

import (
	"flag"
	"io"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/gin-gonic/gin"
	"gopkg.in/gin-contrib/cors.v1"

	"api_gateway_admin/middleware"

	"github.com/devopsfaith/krakend/config"
	"github.com/devopsfaith/krakend/logging"
	"github.com/devopsfaith/krakend/proxy"
	krakendgin "github.com/devopsfaith/krakend/router/gin"
)

func main() {
	port := flag.Int("p", 0, "Port of the service")
	logLevel := flag.String("l", "ERROR", "Logging level")
	debug := flag.Bool("d", false, "Enable the debug")
	configFile := flag.String("c", "{{path to file}}/configuration.json", "Path to the configuration filename")
	flag.Parse()

	parser := config.NewParser()
	serviceConfig, err := parser.Parse(*configFile)
	if err != nil {
		log.Fatal("ERROR:", err.Error())
	}

	// render that does not change response
	noTransformRender := func(c *gin.Context, response *proxy.Response) {
		if response == nil {
			c.Status(http.StatusInternalServerError)
			return
		}
		c.Status(response.Metadata.StatusCode)
		for k, v := range response.Metadata.Headers {
			c.Header(k, v[0])
		}
		io.Copy(c.Writer, response.Io)
	}

	// register the render at the router level
	krakendgin.RegisterRender("NoTransformRender", noTransformRender)

	// assign NoTransformRender to all endpoints loaded from config file
	for _, v := range serviceConfig.Endpoints {
		v.OutputEncoding = "NoTransformRender"
	}

	serviceConfig.Debug = serviceConfig.Debug || *debug
	if *port != 0 {
		serviceConfig.Port = *port
	}

	logger, err := logging.NewLogger(*logLevel, os.Stdout, "[KRAKEND]")
	if err != nil {
		log.Println("ERROR:", err.Error())
		return
	}

	backendFactory := func(backendCfg *config.Backend) proxy.Proxy {

		// status handler that does change status
		ns := proxy.NoOpHTTPStatusHandler

		// the default request executor
		re := proxy.DefaultHTTPRequestExecutor(proxy.NewHTTPClient)

		// response parser that copies Backend response body to proxy Response IO reader
		rp := proxy.NoOpHTTPResponseParser

		// build and return the new backend proxy
		return proxy.NewHTTPProxyDetailed(backendCfg, re, ns, rp)
	}

	// build the pipes on top of the custom backend factory
	proxyFactory := proxy.NewDefaultFactory(backendFactory, logger)

	engine := gin.Default()

	routerConfig := krakendgin.Config{
		Engine:         engine,
		ProxyFactory:   proxyFactory,
		Logger:         logger,
		HandlerFactory: krakendgin.EndpointHandler,
		Middlewares: []gin.HandlerFunc{
			cors.New(cors.Config{
				AllowOrigins: []string{"http://localhost:4200", "http://127.0.0.1:4200", "http://localhost:8089", "http://localhost:8069", "http://localhost:8080", "http://localhost:8099"},
				AllowMethods: []string{"PUT", "PATCH", "POST", "GET", "DELETE", "OPTIONS"},
				AllowHeaders: []string{"Accept",
					"Accept-Encoding",
					"Accept-Language",
					"access-control-allow-origin",
					"Access-Control-Request-Headers",
					"Access-Control-Request-Method",
					"authorization",
					"Cache-Control",
					"Connection",
					"Content-Type",
					"Host",
					"If-Modified-Since",
					"Keep-Alive",
					"Key",
					"Origin",
					"Pragma",
					"User-Agent",
					"X-Custom-Header"},
				ExposeHeaders:    []string{"Content-Length", "Content-Type"},
				AllowCredentials: true,
				MaxAge:           48 * time.Hour,
			}),
			middleware.JwtCheck(),
		},
	}

	routerFactory := krakendgin.NewFactory(routerConfig)

	routerFactory.New().Run(serviceConfig)
}

Thank you very much for your quick feedback.
Congrats for your great project.

Thanks!

@kpacha
Copy link
Member

kpacha commented Aug 17, 2018

@ricmoreira that's amazing!

remember you can avoid some of that code by just defining the extra_config for the CORS module like in this example: https://github.com/devopsfaith/krakend-cors#configuration-example

also, you can add "output_encoding": "NoTransformRender" to each endpoint definition in the same config file, so you'll have more control.

enjoy playing with the KrakenD!!!

@ricmoreira
Copy link
Author

Thank you very much!
Much better now.

I'll leave here my main and my config file for whoever needs an example.

main.go

package main

import (
	"flag"
	"io"
	"log"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"

	"api_gateway_admin/middleware"

	"github.com/devopsfaith/krakend/config"
	"github.com/devopsfaith/krakend/logging"
	"github.com/devopsfaith/krakend/proxy"
	krakendgin "github.com/devopsfaith/krakend/router/gin"
)

func main() {
	port := flag.Int("p", 0, "Port of the service")
	logLevel := flag.String("l", "ERROR", "Logging level")
	debug := flag.Bool("d", false, "Enable the debug")
	configFile := flag.String("c", "{{path to file}}/configuration.json", "Path to the configuration filename")
	flag.Parse()

	parser := config.NewParser()
	serviceConfig, err := parser.Parse(*configFile)
	if err != nil {
		log.Fatal("ERROR:", err.Error())
	}

	// render that does not change response
	noTransformRender := func(c *gin.Context, response *proxy.Response) {
		if response == nil {
			c.Status(http.StatusInternalServerError)
			return
		}
		c.Status(response.Metadata.StatusCode)
		for k, v := range response.Metadata.Headers {
			c.Header(k, v[0])
		}
		io.Copy(c.Writer, response.Io)
	}

	// register the render at the router level
	krakendgin.RegisterRender("NoTransformRender", noTransformRender)

	serviceConfig.Debug = serviceConfig.Debug || *debug
	if *port != 0 {
		serviceConfig.Port = *port
	}

	logger, err := logging.NewLogger(*logLevel, os.Stdout, "[KRAKEND]")
	if err != nil {
		log.Println("ERROR:", err.Error())
		return
	}

	backendFactory := func(backendCfg *config.Backend) proxy.Proxy {

		// status handler that does change status
		ns := proxy.NoOpHTTPStatusHandler

		// the default request executor
		re := proxy.DefaultHTTPRequestExecutor(proxy.NewHTTPClient)

		// response parser that copies Backend response body to proxy Response IO reader
		rp := proxy.NoOpHTTPResponseParser

		// build and return the new backend proxy
		return proxy.NewHTTPProxyDetailed(backendCfg, re, ns, rp)
	}

	// build the pipes on top of the custom backend factory
	proxyFactory := proxy.NewDefaultFactory(backendFactory, logger)

	engine := gin.Default()

	routerConfig := krakendgin.Config{
		Engine:         engine,
		ProxyFactory:   proxyFactory,
		Logger:         logger,
		HandlerFactory: krakendgin.EndpointHandler,
		Middlewares: []gin.HandlerFunc{
			middleware.JwtCheck(),
		},
	}

	routerFactory := krakendgin.NewFactory(routerConfig)

	routerFactory.New().Run(serviceConfig)
}

configuration.json

{
  "version": 2,
  "name": "ecommerce-service",
  "port": 8080,
  "cache_ttl": "1s",
  "timeout": "10s",
  "host": [
    "http://localhost"
  ],
  "extra_config": {
    "github_com/devopsfaith/krakend-cors": {
      "allow_origins": [ "http://localhost:4200", "http://127.0.0.1:4200", "http://localhost:8089", "http://localhost:8069", "http://localhost:8080", "http://localhost:8099" ],
      "allow_methods": [ "PUT", "PATCH", "POST", "GET", "DELETE", "OPTIONS"],
      "allow_heathers": [ "Accept-Encoding",
        "Accept-Language",
        "access-control-allow-origin",
        "Access-Control-Request-Headers",
        "Access-Control-Request-Method",
        "authorization",
        "Cache-Control",
        "Connection",
        "Content-Type",
        "Host",
        "If-Modified-Since",
        "Keep-Alive",
        "Key",
        "Origin",
        "Pragma",
        "User-Agent",
        "X-Custom-Header"],
      "max_age": "48h",
      "allow_credentials": true,
      "expose_headers": ["Content-Length", "Content-Type"]
    }
  },
  "endpoints": [
    {
      "endpoint": "/api/v1/product",
      "timeout": "800ms",
      "method": "POST",
      "backend": [
        {
          "url_pattern": "/api/v1/product",
          "host": [
            "http://localhost:8069"
          ]
        }
      ],
      "output_encoding": "NoTransformRender"
    },
    {
      "endpoint": "/api/v1/product",
      "timeout": "800ms",
      "method": "GET",
      "querystring_params": [
        "page",
        "per_page"
      ],
      "backend": [
        {
          "url_pattern": "/api/v1/product",
          "host": [
            "http://localhost:8069"
          ]
        }
      ],
      "output_encoding": "NoTransformRender"
    },
    {
      "endpoint": "/api/v1/saft/upload",
      "timeout": "800ms",
      "method": "POST",
      "headers_to_pass": [
        "content-type",
        "Content-Type"
      ],
      "backend": [
        {
          "url_pattern": "/api/v1/saft/upload",
          "host": [
            "http://localhost:8099"
          ]
        }
      ],
      "output_encoding": "NoTransformRender"
    }
  ]
}

@dominiksimek
Copy link

Hello,
I'm trying to modify default krakend-ce backendFactory to make it works with NoOpHTTPStatusHandler. Original backendFactory code is (backend_factory.go):

// NewBackendFactory creates a BackendFactory by stacking all the available middlewares:
// - oauth2 client credentials
// - martian
// - rate-limit
// - circuit breaker
// - metrics collector
// - opencensus collector
func NewBackendFactory(logger logging.Logger, metricCollector *metrics.Metrics) proxy.BackendFactory {
	requestExecutorFactory := func(cfg *config.Backend) client.HTTPRequestExecutor {
		var clientFactory client.HTTPClientFactory
		if _, ok := cfg.ExtraConfig[oauth2client.Namespace]; ok {
			clientFactory = oauth2client.NewHTTPClient(cfg)
		} else {
			clientFactory = httpcache.NewHTTPClient(cfg)
		}
		return opencensus.HTTPRequestExecutor(clientFactory)
	}
	backendFactory := martian.NewConfiguredBackendFactory(logger, requestExecutorFactory)
	backendFactory = juju.BackendFactory(backendFactory)
	backendFactory = cb.BackendFactory(backendFactory)
	backendFactory = metricCollector.BackendFactory("backend", backendFactory)
	backendFactory = opencensus.BackendFactory(backendFactory)
	return backendFactory
}

Is it possible to use NoOpHTTPStatusHandler together with all middlewares metioned in the NewBackendFactory function?

I'm a little confused about how krakend deals with middlewares listed in the krakend.json vs. middlewares "hardcoded" in the NewBackendFactory function. It is possible to use some middleware configured in the krakend.json even if it's not explicitly mentioned in the code of the NewBackendFactory function?

Thank you.

@kpacha
Copy link
Member

kpacha commented Dec 10, 2018

hi @dominiksimek

Is it possible to use NoOpHTTPStatusHandler together with all middlewares metioned in the NewBackendFactory function?

yes, it is. You can do it without touching the code by adding "output_encoding": "no-op" at the endpoint config and "encoding": "no-op" at the backend

I'm a little confused about how krakend deals with middlewares listed in the krakend.json vs. middlewares "hardcoded" in the NewBackendFactory function. It is possible to use some middleware configured in the krakend.json even if it's not explicitly mentioned in the code of the NewBackendFactory function?

The system loads all the factories required to support/enable the modules/middlewares included. Each factory looks for its configuration at some part of the config file. If it is not configured, the module/middleware is not added to the final pipe. That's why the config of a not included component is ignored.

cheers

@dominiksimek
Copy link

Great, it works well.

However, I have an issue with endpoint used to sign JWT (github.com/devopsfaith/krakend-jose/signer). Signed token is not returned from Krakend when using Backend "encoding": "no-op" (it returns only empty JSON).
On the other hand, response from Krakend contains valid json with signed token when using Backend "encoding": "json". But StatusCode from Krakend response can be only 200 or 400. In the case of unsuccessful user authentication (e.g. wrong password), my backend sends 401 with additional JSON in the response body. Is it possible to proxy such response from backend through Krakend?

Thank you

@kpacha
Copy link
Member

kpacha commented Dec 11, 2018

@dominiksimek in order to avoid polluting this issue, I'd suggest you to move the discussion to the slack

@nadim500
Copy link

Hello.

I am using the example of ricomeira to return the original status and response of a request, which works well, but when doing a merge of three requests, it does not show any results

image

main.go

package main

import (
	"flag"
	"io"
	"log"
	"net/http"
	"os"

	limit "github.com/aviddiviner/gin-limit"
	"github.com/gin-gonic/gin"

	"github.com/devopsfaith/krakend/config"
	"github.com/devopsfaith/krakend/logging"
	"github.com/devopsfaith/krakend/proxy"
	"github.com/devopsfaith/krakend/router"
	krakendgin "github.com/devopsfaith/krakend/router/gin"
	"github.com/devopsfaith/krakend/transport/http/client"
)

func main() {
	port := flag.Int("p", 0, "Port of the service")
	logLevel := flag.String("l", "ERROR", "Logging level")
	debug := flag.Bool("d", false, "Enable the debug")
	configFile := flag.String("c", "./krakend.json", "Path to the configuration filename")
	flag.Parse()

	parser := config.NewParser()
	serviceConfig, err := parser.Parse(*configFile)
	if err != nil {
		log.Fatal("ERROR:", err.Error())
	}

	// render that does not change response
	noTransformRender := func(c *gin.Context, response *proxy.Response) {
		if response == nil {
			c.Status(http.StatusInternalServerError)
			return
		}
		c.Status(response.Metadata.StatusCode)
		for k, v := range response.Metadata.Headers {
			c.Header(k, v[0])
		}
		io.Copy(c.Writer, response.Io)
	}

	// register the render at the router level
	krakendgin.RegisterRender("NoTransformRender", noTransformRender)

	serviceConfig.Debug = serviceConfig.Debug || *debug
	if *port != 0 {
		serviceConfig.Port = *port
	}

	logger, err := logging.NewLogger(*logLevel, os.Stdout, "[KRAKEND]")
	if err != nil {
		log.Fatal("ERROR:", err.Error())
	}

	backendFactory := func(backendCfg *config.Backend) proxy.Proxy {

		// status handler that does change status
		ns := client.NoOpHTTPStatusHandler

		// the default request executor
		re := client.DefaultHTTPRequestExecutor(client.NewHTTPClient)

		// response parser that copies Backend response body to proxy Response IO reader
		rp := proxy.NoOpHTTPResponseParser

		// build and return the new backend proxy
		return proxy.NewHTTPProxyDetailed(backendCfg, re, ns, rp)
	}

	// build the pipes on top of the custom backend factory
	proxyFactory := proxy.NewDefaultFactory(backendFactory, logger)

	// store := cache.NewInMemoryStore(time.Minute)

	mws := []gin.HandlerFunc{
		limit.MaxAllowed(20),
	}

	// routerFactory := krakendgin.DefaultFactory(proxy.DefaultFactory(logger), logger)

	routerFactory := krakendgin.NewFactory(krakendgin.Config{
		Engine:         gin.Default(),
		ProxyFactory:   proxyFactory,
		Middlewares:    mws,
		Logger:         logger,
		HandlerFactory: krakendgin.EndpointHandler,
		RunServer:      router.RunServer,
	})

	routerFactory.New().Run(serviceConfig)
}

krakend.json

{
    "version": 2,
    "name": "kraken_test",
    "port": 8000,
    "cache_ttl": "3600s",
    "timeout": "3000ms",
    "extra_config": {
        "github_com/devopsfaith/krakend-gologging": {
            "level": "DEBUG",
            "prefix": "[KRAKEND]",
            "syslog": false,
            "stdout": true
        },
        "github_com/devopsfaith/krakend-metrics": {
            "collection_time": "60s",
            "proxy_disabled": false,
            "router_disabled": false,
            "backend_disabled": false,
            "endpoint_disabled": false,
            "listen_address": ":8090"
        },
        "github_com/devopsfaith/krakend-cors": {
            "allow_origins": [
                "http://192.168.99.100:3000",
                "http://localhost:8080"
            ],
            "allow_methods": [
                "POST",
                "GET"
            ],
            "allow_headers": [
                "Origin",
                "Authorization",
                "Content-Type"
            ],
            "expose_headers": [
                "Content-Length"
            ],
            "max_age": "12h"
        }
    },
    "endpoints": [
        {
            "endpoint": "/abc",
            "method": "GET",
            "headers_to_pass": [
                "Authorization",
                "Content-Type"
            ],
            "backend": [
                {
                    "host": [
                        "http://127.0.0.1:8080"
                    ],
                    "url_pattern": "/v1/test/a",
                    "encoding": "json"
                },
                {
                    "host": [
                        "http://127.0.0.1:8080"
                    ],
                    "url_pattern": "/v1/test/b",
                    "encoding": "json"
                },
                {
                    "host": [
                        "http://127.0.0.1:8080"
                    ],
                    "url_pattern": "/v1/test/c",
                    "encoding": "json"
                }
            ]
        },
        {
            "endpoint": "/200",
            "method": "GET",
            "headers_to_pass": [
                "Authorization",
                "Content-Type"
            ],
            "backend": [
                {
                    "host": [
                        "http://127.0.0.1:8080"
                    ],
                    "url_pattern": "/v1/test/200",
                    "encoding": "json",
                    "extra_config": {
                        "github.com/devopsfaith/krakend-ratelimit/juju/proxy": {
                            "maxRate": 1,
                            "capacity": 1
                        },
                        "github.com/devopsfaith/krakend-circuitbreaker/gobreaker": {
                            "interval": 60,
                            "timeout": 10,
                            "maxErrors": 1
                        }
                    }
                }
            ],
            "output_encoding": "NoTransformRender"
        },
        {
            "endpoint": "/201",
            "method": "GET",
            "headers_to_pass": [
                "Authorization",
                "Content-Type"
            ],
            "backend": [
                {
                    "host": [
                        "http://127.0.0.1:8080"
                    ],
                    "url_pattern": "/v1/test/201",
                    "encoding": "json",
                    "extra_config": {
                        "github.com/devopsfaith/krakend-ratelimit/juju/proxy": {
                            "maxRate": 1,
                            "capacity": 1
                        },
                        "github.com/devopsfaith/krakend-circuitbreaker/gobreaker": {
                            "interval": 60,
                            "timeout": 10,
                            "maxErrors": 1
                        }
                    }
                }
            ],
            "output_encoding": "NoTransformRender"
        },
        {
            "endpoint": "/400",
            "method": "GET",
            "headers_to_pass": [
                "Authorization",
                "Content-Type"
            ],
            "backend": [
                {
                    "host": [
                        "http://127.0.0.1:8080"
                    ],
                    "url_pattern": "/v1/test/400",
                    "encoding": "json",
                    "extra_config": {
                        "github.com/devopsfaith/krakend-ratelimit/juju/proxy": {
                            "maxRate": 1,
                            "capacity": 1
                        },
                        "github.com/devopsfaith/krakend-circuitbreaker/gobreaker": {
                            "interval": 60,
                            "timeout": 10,
                            "maxErrors": 1
                        }
                    }
                }
            ],
            "output_encoding": "NoTransformRender"
        },
        {
            "endpoint": "/401",
            "method": "GET",
            "headers_to_pass": [
                "Authorization",
                "Content-Type"
            ],
            "backend": [
                {
                    "host": [
                        "http://127.0.0.1:8080"
                    ],
                    "url_pattern": "/v1/test/401",
                    "encoding": "json",
                    "extra_config": {
                        "github.com/devopsfaith/krakend-ratelimit/juju/proxy": {
                            "maxRate": 1,
                            "capacity": 1
                        },
                        "github.com/devopsfaith/krakend-circuitbreaker/gobreaker": {
                            "interval": 60,
                            "timeout": 10,
                            "maxErrors": 1
                        }
                    }
                }
            ],
            "output_encoding": "NoTransformRender"
        },
        {
            "endpoint": "/404",
            "method": "GET",
            "headers_to_pass": [
                "Authorization",
                "Content-Type"
            ],
            "backend": [
                {
                    "host": [
                        "http://127.0.0.1:8080"
                    ],
                    "url_pattern": "/v1/test/404",
                    "encoding": "json",
                    "extra_config": {
                        "github.com/devopsfaith/krakend-ratelimit/juju/proxy": {
                            "maxRate": 1,
                            "capacity": 1
                        },
                        "github.com/devopsfaith/krakend-circuitbreaker/gobreaker": {
                            "interval": 60,
                            "timeout": 10,
                            "maxErrors": 1
                        }
                    }
                }
            ],
            "output_encoding": "NoTransformRender"
        },
        {
            "endpoint": "/500",
            "method": "GET",
            "headers_to_pass": [
                "Authorization",
                "Content-Type"
            ],
            "backend": [
                {
                    "host": [
                        "http://127.0.0.1:8080"
                    ],
                    "url_pattern": "/v1/test/500",
                    "encoding": "json",
                    "extra_config": {
                        "github.com/devopsfaith/krakend-ratelimit/juju/proxy": {
                            "maxRate": 1,
                            "capacity": 1
                        },
                        "github.com/devopsfaith/krakend-circuitbreaker/gobreaker": {
                            "interval": 60,
                            "timeout": 10,
                            "maxErrors": 1
                        }
                    }
                }
            ],
            "output_encoding": "NoTransformRender"
        }
    ]
}

This is my test server where I generate the APIs : webnode

Could you please help me?
Thank you.

@kpacha
Copy link
Member

kpacha commented Apr 21, 2019

@nadim500, notice the pipe of that example has two important customizations:

  • its backend proxy does not decode the response, keeping it as received into the Response.Io.
  • its response render function does not encode the response data. It just copies Response.Io into the output buffer

These two details are very important because they make the pipe behave like a no-op pipe, so no merging is supported because merging requires the data from the backends to be already decoded and it ignores the Response.Io.

@muhammadluth
Copy link

muhammadluth commented Oct 11, 2021

Great, it works well.

However, I have an issue with endpoint used to sign JWT (github.com/devopsfaith/krakend-jose/signer). Signed token is not returned from Krakend when using Backend "encoding": "no-op" (it returns only empty JSON). On the other hand, response from Krakend contains valid json with signed token when using Backend "encoding": "json". But StatusCode from Krakend response can be only 200 or 400. In the case of unsuccessful user authentication (e.g. wrong password), my backend sends 401 with additional JSON in the response body. Is it possible to proxy such response from backend through Krakend?

Thank you

It's the same for me. I can't get response body from backend when my backend return invalid password but krakend returns response 400 with empty response body.
Can anyone help me ?

@github-actions
Copy link

github-actions bot commented Apr 6, 2022

This issue was marked as resolved a long time ago and now has been automatically locked as there has not been any recent activity after it. You can still open a new issue and reference this link.

@github-actions github-actions bot added the locked label Apr 6, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 6, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

6 participants