Ultra performant API Gateway with middlewares

Krakend logo

The KrakenD framework

Go Report Card Coverage Status GoDoc CII Best Practices Docker Pulls Slack Widget

An open framework to assemble ultra performance API Gateways with middlewares; core service of the KrakenD API Gateway.

Looking for the API gateway ready to use?

Site | Download | Build | Documentation | Blog

Motivation

Consumers of REST API content (specially in microservices) often query backend services that weren't coded for the UI implementation. This is of course a good practice, but the UI consumers need to do implementations that suffer a lot of complexity and burden with the sizes of their microservices responses.

KrakenD is an API Gateway builder and proxy generator that sits between the client and all the source servers, adding a new layer that removes all the complexity to the clients, providing them only the information that the UI needs. KrakenD acts as an aggregator of many sources into single endpoints and allows you to group, wrap, transform and shrink responses. Additionally it supports a myriad of middlewares and plugins that allow you to extend the functionality, such as adding Oauth authorization or security layers.

KrakenD not only supports HTTP(S), but because it is a set of generic libraries you can build all type of API Gateways and proxies, including for instance, a RPC gateway.

Practical Example

A mobile developer needs to construct a single front page that requires data from 4 different calls to their backend services, e.g:

1) api.store.server/products
2) api.store.server/marketing-promos
3) api.users.server/users/{id_user}
4) api.users.server/shopping-cart/{id_user}

The screen is very simple and the mobile client only needs to retrieve data from 4 different sources, wait for the round trip and then hand pick only a few fields from the response.

What if the mobile could call a single endpoint?

1) krakend.server/frontpage/{id_user}

That's something KrakenD can do for you. And this is how it would look like:

Gateway

KrakenD would merge all the data and return only the fields you need (the difference in size in the graph).

Visit the KrakenD website for more information.

What's in this repository?

The source code on which the KrakenD service core is built on. It is designed to work with your own middleware and extend the functionality by using small, independent, reusable components following the Unix philosophy.

Use this repository if want to build from source your API Gateway or if you want to reuse the components in another application.

If you need the KrakenD API Gateway download the binary for your architecture or build it yourself.

Library Usage

KrakenD is presented as a go library that you can include in your own go application to build a powerful proxy or API gateway. In order to get you started several examples of implementations are included in the examples folder.

Of course you will need golang installed in your system to compile the code.

A ready to use example:

    package main

    import (
        "flag"
        "log"
        "os"

        "github.com/devopsfaith/krakend/config"
        "github.com/devopsfaith/krakend/logging"
        "github.com/devopsfaith/krakend/proxy"
        "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", "/etc/krakend/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, _ := logging.NewLogger(*logLevel, os.Stdout, "[KRAKEND]")

        routerFactory := gin.DefaultFactory(proxy.DefaultFactory(logger), logger)

        routerFactory.New().Run(serviceConfig)
    }

Visit the framework overview for more details about the components of the KrakenD.

Examples

The project KrakenD examples

  1. gin router
  2. mux router
  3. gorilla router
  4. negroni middlewares
  5. dns srv service discovery
  6. jwt middlewares
  7. httpcache based proxies

Configuration file

KrakenD config file

Benchmarks

Check out the benchmark results of several KrakenD components

Contributing

We are always happy to receive contributions. If you have questions, suggestions, bugs please open an issue. If you want to submit the code, create the issue and send us a pull request for review.

If you want to contribute on the KrakenD API Gateway binary see the builder

Want more?

Enjoy the KrakenD!

Owner
Devops Faith - Open source for DevOps
KrakenD API Gateway, API2HTML, Go tools.
Devops Faith - Open source for DevOps
Comments
  • fatal error: concurrent map writes when multiple backends

    fatal error: concurrent map writes when multiple backends

    krakend[4734]: goroutine 1053 [running]:
    krakend[4734]: runtime.throw(0xc8a990, 0x15)
    krakend[4734]: /var/opt/go/1.10/src/runtime/panic.go:619 +0x81 fp=0xc42061d920 sp=0xc42061d900 pc=0x42c921
    krakend[4734]: runtime.mapassign_faststr(0xb74440, 0xc4205adda0, 0xc84b14, 0xd, 0xc4201eacb0)
    krakend[4734]: /var/opt/go/1.10/src/runtime/hashmap_fast.go:703 +0x3e9 fp=0xc42061d990 sp=0xc42061d920 pc=0x40d529
    krakend[4734]: ioki.pl/krakend-ce/oauth1.newMiddleware.func1.1(0xd225c0, 0xc4201a0840, 0xc4205ca140, 0xc4205f85a6, 0xc4205f85c0, 0xc42064ac78)
    krakend[4734]: /home/bartoszgolek/go/src/ioki.pl/krakend-ce/oauth1/backend.go:35 +0x12c fp=0xc42061dbc0 sp=0xc42061d990 pc=0x96f96c
    krakend[4734]: ioki.pl/krakend-ce/vendor/github.com/devopsfaith/krakend-metrics.NewProxyMiddleware.func1.1(0xd225c0, 0xc4201a0840, 0xc4205ca140, 0x0, 0x0, 0x50)
    krakend[4734]: /home/bartoszgolek/go/src/ioki.pl/krakend-ce/vendor/github.com/devopsfaith/krakend-metrics/proxy.go:56 +0xd9 fp=0xc42061dc88 sp=0xc42061dbc0 pc=0x95de49
    krakend[4734]: ioki.pl/krakend-ce/vendor/github.com/devopsfaith/krakend/proxy.newLoadBalancedMiddleware.func1.1(0xd225c0, 0xc4201a0840, 0xc4205ca0f0, 0x412468, 0x10, 0xba0580)
    krakend[4734]: /home/bartoszgolek/go/src/ioki.pl/krakend-ce/vendor/github.com/devopsfaith/krakend/proxy/balancing.go:59 +0x304 fp=0xc42061ddc0 sp=0xc42061dc88 pc=0x6dba54
    krakend[4734]: ioki.pl/krakend-ce/vendor/github.com/devopsfaith/krakend/proxy.NewRequestBuilderMiddleware.func1.1(0xd225c0, 0xc4201a0840, 0xc42049ca50, 0xc4201a0840, 0xc4203620d0, 0xc4201282d0)
    krakend[4734]: /home/bartoszgolek/go/src/ioki.pl/krakend-ce/vendor/github.com/devopsfaith/krakend/proxy/http.go:87 +0x1df fp=0xc42061deb8 sp=0xc42061ddc0 pc=0x6dcd3f
    krakend[4734]: ioki.pl/krakend-ce/vendor/github.com/devopsfaith/krakend/proxy.requestPart(0xd22640, 0xc420020f60, 0xc4202dd770, 0xc42049ca50, 0xc420020fc0, 0xc420021020)
    krakend[4734]: /home/bartoszgolek/go/src/ioki.pl/krakend-ce/vendor/github.com/devopsfaith/krakend/proxy/merging.go:61 +0x84 fp=0xc42061dfb0 sp=0xc42061deb8 pc=0x6dad14
    krakend[4734]: runtime.goexit()
    krakend[4734]: /var/opt/go/1.10/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc42061dfb8 sp=0xc42061dfb0 pc=0x459921
    krakend[4734]: created by ioki.pl/krakend-ce/vendor/github.com/devopsfaith/krakend/proxy.NewMergeDataMiddleware.func1.1
    

    I think it is connected to: https://github.com/devopsfaith/krakend/pull/98/commits/4fbd601e5f5f7799cd0e693f7649d7f0ee0db076

    I've found that better solutino would be: https://github.com/devopsfaith/krakend/commit/079376adbc655473d3eabd12e6c91581bdb77597

  • How to cache backend responses?

    How to cache backend responses?

    Describe the bug I was interested in caching, so I tested it, but the result was a little confusing

    To Reproduce Steps to reproduce the behavior:

    1. Configuration used
    // port 8000
    .....
    .....
    {
         "endpoint": "/page",
         "backend": [
            {
              "url_pattern": "/page",
              "host": [
                 "http://127.0.0.1:8001"
              ],
              "extra_config": {
                "github.com/devopsfaith/krakend-httpcache": {}
              }
            }
          ]
    }
    
    1. Then i just run krakend-ce , and call endpoint multiple times
    curl -i "http://127.0.0.1:8000/page"
    
    1. However, every time the backend has a requested log, it is not cached after the first request
    2. I noticed that krakend uses sony's go-breaker and gets cache time from Cache-Control. my response header also has Cache-Control

    Expected behavior Only the first request has a log in the backend, and the rest should use the response in the cache

    Logs Krakend-ce: [GIN] 2020/03/13 - 12:20:13 | 200 | 2.541701ms | 127.0.0.1 | GET /page [GIN] 2020/03/13 - 12:20:13 | 200 | 1.019577ms | 127.0.0.1 | GET /page [GIN] 2020/03/13 - 12:20:14 | 200 | 683.903µs | 127.0.0.1 | GET /page

    Servers: [GIN] 2020/03/13 - 12:20:13 | 200 | 1.396364ms | 127.0.0.1 | GET /page [GIN] 2020/03/13 - 12:20:13 | 200 | 342.851µs | 127.0.0.1 | GET /page [GIN] 2020/03/13 - 12:20:14 | 200 | 202.322µs | 127.0.0.1 | GET /page Additional context Add any other context about the problem here.

  • 500 Internal Server Error /  no hosts available

    500 Internal Server Error / no hosts available

    I'm setting up KrakenD for the first time. I'm trying to use SD DNS to work in tandem with Consul. If I specify a static IP everything works fine, but SD DNS isn't working.

    For example, this simple curl example returns a 500: >curl http://10.30.54.185:8000/consul --verbose

    *   Trying 10.30.54.185...
    * TCP_NODELAY set
    * Connected to 10.30.54.185 (10.30.54.185) port 8000 (#0)
    > GET /consul HTTP/1.1
    > Host: 10.30.54.185:8000
    > User-Agent: curl/7.58.0
    > Accept: */*
    >
    < HTTP/1.1 500 Internal Server Error
    < X-Krakend: Version 0.9.0
    < X-Krakend-Completed: false
    < Date: Mon, 15 Jul 2019 19:42:36 GMT
    < Content-Length: 0
    <
    * Connection #0 to host 10.30.54.185 left intact
    

    The configuration file, cat /etc/krakend/krakend.json:

    {
      "version": 2,
      "name": "CAMP API Gateway",
      "timeout": "3000ms",
      "cache_ttl": "300s",
      "port": 8000,
      "output_encoding": "json",
      "extra_config": {
        "github_com/devopsfaith/krakend-gologging": {
          "level": "DEBUG",
          "prefix": "[KRAKEND]",
          "syslog": true,
          "stdout": true,
          "format": "custom",
          "custom_format": "%{message}"
        },
        "github_com/devopsfaith/krakend-cors": {
          "allow_origins": [ "*" ],
          "allow_methods": [ "POST", "GET", "PUT", "DELETE" ],
          "allow_headers": [
            "Origin",
            "Authorization",
            "Content-Type",
            "Accept",
            "X-Auth-Token"
          ],
          "expose_headers": [ "Content-Length" ],
          "max_age": "12h"
        }
      },
      "endpoints": [
        {
          "endpoint": "/consul",
          "timeout": "15s",
          "method": "GET",
          "headers_to_pass": ["*", "Cookie"],
          "backend": [
            {
              "url_pattern": "/v1/status/leader",
              "sd": "dns",
              "host": [
                "http://consul.service.consul:8500"
              ],
              "disable_host_sanitize": true
            }
          ]
        }
      ]
    }
    

    Note: For 'host', I also tried "consul.service.consul:8500" but it made no difference. Log file (notice logging is set to DEBUG level):

    krakend.service - Krakend API Gateway
       Loaded: loaded (/lib/systemd/system/krakend.service; enabled; vendor preset: enabled)
       Active: active (running) since Mon 2019-07-15 19:39:27 UTC; 6min ago
         Docs: http://krakend.io
     Main PID: 5661 (krakend)
        Tasks: 9 (limit: 4599)
       CGroup: /system.slice/krakend.service
               └─5661 /usr/bin/krakend run -c /etc/krakend/krakend.json
    
    Jul 15 19:39:27 krakend1-vm [KRAKEND][5661]: AMQP: http://consul.service.consul:8500: no amqp consumer defined
    Jul 15 19:39:27 krakend1-vm [KRAKEND][5661]: AMQP: http://consul.service.consul:8500: no amqp producer defined
    Jul 15 19:39:27 krakend1-vm [KRAKEND][5661]: CEL: no extra config detected for backend /v1/status/leader
    Jul 15 19:39:27 krakend1-vm [KRAKEND][5661]: CEL: no extra config detected for pipe /consul
    Jul 15 19:39:27 krakend1-vm [KRAKEND][5661]: JOSE: singer disabled for the endpoint /consul
    Jul 15 19:39:27 krakend1-vm [KRAKEND][5661]: JOSE: validator disabled for the endpoint /consul
    Jul 15 19:40:04 krakend1-vm krakend[5661]: [GIN] 2019/07/15 - 19:40:04 | 500 |        67.9µs |    10.30.54.185 | GET      /consul
    Jul 15 19:40:04 krakend1-vm krakend[5661]: Error #01: no hosts available
    Jul 15 19:42:36 krakend1-vm krakend[5661]: [GIN] 2019/07/15 - 19:42:36 | 500 |        13.5µs |    10.30.54.185 | GET      /consul
    Jul 15 19:42:36 krakend1-vm krakend[5661]: Error #01: no hosts available
    

    Results of dig on consul.service.consul:

    ; <<>> DiG 9.11.3-1ubuntu1.8-Ubuntu <<>> consul.service.consul
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37758
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 65494
    ;; QUESTION SECTION:
    ;consul.service.consul.         IN      A
    
    ;; ANSWER SECTION:
    consul.service.consul.  0       IN      A       10.30.54.161
    consul.service.consul.  0       IN      A       10.30.54.171
    
    ;; Query time: 4 msec
    ;; SERVER: 127.0.0.53#53(127.0.0.53)
    ;; WHEN: Mon Jul 15 19:47:27 UTC 2019
    ;; MSG SIZE  rcvd: 82
    

    Those IP addresses are correct - there are two consul servers.

    Also: dig consul.service.consul SRV +short

    1 1 8300 consul2-vm.node.stage-vm.consul.
    1 1 8300 consul1-vm.node.stage-vm.consul.
    

    I can ping those two addresses. This is running on Ubuntu Server 18.04.2 LTS I'm not sure what I'm missing. I've been banging away at this all day. Any help is much appreciated.

  • plugin was built with a different version of package github.com/luraproject/lura/v2/register

    plugin was built with a different version of package github.com/luraproject/lura/v2/register

    Describe what are you trying to do Using the github.com/luraproject/lura/v2/proxy for request/response modifier plugin following below KrakenD suggested document.

    Modifier plugin is not getting registered with the below errors. Looks like some of the below libraries mentioned in go.mod as below are not built with the GO version our project is using. Not sure how to overcome this. If I remove proxy.ResponseMetadataWrapper from the ResponseWrapper interface all working fine. I am not sure how to build the proxy package provided by lura to make it compatible with Go 1.17.8.

    Tried with both v2 and 1.4.1 but giving same errors

    V2 with below go.mod giving below errors

    go 1.17

    require ( plugin was built with a different version of package github.com/luraproject/lura/v2/register )

    2022/04/11 08:53:56 KRAKEND DEBUG: [SERVICE: Executor Plugin] plugin #1 (/etc/krakend/plugins/modifierPlugin.so): plugin.Open("/etc/krakend/plugins/modifierPlugin"): plugin was built with a different version of package github.com/luraproject/lura/v2/register

    V1.4.1 with below go.mod giving below errors

    go 1.17

    require ( github.com/devopsfaith/flatmap v0.0.0-20200601181759-8521186182fc // indirect github.com/luraproject/lura v1.4.1 // indirect github.com/valyala/fastrand v1.0.0 // indirect )

    https://www.krakend.io/docs/extending/plugin-modifiers/

    Your configuration file

    Go Lang version tried with 1.17.8 Used this below command to build .so plugin

    go build -buildmode=plugin -o modifierPlugin.so modifierPlugin.go

    Logs 2022/04/07 16:49:51 KRAKEND DEBUG: [SERVICE: Executor Plugin] plugin https://github.com/devopsfaith/krakend-ce/pull/1 (/etc/krakend/plugins/modifierPlugin.so): plugin.Open("/etc/krakend/plugins/modifierPlugin"): plugin was built with a different version of package github.com/valyala/fastrand 2022/04/07 16:49:51 KRAKEND DEBUG: [SERVICE: Handler Plugin] plugin https://github.com/devopsfaith/krakend-ce/pull/1 (/etc/krakend/plugins/modifierPlugin.so): plugin.Open("/etc/krakend/plugins/modifierPlugin.so"): plugin was built with a different version of package github.com/valyala/fastrand (previous failure) 2022/04/07 16:49:51 KRAKEND DEBUG: [SERVICE: Modifier Plugin] plugin #0 (/etc/krakend/plugins/httpHandlerPlugin.so): plugin: symbol ModifierRegisterer not found in plugin plugin/unnamed-be415b995a80d55a5fde08e3201bb850429c9287 2022/04/07 16:49:51 KRAKEND DEBUG: [SERVICE: Modifier Plugin] plugin https://github.com/devopsfaith/krakend-ce/pull/1 (/etc/krakend/plugins/modifierPlugin.so): plugin.Open("/etc/krakend/plugins/modifierPlugin.so"): plugin was built with a different version of package github.com/valyala/fastrand (previous failure)

  • Possibility to remove x-krakend headers from response

    Possibility to remove x-krakend headers from response

    Is your feature request related to a problem? Please describe. For security reason i would like to hide the x-krakend and x-krakend-completed headers from the responses, in order none knows that i use krakend and the version.

    Describe the solution you'd like A boolean in the config hide_krakend_headers

    Describe alternatives you've considered Maybe a plugin to remove these headers but i didn"t find. I tried with martian but did'nt figure out how to do it.

    Additional context image

  • Why am I getting Error #01: Invalid status code?

    Why am I getting Error #01: Invalid status code?

    Hi, it me again, still new to Krakend ! 💃

    When I do a request throug the gateway, I am getting a status code 0 (?) in my response when using the "gin example" of the repository.

    api_gateway_1  | [GIN] 2018/03/15 - 07:49:49 |   0 |   85.720918ms |      172.20.0.1 | POST     /api/v1/users?create_profile=true
    api_gateway_1  | Error #01: Invalid status code
    

    (I still get the response body I expected)

    Then doing the request again:

    api_gateway_1  | [GIN] 2018/03/15 - 07:49:49 |   200 |   85.720918ms |      172.20.0.1 | POST     /api/v1/users?create_profile=true
    

    The request is returning 200 while I am waiting for a 409, nothing is called and nothing is returned.

    I then tried to use the example directly in the README.md (since it is an even simpler version using gin too) and I get better results:

    api_user_1     | [GIN] 2018/03/15 - 07:57:21 | 201 |   86.655951ms |      172.20.0.1 | POST     /api/v1/users?create_profile=true
    api_gateway_1  | [GIN] 2018/03/15 - 07:57:21 | 200 |   89.901626ms |      172.20.0.1 | POST     /api/v1/users?create_profile=true
    

    But I get a 200 while I was expecting a 201 (?) Then I tried to do the request again, it fails as expected but I get a 500 instead of the expected 409 with the message again:

    api_user_1     | [GIN] 2018/03/15 - 07:57:28 | 409 |   51.846764ms |      172.20.0.1 | POST     /api/v1/users?create_profile=true
    api_gateway_1  | [GIN] 2018/03/15 - 07:57:28 | 500 |   52.963005ms |      172.20.0.1 | POST     /api/v1/users?create_profile=true
    api_gateway_1  | Error #01: Invalid status code
    

    go code:

    func main() {
    	serviceConfig, err := config.NewParser().Parse("/etc/krakend/configuration.json")
    	if err != nil {
    		log.Fatal("ERROR:", err.Error())
    	}
    	serviceConfig.Debug = true
    	serviceConfig.Port = 4200
    
    	logger, err := logging.NewLogger("ERROR", os.Stdout, "[KRAKEND]")
    	if err != nil {
    		log.Fatal("ERROR:", err.Error())
    	}
    
    	routerFactory := gin.DefaultFactory(proxy.DefaultFactory(logger), logger)
    
    	routerFactory.New().Run(serviceConfig)
    }
    

    Why are the response I am getting inconsistent? How is it possible and what am I doing wrong here?

    Thank you, I really value your time and I appreciate your help very much! 👍

  • Support middleware on specific endpoint

    Support middleware on specific endpoint

    Considering authentication, some endpoint may require to be authenticated (account update is an exemple) and some other may be publicly available without authentication (reaching public profile information).

    To implement such a feature, several options are available including:

    • Add a global middleware matching itself the authenticated endpoint
    • Add an authentication middleware only on endpoints that require authentication

    In the first option, the middleware should have to perform operations similar to what the http router already does and thus would add some latency to each request.

    The second option has the advantage of adding the computation time at startup, when creating middlewares, and leaving middleware to do their goal: authentication (or any other middleware core logic), leaving the route selection to the router, already implemented

  • Collection merging is not working.

    Collection merging is not working.

    Describe the bug Collection merging is not working. It returns one of collection.

    To Reproduce Steps to reproduce the behavior:

    1. Add two backends that return collections without mapping or grouping.
    2. Trigger endpoint.

    Expected behavior Returning two merged collections.

    Actual behavior Returns one of collection.

    Additional context Grouping or mapping working although.

  • Krakend returns 500 status code with backend returning 201

    Krakend returns 500 status code with backend returning 201

    Describe the bug The krakend is returning the 500 status code with backend returning 201, i think that can be a timeout issue, but i didn't find in docs if there is a default timeout.

  • Help with defining krakend.json for a backend service

    Help with defining krakend.json for a backend service

    Hi,

    I've the following curl command to query a backend service. How can I define it in krakend.json?

    curl  -H "Authorization: xxxxxxxxxxxx"  -G  --data-urlencode 'query={"a":"b"}'  http://localhost:4000/api/v1/load
    

    Here's my krakend.json:

    {
      "version": 2,
      "extra_config": {},
      "timeout": "3000ms",
      "cache_ttl": "300s",
      "output_encoding": "json",
      "name": "test",
      "port": 8080,
      "endpoints": [
        {
          "endpoint": "/test",
          "method": "GET",
          "extra_config": {},
          "output_encoding": "json",
          "concurrent_calls": 1,
          "backend": [
            {
              "url_pattern": "/api/v1/load",
              "encoding": "json",
              "sd": "static",
              "extra_config": {},
              "method": "GET",
              "disable_host_sanitize": true,
              "host": [
                "localhost:4000"
              ]
            }
          ]
        }
      ]
    }
    
  • How to prevent

    How to prevent "Transfer-Encoding: chunked"

    Hi, I am implementing an application where KrakenD is used as a gateway. I am trying to make it work to integrate with a .NET Web API service, but the POST body received at the service is empty. After thorough investigation I came to the conclusion that it is related to the way POST body is being forwarded by krakenD - krakenD sends it with "Transfer-Encoding: chunked", which .NET has problems with handling (could be a bug in .NET).

    I have tried different strategies to prevent krakenD from sending POST body with "Transfer-Encoding: chunked", which is e.g.:

    • forwarding all the headers
    • different combinations between "no-op" encoding and "json",
    • disabling compression.

    Do you know how we could achieve that krakenD sends the body not in a "chunked" way?

    My latest configuration file: configuration.zip

    Thanks in advance!

  • Rest to graphql doesn't honor the variables datatype of graphql schema

    Rest to graphql doesn't honor the variables datatype of graphql schema

    Describe the bug I was trying krakend Rest API call to Graphql and passing query params like below. http://localhost:8085/test?foo=test&offset=1&limit=10 here test param is of string type but the offset and the limit are of integer type. In my Graphql Schema, I have mentioned offset as int and limit as int. But Krakend always sends all the param as strings to the graphql request variable and sends the request upstream. Which fails as the data is incorrect.

    To Reproduce Steps to reproduce the behavior:

    1. Send integer param in the query param and see the result in the graphql request. it sends them as string.
    2. Send params in the body and see the result in the graphql request. it sends them as string.

    Expected behavior Ideally while mapping query or path param to the variable of graphql query it should convert or keep the datatype mentioned as the graphql schema. An option to provide the datatype of query param in config can also work.

    Thanks in advance.

  • AMQP producer, consumer, and async agents do not support enough parameters

    AMQP producer, consumer, and async agents do not support enough parameters

    (Based on discussion with Albert Lombarte on slack)

    Is your feature request related to a problem? Please describe. When creating an AMPQ producer/consumer or an async agent in KrakenD to connect to RabbitMQ, there are not enough parameters to support common RabbitMQ settings. In particular, connecting to an existing exchange with 'alternate-exchange' defined will cause:

    Reason: "PRECONDITION_FAILED - inequivalent arg 'alternate-exchange' for exchange 'XXX' in vhost 'XXX': received none but current is the value 'some-other-exchange' of type 'longstr'"
    

    This is particularly problematic when defining queues with a dead-letter exchange. This is important for many queues, but a producer can't connect to it because of mismatched args.

    Describe the solution you'd like Ideally, we would be able to pass all currently-supported parameters. For exchanges this is only 'alternate-exchange', but for queues there is:

    • type (classic, quorum, stream)
    • x-message-ttl
    • x-expires
    • x-overflow
    • x-single-active-consumer
    • x-dead-letter-exchange
    • x-dead-letter-routing-key
    • x-max-length
    • x-max-length-bytes
    • x-max-priority
    • x-queue-mode
    • x-queue-master-locator

    Since these are simple key/value pairs, would it be possible to just pass any "x-" parameter straight to Rabbit?

    Describe alternatives you've considered

    • For producing messages, we are able to use the RabbitMQ HTTP API to send a message via POST. However this is not ideal as it is slower, and it requires clients to either send a full AMPQ envelope (which tightly-couples them to Rabbit) or use Martian to modify the POST payload (which we'd rather not do as we would prefer to keep the endpoint no-op).
    • At present, we are unable to receive messages via Async Agents from queues defined with a DLX (or any other property that KrakenD does not support).
  • Provide a configuration point to allow access to the Response Headers from backends

    Provide a configuration point to allow access to the Response Headers from backends

    There is a need to be able to choose some response headers to be accessible, for example in plugins. A specific use case for this is the ability to tie a response to a request using a correlation id (X-Correlation-ID) in a header. At the moment there is no mechanism to do this.

  • Backend plugin middleware does not execute response modifier if proxy returns an error in at least 1 backend

    Backend plugin middleware does not execute response modifier if proxy returns an error in at least 1 backend

    Environment info:

    • KrakenD version: 2.0.5
    • lura version: 2.0.5
    • System info: docker
    • Backend technology: Go

    Describe the bug plugin/req-resp-modifier in an endpoint is not called if one of the backend CEL evaluations fails

    this was initially submitted in https://github.com/krakendio/krakend-ce/issues/542

    After some debugging it looks like it's an issue in the plugin.go in the proxy pkg https://github.com/luraproject/lura/blob/master/proxy/plugin.go#L91-L96

    When receiving a merged response for multiple backends, if one of the backends fails, we get a non nil err that is a mergeError. The error contains a slice with one entry per failed backend. Tested a simple fix, check if resp is nil, this still returns error and does not call the response modifier when all backends fail or is just one that failed, while allowing for the modifier to still be called.

    Your configuration file:

    {
      "$schema": "https://www.krakend.io/schema/v3.json",
      "version": 3,
      "name": "conditional test",
      "timeout": "3000s",
      "cache_ttl": "300s",
      "output_encoding": "json",
      "disable_rest": false,
      "plugin": {
        "folder": "./plugins/",
        "pattern": ".so"
      },
      "extra_config": {
        "telemetry/logging": {
          "level": "DEBUG",
          "prefix": "[KRAKEND]",
          "syslog": false,
          "stdout": true
        }
      },
      "endpoints": [
        {
          "endpoint": "/services",
          "input_headers": [
            "X-Group-Id"
          ],
          "method": "GET",
          "output_encoding": "json-collection",
          "extra_config": {
            "plugin/req-resp-modifier": {
              "name": [
                "krakend-response-aggregator"
              ]
            }
          },
          "backend": [
            {
              "group": "app1",
              "url_pattern": "/pattern1",
              "encoding": "safejson",
              "sd": "static",
              "method": "GET",
              "host": [
                "localhost:8090"
              ],
              "extra_config": {
                "validation/cel": [
                  {
                    "check_expr": "'group1' in req_headers['X-Group-Id']"
                  }
                ]
              }
            },
            {
              "group": "app2",
              "url_pattern": "/pattern1",
              "encoding": "safejson",
              "sd": "static",
              "method": "GET",
              "host": [
                "localhost:8090"
              ],
              "extra_config": {
                "validation/cel": [
                  {
                    "check_expr": "'group2' in req_headers['X-Group-Id']"
                  }
                ]
              }
            },
            {
              "group": "app3",
              "url_pattern": "/pattern2",
              "encoding": "safejson",
              "sd": "static",
              "method": "GET",
              "host": [
                "localhost:8090"
              ],
              "extra_config": {
                "validation/cel": [
                  {
                    "check_expr": "'group1' in req_headers['X-Group-Id']"
                  }
                ]
              }
            }
          ]
        }
      ]
    }
    

    Configuration check output: Result of krakend check -dtc krakend_conditional.json --lint command

    Parsing configuration file: krakend_conditional.json
    Global settings
            Name: conditional test
            Port: 8080
            Folder: ./plugins/
            Pattern: .so
    1 global component configuration(s):
    - telemetry/logging
    1 API endpoint(s):
            - GET /services
            Timeout: 50m0s
            1 endpoint component configuration(s):
            - plugin/req-resp-modifier
            Connecting to 3 backend(s):
                    [+] GET /pattern1
                    Timeout: 50m0s
                    Hosts: [http://localhost:8090]
                    1 backend component configuration(s):
                    - validation/cel
    
                    [+] GET /pattern1
                    Timeout: 50m0s
                    Hosts: [http://localhost:8090]
                    1 backend component configuration(s):
                    - validation/cel
    
                    [+] GET /pattern2
                    Timeout: 50m0s
                    Hosts: [http://localhost:8090]
                    1 backend component configuration(s):
                    - validation/cel
    
    0 async agent(s):
    Syntax OK!
    

    Commands used: How did you start the software?

    krakend run -d  -c krakend_conditional.json
    

    Expected behavior The objective is to call multiple backends on a endpoint conditionally and return each backend response as a JSON collection where each element is the backend response.

    Each backend is called if an HTTP header values matches a condition.

    Each backend has a group defined and I have written a response modifier plugin that applied to the endpoint gets the merged response and then collapses each group response and moves the group key name to the value of "name" into the each backend response and adds the response collection to a "collection" object.

    So each backend returns something in the likes of

    {
      "groupId": "group1",
      "url": "/pattern1"
    }
    

    Merged response would look like

    {
      "app1": {
        "groupId": "group1",
        "url": "/pattern1"
      },
      "app3": {
        "groupId": "group1",
        "url": "/pattern2"
      }
    }
    

    And modified response by the custom plugin:

    {
      "collection": [
        {
          "name": "app1",
          "groupId": "group1",
          "url": "/pattern1"
        },
        {
          "name": "app3",
          "groupId": "group1",
          "url": "/pattern2"
        }
      ]
    }
    

    With output_encoding as json-collection we would get:

    [
      {
        "name": "app1",
        "groupId": "group1",
        "url": "/pattern1"
      },
      {
        "name": "app3",
        "groupId": "group1",
        "url": "/pattern2"
      }
    ]
    

    Call to services endpoint should return the expected collection resulting of the custom plugin response modification but instead returns an empty JSON collection

     curl http://localhost:8080/services -H 'x-group-id: group1' | jq
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100     2  100     2    0     0    163      0 --:--:-- --:--:-- --:--:--   181
    []
    

    Setting the endpoint's output_encoding to json shows that the backend responses were merged but the response modifier was not triggered.

    {
      "app1": {
        "groupId": "group1",
        "url": "/pattern1"
      },
      "app3": {
        "groupId": "group1",
        "url": "/pattern2"
      }
    }
    

    Logs:

    The custom-plugin has logging and it should be visible with debug

    Parsing configuration file: krakend_conditional.json
    [KRAKEND] 2022/08/03 - 15:38:34.300 ▶ DEBUG [SERVICE: Plugin Loader] Starting loading process
    krakend-response-aggregator loaded
    [KRAKEND] 2022/08/03 - 15:38:34.348 ▶ DEBUG [SERVICE: Executor Plugin] plugin #0 (plugins/krakend-response-aggregator.so): plugin: symbol ClientRegisterer not found in plugin krakend-response-aggregator
    [KRAKEND] 2022/08/03 - 15:38:34.348 ▶ DEBUG [SERVICE: Handler Plugin] plugin #0 (plugins/krakend-response-aggregator.so): plugin: symbol HandlerRegisterer not found in plugin krakend-response-aggregator
    [KRAKEND] 2022/08/03 - 15:38:34.349 ▶ DEBUG [PLUGIN: krakend-response-aggregator] Logger loaded
    [KRAKEND] 2022/08/03 - 15:38:34.349 ▶ INFO [SERVICE: Modifier Plugin] Total plugins loaded: 1
    [KRAKEND] 2022/08/03 - 15:38:34.349 ▶ DEBUG [SERVICE: Plugin Loader] Loading process completed
    [KRAKEND] 2022/08/03 - 15:38:34.349 ▶ DEBUG [SERVICE: Gin] Debug enabled
    [KRAKEND] 2022/08/03 - 15:38:34.349 ▶ INFO Starting the KrakenD instance
    [KRAKEND] 2022/08/03 - 15:38:34.349 ▶ DEBUG [ENDPOINT: /services] Building the proxy pipe
    [KRAKEND] 2022/08/03 - 15:38:34.349 ▶ DEBUG [BACKEND: /pattern1] Building the backend pipe
    [KRAKEND] 2022/08/03 - 15:38:34.349 ▶ DEBUG [BACKEND: /pattern1][CEL] Loading configuration
    [KRAKEND] 2022/08/03 - 15:38:34.350 ▶ DEBUG [CEL] Parsing expression: 'group1' in req_headers['X-Group-Id']
    [KRAKEND] 2022/08/03 - 15:38:34.360 ▶ DEBUG [BACKEND: /pattern1][CEL] 1 preEvaluator(s) loaded
    [KRAKEND] 2022/08/03 - 15:38:34.360 ▶ DEBUG [BACKEND: /pattern1][CEL] 0 postEvaluator(s) loaded
    [KRAKEND] 2022/08/03 - 15:38:34.360 ▶ DEBUG [BACKEND: /pattern1] Building the backend pipe
    [KRAKEND] 2022/08/03 - 15:38:34.360 ▶ DEBUG [BACKEND: /pattern1][CEL] Loading configuration
    [KRAKEND] 2022/08/03 - 15:38:34.360 ▶ DEBUG [CEL] Parsing expression: 'group2' in req_headers['X-Group-Id']
    [KRAKEND] 2022/08/03 - 15:38:34.360 ▶ DEBUG [BACKEND: /pattern1][CEL] 1 preEvaluator(s) loaded
    [KRAKEND] 2022/08/03 - 15:38:34.360 ▶ DEBUG [BACKEND: /pattern1][CEL] 0 postEvaluator(s) loaded
    [KRAKEND] 2022/08/03 - 15:38:34.360 ▶ DEBUG [BACKEND: /pattern2] Building the backend pipe
    [KRAKEND] 2022/08/03 - 15:38:34.360 ▶ DEBUG [BACKEND: /pattern2][CEL] Loading configuration
    [KRAKEND] 2022/08/03 - 15:38:34.361 ▶ DEBUG [CEL] Parsing expression: 'group1' in req_headers['X-Group-Id']
    [KRAKEND] 2022/08/03 - 15:38:34.361 ▶ DEBUG [BACKEND: /pattern2][CEL] 1 preEvaluator(s) loaded
    [KRAKEND] 2022/08/03 - 15:38:34.361 ▶ DEBUG [BACKEND: /pattern2][CEL] 0 postEvaluator(s) loaded
    [KRAKEND] 2022/08/03 - 15:38:34.361 ▶ DEBUG [ENDPOINT: /services][Merge] Backends: 3, sequential: false, combiner: default
    [KRAKEND] 2022/08/03 - 15:38:34.361 ▶ DEBUG [ENDPOINT: /services][Modifier Plugins] Adding 0 request and 1 response modifiers
    [KRAKEND] 2022/08/03 - 15:38:34.361 ▶ DEBUG [ENDPOINT: /services] Building the http handler
    [KRAKEND] 2022/08/03 - 15:38:34.361 ▶ DEBUG [ENDPOINT: /services][JWTSigner] Signer disabled
    [KRAKEND] 2022/08/03 - 15:38:34.361 ▶ INFO [ENDPOINT: /services][JWTValidator] Validator disabled for this endpoint
    [KRAKEND] 2022/08/03 - 15:38:34.361 ▶ INFO [SERVICE: Gin] Listening on port: 8080
    [KRAKEND] 2022/08/03 - 15:38:39.301 ▶ DEBUG [SERVICE: Telemetry] Registering usage stats for Cluster ID uSR1YoKcD2Ts8buAGDYEE9UgLU1ZN1NSKgJqm4dPzJI=
    [KRAKEND] 2022/08/03 - 15:41:58.351 ▶ DEBUG [BACKEND: /pattern2][CEL][pre] Evaluator #0 result: true
    [KRAKEND] 2022/08/03 - 15:41:58.351 ▶ INFO [BACKEND: /pattern1][CEL][pre] Evaluator #0 result: false
    [KRAKEND] 2022/08/03 - 15:41:58.351 ▶ DEBUG [BACKEND: /pattern1][CEL][pre] Evaluator #0 result: true
    [KRAKEND] 2022/08/03 - 15:41:58.358 ▶ ERROR [ENDPOINT: /services] Error #0: request aborted by evaluator #0
    [GIN] 2022/08/03 - 15:41:58 | 200 |    7.348922ms |       127.0.0.1 | GET      "/services"
    

    Additional comments:

    Changing the CEL expression with group2 to group1 so that all backends pass the CEL evaluation proves that the custom plugin works when called

    ➜ curl http://localhost:8080/services -H 'x-group-id: group1' | jq
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100   160  100   160    0     0  16472      0 --:--:-- --:--:-- --:--:-- 17777
    [
      {
        "groupId": "group1",
        "name": "app2",
        "url": "/pattern1"
      },
      {
        "groupId": "group1",
        "name": "app3",
        "url": "/pattern2"
      },
      {
        "groupId": "group1",
        "name": "app1",
        "url": "/pattern1"
      }
    ]
    

    Logs

    ...
    [KRAKEND] 2022/08/03 - 15:52:31.953 ▶ DEBUG [BACKEND: /pattern2][CEL][pre] Evaluator #0 result: true
    [KRAKEND] 2022/08/03 - 15:52:31.953 ▶ DEBUG [BACKEND: /pattern1][CEL][pre] Evaluator #0 result: true
    [KRAKEND] 2022/08/03 - 15:52:31.953 ▶ DEBUG [BACKEND: /pattern1][CEL][pre] Evaluator #0 result: true
    [KRAKEND] 2022/08/03 - 15:52:31.961 ▶ DEBUG [PLUGIN: krakend-response-aggregator] called
    [KRAKEND] 2022/08/03 - 15:52:31.962 ▶ DEBUG [PLUGIN: krakend-response-aggregator] response: {map[app1:map[groupId:group1 name:app1 url:/pattern1] app2:map[groupId:group1 name:app2 url:/pattern1] app3:map[groupId:group1 name:app3 url:/pattern2]] true {map[] 0} <nil>}
    [GIN] 2022/08/03 - 15:52:31 | 200 |    8.802293ms |       127.0.0.1 | GET      "/services"
    
  • Can Krakend handle Api Orchestration support concurrent mode and sequential mode in one endpoint (mix mode)

    Can Krakend handle Api Orchestration support concurrent mode and sequential mode in one endpoint (mix mode)

    Is there anyone can help me to build one endpoint with below scenario?

    backend A -----> backend B(rely on the result from A) -----> backend D(rely on the result from both B and C)
    -----> backend C(rely on the result from A)

    much like the mix model in rule engine

    similar issues: https://github.com/krakendio/krakend-ce/issues/176 https://github.com/luraproject/lura/issues/182

protoc-gen-grpc-gateway-ts is a Typescript client generator for the grpc-gateway project. It generates idiomatic Typescript clients that connect the web frontend and golang backend fronted by grpc-gateway.

protoc-gen-grpc-gateway-ts protoc-gen-grpc-gateway-ts is a Typescript client generator for the grpc-gateway project. It generates idiomatic Typescript

Dec 19, 2022
HTTP Authentication middlewares

goji/httpauth httpauth currently provides HTTP Basic Authentication middleware for Go. It is compatible with Go's own net/http, goji, Gin & anything t

Dec 23, 2022
Useful HTTP middlewares

This project contains middlewares that I often found myself reimplementing in new projects. In addition, it includes a middleware that logs in a forma

Apr 16, 2022
Golang gRPC Middlewares: interceptor chaining, auth, logging, retries and more.

Golang gRPC Middlewares: interceptor chaining, auth, logging, retries and more.

Jan 7, 2023
CrankDB is an ultra fast and very lightweight Key Value based Document Store.

CrankDB is a ultra fast, extreme lightweight Key Value based Document Store.

Apr 12, 2022
Ultra simple project scaffolding
Ultra simple project scaffolding

?? You can help the author become a full-time open-source maintainer by sponsoring him on GitHub. aho ultra simple project scaffolding Install curl -f

Dec 28, 2022
Rpcx-framework - An RPC microservices framework based on rpcx, simple and easy to use, ultra fast and efficient, powerful, service discovery, service governance, service layering, version control, routing label registration.

RPCX Framework An RPC microservices framework based on rpcx. Features: simple and easy to use, ultra fast and efficient, powerful, service discovery,

Jan 5, 2022
gin middlewares, just like nginx try-file function

Gin Middleware TryFile This project is to solve the problem that the gin framework processes the dynamic routing file in the front-end compilation fil

Aug 11, 2022
BlobStore is a highly reliable,highly available and ultra-large scale distributed storage system

BlobStore Overview Documents Build BlobStore Deploy BlobStore Manage BlobStore License Overview BlobStore is a highly reliable,highly available and ul

Oct 10, 2022
The Durudex gateway combines all durudex services so that it can be used through a single gateway.

The Durudex gateway combines all durudex services so that it can be used through a single gateway.

Dec 13, 2022
Ruuvi-go-gateway - Software replica of the Ruuvi Gateway

ruuvi-go-gateway ruuvi-go-gateway is a software that tries to replicate Ruuvi Ga

Dec 21, 2022
Grpc-gateway-map-null - gRPC Gateway test using nullable values in map

Demonstrate gRPC gateway behavior with nullable values in maps Using grpc-gatewa

Jan 6, 2022
A dead simple, highly performant, highly customizable sessions middleware for go http servers.

If you're interested in jwt's, see my jwt library! Sessions A dead simple, highly performant, highly customizable sessions service for go http servers

Dec 19, 2022
Composable, observable and performant config handling for Go for the distributed processing era

Konfig Composable, observable and performant config handling for Go. Written for larger distributed systems where you may have plenty of configuration

Dec 11, 2022
A collection of useful, performant, and threadsafe Go datastructures.

go-datastructures Go-datastructures is a collection of useful, performant, and threadsafe Go datastructures. NOTE: only tested with Go 1.3+. Augmented

Dec 29, 2022
🐝 A Highly Performant and easy to use goroutine pool for Go
🐝 A Highly Performant and easy to use goroutine pool for Go

gohive Package gohive implements a simple and easy to use goroutine pool for Go Features Pool can be created with a specific size as per the requireme

Sep 26, 2022