- API aggregation is a pattern to aggregate multiple individual requests into a single request. This pattern is useful when a client must make multiple calls to different backend systems to operate.[1]
- Easegress provides filters RequestBuilder & ResponseBuilder for this powerful feature.
- Suppose we have three backend services called
demo1
,demo2
, anddemo3
. We want to call these three services and combine their response to one.demo1
returns{"mega":"ease"}
as the HTTP response body,demo2
returns{"hello":"world"}
, anddemo3
returns{"hello":"new world"}
.
echo '
name: pipeline-api
kind: Pipeline
flow:
- filter: copyRequest
namespace: demo1
- filter: copyRequest
namespace: demo2
- filter: copyRequest
namespace: demo3
- filter: proxy-demo1
namespace: demo1
- filter: proxy-demo2
namespace: demo2
- filter: proxy-demo3
namespace: demo3
- filter: buildResponse
filters:
- name: copyRequest
kind: RequestBuilder
sourceNamespace: DEFAULT
- name: proxy-demo1
kind: Proxy
pools:
- servers:
- url: https://demo1
- name: proxy-demo2
kind: Proxy
pools:
- servers:
- url: https://demo2
- name: proxy-demo3
kind: Proxy
pools:
- servers:
- url: https://demo3
- name: buildResponse
kind: ResponseBuilder
template: |
statusCode: 200
body: |
[{{.responses.demo1.Body}}, {{.responses.demo2.Body}}, {{.responses.demo3.Body}}]
' | egctl create -f -
- Creating an HTTPServer for forwarding the traffic to this pipeline.
echo '
kind: HTTPServer
name: server-demo
port: 10080
keepAlive: true
https: false
rules:
- paths:
- pathPrefix: /api
backend: pipeline-api ' | egctl create -f -
- Send a request to the pipeline
$ curl -X GET https://127.0.0.1:10080/api -v
[{"hello":"world"},{"hello":"new world"},{"mega":"ease"}]
- In #Scenario 1,
demo2
anddemo3
's responses share the same JSON key, we want to merge their response body by the JSON key together. If there are duplicated keys, we will use the last value.
- Update the pipeline spec
echo '
name: pipeline-api
kind: Pipeline
flow:
- filter: copyRequest
namespace: demo1
- filter: copyRequest
namespace: demo2
- filter: copyRequest
namespace: demo3
- filter: proxy-demo1
namespace: demo1
- filter: proxy-demo2
namespace: demo2
- filter: proxy-demo3
namespace: demo3
- filter: buildResponse
filters:
- name: copyRequest
kind: RequestBuilder
sourceNamespace: DEFAULT
- name: proxy-demo1
kind: Proxy
pools:
- servers:
- url: https://demo1
- name: proxy-demo2
kind: Proxy
pools:
- servers:
- url: https://demo2
- name: proxy-demo3
kind: Proxy
pools:
- servers:
- url: https://demo3
- name: buildResponse
kind: ResponseBuilder
template: |
statusCode: 200
body: |
{{mergeObject .responses.demo1.JSONBody .responses.demo2.JSONBody .responses.demo3.JSONBody | toRawJson}}
' | egctl apply -f -
- Send a request to the pipeline
$ curl -X GET https://127.0.0.1:10080/api -v
{"hello":"new world","mega":"ease"}
In #Scenario 1, if one of the backend services encounters a failure, the pipeline will result a wrong result. We can improve the pipeline to handle this kind of failures.
- Update the pipeline spec
echo '
name: pipeline-api
kind: Pipeline
flow:
- filter: copyRequest
namespace: demo1
- filter: copyRequest
namespace: demo2
- filter: copyRequest
namespace: demo3
- filter: proxy-demo1
namespace: demo1
jumpIf: { serverError: proxy-demo2 }
- filter: proxy-demo2
namespace: demo2
- filter: proxy-demo3
namespace: demo3
- filter: buildResponse
filters:
- name: copyRequest
kind: RequestBuilder
sourceNamespace: DEFAULT
- name: proxy-demo1
kind: Proxy
pools:
- servers:
- url: https://demo1
- name: proxy-demo2
kind: Proxy
pools:
- servers:
- url: https://demo2
- name: proxy-demo3
kind: Proxy
pools:
- servers:
- url: https://demo3
- name: buildResponse
kind: ResponseBuilder
template: |
statusCode: {{$code := 503}}{{range $resp := .responses}}{{if eq $resp.StatusCode 200}}{{$code = 200}}{{break}}{{end}}{{end}}{{$code}}
body: |
{{$first := true -}}
[{{range $resp := .responses -}}
{{if eq $resp.StatusCode 200 -}}
{{if not $first}},{{end}}{{$resp.Body}}{{$first = false -}}
{{- end}}
{{- end}}]
' | egctl apply -f -
- Stop service
demo1
and send a request to the pipeline
$ curl -X GET https://127.0.0.1:10080/api -v
[{"hello":"world"},{"hello":"new world"}]