· John Williams · Tutorials  · 5 min read

How to do orchestration in Kong

One of the much awaited feature in Kong which was released in 3.10 is the Request Callout, which will help the Kong API management platform to perform orchestration/aggregation of API calls instead of teams exploring custom plugins

One of the much awaited feature in Kong which was released in 3.10 is the Request Callout, which will help the Kong API management platform to perform orchestration/aggregation of API calls instead of teams exploring custom plugins

Pre-requisites

  • Kong Konnect / any Kong deployed
  • Minikube/any K8s Cluster (with Helm)
  • Enterprise License

Aggregation vs Orchestration

One of the major functionalities required in an API Gateway is the ability to support injection of additional parameters based on a sideways call independent of the upstream/backend application being proxied. This has been supported by number of other gateway platforms and this feature came into Kong Gateways with the release of version 3.10

There are two ways how the data could be injected or massaged based on the requirements,

Aggregation : Aggregation refers to the process of collecting and combining data from multiple independent sources into a single, unified response. This reduces complexity for the client by handling multiple backend calls in one place, rather than forcing the client to make separate requests.

Orchestration : Orchestration is the coordinated management of a workflow across multiple services or APIs, where steps are executed in a specific sequence, often with dependencies, transformations, or conditional logic.

Kong Plugins

With the release of Kong 3.10, you have a new plugin Request Callout which allows you to insert arbitrary API calls before proxying a request to the upstream service and/or even call multiple APIs and aggregate the response. Let’s see this in action. For each of the example you would need three things - a service, a route and a plugin configured for request-callout and you can import the declarative yml file given in this link to add this setup into your gateway.

deck gateway sync --konnect-control-plane-name $CONTROL_PLANE_NAME --konnect-addr https://eu.api.konghq.com --konnect-token $KONNECT_TOKEN kong.yml

Make sure your gateway is up and running curl http://localhost:8000

Aggregation

In this scenario Kong will aggregate the response from two endpoints and return a combined response based on the structure of the json you require. You define two callouts and where the request should be sent out and how the response should be handled and decode: true is to to handle the json response from the URL. Finally how to handle the upstream call, here you are using the lua scripts to skip the backend call and to send back the aggregated response to the client calling the API. You are forming the final json response based on the data that you get from the two callouts made earlier.

Plugin Config

- name: request-callout
  enabled: true
  config:
    callouts:
    - name: c1
      request:
        method: GET
        url: http://httpbin.org/uuid
      response:
        body:
          decode: true
    - name: c2
      request:
        method: GET
        url: http://httpbin.org/anything
      response:
        body:
          decode: true
    upstream:
      by_lua: kong.response.exit(200, { uuid = kong.ctx.shared.callouts.c1.response.body.uuid,
          origin = kong.ctx.shared.callouts.c2.response.body.url})
  protocols:
  - grpc
  - grpcs
  - http
  - https
  route: callout-aggregate-route
  service: callout-aggregate

Output

curl http://localhost:8000/callout-aggregate

{"origin":"http://httpbin.org/anything","uuid":"3d545847-6500-4c78-bc32-75996d23e3f6"}

Orchestration

In this scenario Kong will call one endpoint after another and uses an output parameter from the first call to make the second call. First it will get the user details and fetch the userId details from the response and then fetch all the posts by that user and finally appends both in the response to you.

Plugin Config

- name: request-callout
  enabled: true
  config:
    callouts:
    - name: c1
      request:
        method: GET
        url: https://jsonplaceholder.typicode.com/users/1
      response:
        body:
          decode: true
    - name: c2
      request:
        method: GET
        url: https://jsonplaceholder.typicode.com/posts
        query:
          custom:
            userId: $(callouts.c1.response.body.id)
      response:
        body:
          decode: true
    upstream:
      by_lua: |
        local user = kong.ctx.shared.callouts.c1.response.body
        local posts = kong.ctx.shared.callouts.c2.response.body
        -- Filter posts (e.g., only those with user matching)
        local filtered_posts = {}
        for _, post in ipairs(posts) do
          if post.userId == user.id then
            table.insert(filtered_posts, post)
          end
        end
        local combined = {
          user = user,
          posts = filtered_posts
        }
        kong.response.set_header("Content-Type", "application/json")
        kong.response.exit(200, combined)
  protocols:
  - http
  - https
  route: callout-orchestrate-route
  service: callout-orchestrate

Output

curl http://localhost:8000/callout-orchestrate

{{"user":{"address":{"suite":"Apt. 556","city":"Gwenborough","zipcode":"92998-3874","street":"Kulas Light","geo":{"lng":"81.1496","lat":"-37.3159"}},"company":{"catchPhrase":"Multi-layered client-server neural-net","bs":"harness real-time e-markets","name":"Romaguera-Crona"},"website":"hildegard.org","id":1,"phone":"1-770-736-8031 x56442","email":"Sincere@april.biz","username":"Bret","name":"Leanne Graham"},"posts":[{"title":"sunt aut facere repellat provident occaecati excepturi optio reprehenderit","userId":1,"body":"quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto","id":1},{"title":"qui est esse","userId":1,"body":"est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla","id":2}]}}

Auth Header Injection

In this scenario Kong will call token endpoint before calling the upstream and inject a new Authorization header into the upstream call. Here you can see the header is injected in the httpbin response under the header section.

Plugin Config

- name: request-callout
  enabled: true
  config:
    callouts:
    - name: auth
      request:
        url: "{vault://kcsvault/TOKEN_URL}"
        method: POST
        body:
          custom:
            grant_type: client_credentials
            client_id: "{vault://kcsvault/CLIENT_ID}"
            client_secret: "{vault://kcsvault/CLIENT_SECRET}"
            audience: https://api.apiprimer.com
      response:
        body:
          store: true
          decode: true
    upstream:
      headers:
        custom:
          Authorization: Bearer $(callouts.auth.response.body.access_token)
  route: callout-auth-route
  service: callout-auth

Output

curl http://localhost:8000/callout-auth

{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InFXNXJtQ2tXZGpyZ1BNOGdJUVdzTCJ9.eyJpc3MiOiJodHRwczovL2Rldi14ZXJ1cmt6cC51cy5hdXRoMC5jb20vIiwic3ViIjoiell0M2E0WVJ2QVh0aHhZV01xV1RsYkR5S296WmM1WmpAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vYXBpLmFwaXByaW1lci5jb20iLCJpYXQiOjE3NTk1MjIxNjIsImV4cCI6MTc1OTYwODU2MiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIiwiYXpwIjoiell0M2E0WVJ2QVh0aHhZV01xV1RsYkR5S296WmM1WmoifQ.cXuLRXV-7k2Z18BVFE9HWCoEoWUgvzUBFPjS1RwtUh-x3ZZhxkQUvDXhHRc5LcjVYe7HERTKJNrF-hoXtQRPmkVvFfmFdFA7DRJdl8F9gQGVcMRXcsv3ki0Q2UsMR--7JNahJ--9OHFjE7UlveOOe7iA145lYoQYb9LBnYWtdU2c55eVRdHL0pQWCLnGm429BMeRAaGkL7DUiIhmnEJeXGn9KEmFxwcZwYcYf13cmkizI7QT8uKPjaOdi_euUe-0YQeOECoKp5b61CbJxua-98gs5TYQGX2uTLehqc7pAI8TqKbdRUOIMSlFzZ-wCWsy4qC2tWy7TXczRID9v7MDQg", 
    "Host": "localhost", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-68e02d72-7a012a760392f0f01fc44325", 
    "X-Forwarded-Host": "localhost", 
    "X-Forwarded-Path": "/callout-auth", 
    "X-Forwarded-Prefix": "/callout-auth", 
    "X-Kong-Request-Id": "82b55227ed0f8a1f9df84673a2f94d02"
  },
  "url": "http://localhost/get"
}

This plugin will be of great interest in the community where there are lot of systems involved and adding an additional simple logics in the Gateway. But be mindful about the usage of this plugin, as the latency caused by the external calls may start blocking the gateway if used too much. For light weight cases this is surely a great tool as it can replace the custom plugin generation and maintenance of that code.

I have also seen customers looking for such functionality who are coming from an Apigee or other platforms where this was supported, probably this would be an additional checked box when comparing between different gateway platforms.

Back to Blog

Related Posts

View All Posts »
Using Gateway API with Kong

Using Gateway API with Kong

Kubernetes has revolutionized how we deploy and manage applications. This blog post will delve into the methods of exposing pods in Kubernetes, the existing Ingress API, its limitations, and why the Kubernetes SIG (Special Interest Group) is developing the new Gateway API as its successor. We'll also walk through how to deploy the Gateway API using Kong

Get started on APIOps with Kong

Get started on APIOps with Kong

Increasing your developer productivity can greatly enhance your business. Kong provides a set of tools which you can leverage to make your developer life easier with aspects on API Provider Lifecycle

How to instrument observability in Kong

How to instrument observability in Kong

Observability is one of the major concern when managing a platform of scale. Kong provides lot of plugins to integrate with most familiar tools in the market. Here we will see how Kong can integrate onto any platform of choice supported by fluent-bit for logs and metrics and otel for traces.