You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by GitBox <gi...@apache.org> on 2020/04/01 15:09:34 UTC

[GitHub] [incubator-apisix] ShiningRush opened a new pull request #1388: feat: add api aggreate

ShiningRush opened a new pull request #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388
 
 
   ### Summary
   
   support api aggregation noticed in #603 
   
   (BTW: I will write doc for it when code review finish.)
   

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408559620
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,206 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+    end
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    core.log.info(data.timeout)
 
 Review comment:
   Oh, that's unnecessary log, I will remove it.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feat: add api aggreate

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r404518967
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,144 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+local type   = type
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    properties = {
 
 Review comment:
   @membphis Hi, What should I do to fix it?I think its schema is same as Prometheus plugin, it has no property.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feat: add api aggreate

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r402739425
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,144 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+local type   = type
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    properties = {
 
 Review comment:
   we need a schema

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408557039
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,206 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+    end
+    local data, err = core.json.decode(req_body)
 
 Review comment:
   need a blank line

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408634267
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
+
+## 聚合接口请求/响应
+插件会为 `apisix` 创建一个 `/apisix/aggregate` 的聚合接口来处理你的聚合请求。
 
 Review comment:
   Well, is here example about how to create a api via plugin's configures?API-Aggregation need a API to handle request.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408637552
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
 
 Review comment:
   Actually, the plugin is responsible to open a API for accept client's request, so it does not have state "enabled" or "disabled". Maybe I should write more detail about this or remove the section `How To Enable`.
   Have any idea?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408637552
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
 
 Review comment:
   Actually, the plugin is responsible to open a API for accept client's request, so it does not have state "enabled" or "disabled".
   Have any idea?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feat: add api aggreate

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r402070307
 
 

 ##########
 File path: bin/apisix
 ##########
 @@ -380,6 +380,12 @@ http {
         }
         {% end %}
 
+        location /apisix/aggregate {
 
 Review comment:
   ok, i will learn about plugin's api first.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408637552
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
 
 Review comment:
   Actually, the plugin is responsible to open a API for accept client's request, so it does not have state "enabled" or "disabled". Maybe I should write more detail about this or remove the section "How To Enable".
   Have any idea?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r407060160
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,144 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+local type   = type
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    properties = {
 
 Review comment:
   sorry for this. the current implementation is right.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on issue #1388: feat: add api aggreate

Posted by GitBox <gi...@apache.org>.
membphis commented on issue #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388#issuecomment-608232579
 
 
   @ShiningRush missing test case with invalid arguments

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408634267
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
+
+## 聚合接口请求/响应
+插件会为 `apisix` 创建一个 `/apisix/aggregate` 的聚合接口来处理你的聚合请求。
 
 Review comment:
   Well, is here example about how to create a api via plugin's configures?API-Aggregation need api to handle request.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] moonming commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
moonming commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408621755
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
+
+## 聚合接口请求/响应
+插件会为 `apisix` 创建一个 `/apisix/aggregate` 的聚合接口来处理你的聚合请求。
+
+### 接口请求参数:
+
+| 参数名 | 类型 | 可选 | 默认值 | 描述 |
+| --- | --- | --- | --- | --- |
+| query | Object | Yes | | 给所有请求都携带的 `QueryString` |
+| headers | Object | Yes | | 给所有请求都携带的 `Header` |
+| timeout | Number | Yes | 3000 | 聚合请求的超时时间,单位为 `ms` |
+| pipeline | [HttpRequest](#Request) | No | | Http 请求的详细信息 |
+
+#### HttpRequest
+| 参数名 | 类型 | 可选 | 默认值 | 描述 |
+| --- | --- | --- | --- | --- |
+| version | Enum | Yes | 1.1 | 请求用的 `http` 协议版本,可以使用 `1.0` or `1.1` |
+| method | Enum | Yes | GET | 请求使用的 `http` 方法,例如:`GET`. |
+| query | Object | Yes | | 独立请求所携带的 `QueryString`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
+| headers | Object | Yes | | 独立请求所携带的 `Header`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
+| path | String | No | | 请求路径 |
+| body | String | Yes | | 请求体 |
+
+### 接口响应参数:
+返回值为一个 [HttpResponse](#HttpResponse) 的 `数组`。
+
+#### HttpResponse
+| 参数名 | 类型 | 描述 |
+| --- | --- | --- | --- | --- |
+| status | Integer | Http 请求的状态码 |
+| reason | String | Http 请求的返回信息 |
+| body | String | Http 请求的响应体 |
+| headers | Object | Http 请求的响应头 |
+
+## 测试插件
+
+你可以将要访问的请求信息传到网关的聚合接口( `/apisix/aggregate` ),网关会以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式自动帮你完成请求。
+```shell
+curl --location --request POST 'http://100.109.220.139/apisix/aggregate' \
 
 Review comment:
   `100.109.220.139` is not a good example.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408557287
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,206 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
 
 Review comment:
   two blank lines between different function.
   please fix some other similar points.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on issue #1388: feat: add api aggreate

Posted by GitBox <gi...@apache.org>.
membphis commented on issue #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388#issuecomment-608233810
 
 
   and please take a look at the output of Travis: https://travis-ci.org/github/apache/incubator-apisix/jobs/670393219#L817

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] moonming commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
moonming commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r410691486
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
+
+## 聚合接口请求/响应
+插件会为 `apisix` 创建一个 `/apisix/aggregate` 的聚合接口来处理你的聚合请求。
+
+### 接口请求参数:
+
+| 参数名 | 类型 | 可选 | 默认值 | 描述 |
+| --- | --- | --- | --- | --- |
+| query | Object | Yes | | 给所有请求都携带的 `QueryString` |
+| headers | Object | Yes | | 给所有请求都携带的 `Header` |
+| timeout | Number | Yes | 3000 | 聚合请求的超时时间,单位为 `ms` |
+| pipeline | [HttpRequest](#Request) | No | | Http 请求的详细信息 |
+
+#### HttpRequest
+| 参数名 | 类型 | 可选 | 默认值 | 描述 |
+| --- | --- | --- | --- | --- |
+| version | Enum | Yes | 1.1 | 请求用的 `http` 协议版本,可以使用 `1.0` or `1.1` |
+| method | Enum | Yes | GET | 请求使用的 `http` 方法,例如:`GET`. |
+| query | Object | Yes | | 独立请求所携带的 `QueryString`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
+| headers | Object | Yes | | 独立请求所携带的 `Header`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
+| path | String | No | | 请求路径 |
+| body | String | Yes | | 请求体 |
+
+### 接口响应参数:
+返回值为一个 [HttpResponse](#HttpResponse) 的 `数组`。
+
+#### HttpResponse
+| 参数名 | 类型 | 描述 |
+| --- | --- | --- | --- | --- |
+| status | Integer | Http 请求的状态码 |
+| reason | String | Http 请求的返回信息 |
+| body | String | Http 请求的响应体 |
+| headers | Object | Http 请求的响应头 |
+
+## 测试插件
+
+你可以将要访问的请求信息传到网关的聚合接口( `/apisix/aggregate` ),网关会以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式自动帮你完成请求。
+```shell
+curl --location --request POST 'http://127.0.0.1:9080/apisix/aggregate' \
 
 Review comment:
   IMO, API aggregation should be controlled by the administrator, not the client.
   It's a matter of design, and I think it should be discussed first.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408669237
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
 
 Review comment:
   It is better to disable this plugin by default.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408719087
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
 
 Review comment:
   The only way to disable plugin's API is that remove it from config.yaml, right?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408556983
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,144 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+local type   = type
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    properties = {
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+local function check_input(data)
+    if not data.pipeline then
+        return 400, {message = "missing 'pipeline' in input"}
+    end
+    local type_timeout = type(data.timeout)
+    if type_timeout ~= "number" and type_timeout ~= "nil" then
+        return 400, {message = "'timeout' should be number"}
+    end
+    if not data.timeout or data.timeout == 0 then
+        data.timeout = 30000
+    end
+end
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function aggregate(service_id)
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
 
 Review comment:
   "2. the request body has been read into disk temporary files,"
   
   We need to handle the case normally.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] moonming commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
moonming commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408620183
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
 
 Review comment:
   `默认启用`?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408690013
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,206 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
 
 Review comment:
   No, it dose not need. because it will not work at route or service.But priority  is a required option, so I give a high priority.Is it will cause some bad influence?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feat: add api aggreate

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r404518967
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,144 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+local type   = type
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    properties = {
 
 Review comment:
   @membphis Hi, What should I do for fixing it?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] moonming commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
moonming commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408629490
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
+
+## 聚合接口请求/响应
+插件会为 `apisix` 创建一个 `/apisix/aggregate` 的聚合接口来处理你的聚合请求。
 
 Review comment:
   this plugin is using admin API to aggregate apis, why not use plugin's configures?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r410804874
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
+
+## 聚合接口请求/响应
+插件会为 `apisix` 创建一个 `/apisix/aggregate` 的聚合接口来处理你的聚合请求。
+
+### 接口请求参数:
+
+| 参数名 | 类型 | 可选 | 默认值 | 描述 |
+| --- | --- | --- | --- | --- |
+| query | Object | Yes | | 给所有请求都携带的 `QueryString` |
+| headers | Object | Yes | | 给所有请求都携带的 `Header` |
+| timeout | Number | Yes | 3000 | 聚合请求的超时时间,单位为 `ms` |
+| pipeline | [HttpRequest](#Request) | No | | Http 请求的详细信息 |
+
+#### HttpRequest
+| 参数名 | 类型 | 可选 | 默认值 | 描述 |
+| --- | --- | --- | --- | --- |
+| version | Enum | Yes | 1.1 | 请求用的 `http` 协议版本,可以使用 `1.0` or `1.1` |
+| method | Enum | Yes | GET | 请求使用的 `http` 方法,例如:`GET`. |
+| query | Object | Yes | | 独立请求所携带的 `QueryString`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
+| headers | Object | Yes | | 独立请求所携带的 `Header`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
+| path | String | No | | 请求路径 |
+| body | String | Yes | | 请求体 |
+
+### 接口响应参数:
+返回值为一个 [HttpResponse](#HttpResponse) 的 `数组`。
+
+#### HttpResponse
+| 参数名 | 类型 | 描述 |
+| --- | --- | --- | --- | --- |
+| status | Integer | Http 请求的状态码 |
+| reason | String | Http 请求的返回信息 |
+| body | String | Http 请求的响应体 |
+| headers | Object | Http 请求的响应头 |
+
+## 测试插件
+
+你可以将要访问的请求信息传到网关的聚合接口( `/apisix/aggregate` ),网关会以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式自动帮你完成请求。
+```shell
+curl --location --request POST 'http://127.0.0.1:9080/apisix/aggregate' \
 
 Review comment:
   "API aggregation should be controlled by the administrator" Do you mean the enable of the features or the details of how to aggregate request?
   Maybe we can have a talk in wechat, it can reach a consensus easily.
   @moonming @membphis Do you aggree?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feat: add api aggreate

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r402740443
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,144 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+local type   = type
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    properties = {
+    }
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+local function check_input(data)
+    if not data.pipeline then
+        return 400, {message = "missing 'pipeline' in input"}
+    end
+    local type_timeout = type(data.timeout)
+    if type_timeout ~= "number" and type_timeout ~= "nil" then
+        return 400, {message = "'timeout' should be number"}
+    end
+    if not data.timeout or data.timeout == 0 then
+        data.timeout = 30000
+    end
+end
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function aggregate(service_id)
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
 
 Review comment:
   that is wrong. the `req_body` maybe `nil`.
   
   please take a look at this: https://github.com/openresty/lua-nginx-module#ngxreqget_body_data

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408556667
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,206 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+    end
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    core.log.info(data.timeout)
 
 Review comment:
   Need to add some explanatory text

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feat: add api aggreate

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r402057773
 
 

 ##########
 File path: bin/apisix
 ##########
 @@ -380,6 +380,12 @@ http {
         }
         {% end %}
 
+        location /apisix/aggregate {
 
 Review comment:
   wow, that is wrong. we can use the plugin way to implement this.
   
   please take a look at the plugin `prometheus`: https://github.com/apache/incubator-apisix/blob/master/apisix/plugins/prometheus.lua#L48

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408555937
 
 

 ##########
 File path: doc/plugins/api-aggregate-cn.md
 ##########
 @@ -0,0 +1,135 @@
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+-->
+
+# [English](api-aggregate.md)
+
+# 目录
+
+- [**简介**](#简介)
+- [**属性**](#属性)
+- [**如何启用**](#如何启用)
+- [**聚合接口请求/响应**](#聚合接口请求/响应)
+- [**测试插件**](#测试插件)
+- [**禁用插件**](#禁用插件)
+
+## 简介
+
+`api-aggregate` 插件可以让你在以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式在网关聚合多个http请求。
+
+## 属性
+
+无
+
+## 如何启用
+
+本插件默认启用。
+
+## 聚合接口请求/响应
+插件会为 `apisix` 创建一个 `/apisix/aggregate` 的聚合接口来处理你的聚合请求。
+
+### 接口请求参数:
+
+| 参数名 | 类型 | 可选 | 默认值 | 描述 |
+| --- | --- | --- | --- | --- |
+| query | Object | Yes | | 给所有请求都携带的 `QueryString` |
+| headers | Object | Yes | | 给所有请求都携带的 `Header` |
+| timeout | Number | Yes | 3000 | 聚合请求的超时时间,单位为 `ms` |
+| pipeline | [HttpRequest](#Request) | No | | Http 请求的详细信息 |
+
+#### HttpRequest
+| 参数名 | 类型 | 可选 | 默认值 | 描述 |
+| --- | --- | --- | --- | --- |
+| version | Enum | Yes | 1.1 | 请求用的 `http` 协议版本,可以使用 `1.0` or `1.1` |
+| method | Enum | Yes | GET | 请求使用的 `http` 方法,例如:`GET`. |
+| query | Object | Yes | | 独立请求所携带的 `QueryString`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
+| headers | Object | Yes | | 独立请求所携带的 `Header`, 如果 `Key` 和全局的有冲突,以此设置为主。 |
+| path | String | No | | 请求路径 |
+| body | String | Yes | | 请求体 |
+
+### 接口响应参数:
+返回值为一个 [HttpResponse](#HttpResponse) 的 `数组`。
+
+#### HttpResponse
+| 参数名 | 类型 | 描述 |
+| --- | --- | --- | --- | --- |
+| status | Integer | Http 请求的状态码 |
+| reason | String | Http 请求的返回信息 |
+| body | String | Http 请求的响应体 |
+| headers | Object | Http 请求的响应头 |
+
+## 测试插件
+
+你可以将要访问的请求信息传到网关的聚合接口( `/apisix/aggregate` ),网关会以 [http pipeline](https://en.wikipedia.org/wiki/HTTP_pipelining) 的方式自动帮你完成请求。
+```shell
+curl --location --request POST 'http://100.109.220.139/apisix/aggregate' \
+--header 'Content-Type: application/json' \
+--d '{
+	"headers": {
+		"Content-Type": "application/json",
+		"admin-jwt":"xxxx"
+	},
+	"timeout": 500,
+    "pipeline": [
 
 Review comment:
   bad indentation

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feat: add api aggreate

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388: feat: add api aggreate
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r403393784
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,144 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+local type   = type
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    properties = {
 
 Review comment:
   @justinmclean please use a valid schema
   
   example: https://github.com/apache/incubator-apisix/blob/master/apisix/schema_def.lua

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] moonming commented on a change in pull request #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
moonming commented on a change in pull request #1388: feature: add api aggregate plugin.
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r408619556
 
 

 ##########
 File path: apisix/plugins/api-aggregate.lua
 ##########
 @@ -0,0 +1,206 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core   = require("apisix.core")
+local http   = require("resty.http")
+local ngx    = ngx
+local ipairs = ipairs
+local pairs  = pairs
+
+local plugin_name = "api-aggregate"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
 
 Review comment:
   Is this plugin need high priority?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add batch request plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388:
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r416458002



##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}

Review comment:
       Same style as other plugins:
   ```
           return 400, {error_msg = "bad request body: ".. err}
   ```

##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function getFile(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        return f:read("*all")
+    end
+
+    return

Review comment:
       `f:close()` better perfromance

##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function getFile(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        return f:read("*all")
+    end
+
+    return
+end
+
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = getFile(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})

Review comment:
       this line is too long.

##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function getFile(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        return f:read("*all")
+    end
+
+    return
+end
+
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = getFile(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    httpc:connect("127.0.0.1", ngx.var.server_port)
+    set_base_header(data)

Review comment:
       how about `set_header_with_base` ? 

##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function getFile(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        return f:read("*all")
+    end
+
+    return
+end
+
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = getFile(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    httpc:connect("127.0.0.1", ngx.var.server_port)

Review comment:
       It may fail, we need to check the return value.

##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function getFile(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        return f:read("*all")
+    end
+
+    return
+end
+
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = getFile(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    httpc:connect("127.0.0.1", ngx.var.server_port)
+    set_base_header(data)
+    set_base_query(data)
+    local responses, err = httpc:request_pipeline(data.pipeline)
+    if not responses then
+        core.response.exit(400, {message = "request failed", err = err})
+    end
+
+    local aggregated_resp = {}
+    for i,r in ipairs(responses) do
+        if not r.status then
+            core.table.insert(aggregated_resp, {
+                status = 504,
+                reason = "upstream timeout"
+            })
+        end
+        local sub_resp = {
+            status  = r.status,
+            reason  = r.reason,
+            headers = r.headers,
+        }
+        if r.has_body then
+            sub_resp.body = r:read_body()
+        end
+        core.table.insert(aggregated_resp, sub_resp)
+    end
+    core.response.exit(200, aggregated_resp)
+end
+
+
+function _M.api()
+    return {
+        {
+            methods = {"POST"},
+            uri = "/apisix/batch",

Review comment:
       '/apisix/batch-requests' is better?

##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function getFile(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        return f:read("*all")
+    end
+
+    return
+end
+
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = getFile(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    httpc:connect("127.0.0.1", ngx.var.server_port)
+    set_base_header(data)
+    set_base_query(data)
+    local responses, err = httpc:request_pipeline(data.pipeline)
+    if not responses then
+        core.response.exit(400, {message = "request failed", err = err})
+    end
+
+    local aggregated_resp = {}
+    for i,r in ipairs(responses) do
+        if not r.status then
+            core.table.insert(aggregated_resp, {
+                status = 504,
+                reason = "upstream timeout"
+            })
+        end
+        local sub_resp = {
+            status  = r.status,
+            reason  = r.reason,
+            headers = r.headers,
+        }
+        if r.has_body then
+            sub_resp.body = r:read_body()
+        end
+        core.table.insert(aggregated_resp, sub_resp)
+    end
+    core.response.exit(200, aggregated_resp)
+end
+
+
+function _M.api()
+    return {
+        {
+            methods = {"POST"},
+            uri = "/apisix/batch",
+            handler = aggregate,

Review comment:
       how about change `aggregate` to `batch_requests`?




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add batch request plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388:
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r416490596



##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function getFile(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        return f:read("*all")
+    end
+
+    return
+end
+
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = getFile(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    httpc:connect("127.0.0.1", ngx.var.server_port)
+    set_base_header(data)

Review comment:
       Because the function is set header for all request, so I rename it to "set_common_header", I think the good case of function name should be " verb+ noun " and as short as possible. 




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add batch request plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388:
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r417049399



##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,239 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {error_msg = "bad request body: " .. err}
+    end
+end
+
+
+local function set_common_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_common_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function get_file(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        local req_body = f:read("*all")
+        f:close()
+        return req_body
+    end
+
+    return
+end
+
+
+local function batch_requests()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = get_file(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {
+                message = "no request body, you should give at least one pipeline setting"
+            })
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    local ok, err = httpc:connect("127.0.0.1", ngx.var.server_port)
+    if not ok then
+        core.response.exit(500, {message = "connect to apisix failed", err = err})
+    end
+
+    set_common_header(data)
+    set_common_query(data)
+    local responses, err = httpc:request_pipeline(data.pipeline)
+    if not responses then
+        core.response.exit(400, {message = "request failed", err = err})
+    end
+
+    local aggregated_resp = {}
+    for i,r in ipairs(responses) do

Review comment:
       `res` may mislead to `resource`, I changed to `for _, resp in ipairs(responses) do`




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-apisix] membphis commented on pull request #1388: feature: add batch request plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on pull request #1388:
URL: https://github.com/apache/incubator-apisix/pull/1388#issuecomment-621215153


   merged, many thx @ShiningRush 


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-apisix] ShiningRush commented on issue #1388: feature: add api aggregate plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on issue #1388:
URL: https://github.com/apache/incubator-apisix/pull/1388#issuecomment-618306286


   We have discussed the the feature's detail, then rename the plugin to "batch-requests", it likes the batch APIof google and microsoft.
   Here links :
   - [json-batching](https://docs.microsoft.com/en-us/graph/json-batching)
   - [Batching Requests](https://developers.google.com/classroom/guides/batch)
   - [Sending Batch Requests](https://developers.google.com/calendar/batch)


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add batch request plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388:
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r417042473



##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,239 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {error_msg = "bad request body: " .. err}
+    end
+end
+
+
+local function set_common_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_common_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function get_file(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        local req_body = f:read("*all")
+        f:close()
+        return req_body
+    end
+
+    return
+end
+
+
+local function batch_requests()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = get_file(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {
+                message = "no request body, you should give at least one pipeline setting"
+            })
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    local ok, err = httpc:connect("127.0.0.1", ngx.var.server_port)
+    if not ok then
+        core.response.exit(500, {message = "connect to apisix failed", err = err})

Review comment:
       ditoo

##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,239 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {error_msg = "bad request body: " .. err}
+    end
+end
+
+
+local function set_common_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_common_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function get_file(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        local req_body = f:read("*all")
+        f:close()
+        return req_body
+    end
+
+    return
+end
+
+
+local function batch_requests()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = get_file(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {
+                message = "no request body, you should give at least one pipeline setting"
+            })
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    local ok, err = httpc:connect("127.0.0.1", ngx.var.server_port)
+    if not ok then
+        core.response.exit(500, {message = "connect to apisix failed", err = err})
+    end
+
+    set_common_header(data)
+    set_common_query(data)
+    local responses, err = httpc:request_pipeline(data.pipeline)
+    if not responses then
+        core.response.exit(400, {message = "request failed", err = err})

Review comment:
       ditoo

##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,239 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {error_msg = "bad request body: " .. err}
+    end
+end
+
+
+local function set_common_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_common_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function get_file(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        local req_body = f:read("*all")
+        f:close()
+        return req_body
+    end
+
+    return
+end
+
+
+local function batch_requests()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = get_file(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {
+                message = "no request body, you should give at least one pipeline setting"
+            })
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})

Review comment:
       we should use only one style, eg: `{error_msg = "**** " .. err}`, it is easier for the client shows the error message.
   
   here is the example: https://github.com/apache/incubator-apisix/pull/1388/files#diff-7a39e1834cde089a2da404821d733a92R111
   
   please fix the other similar points.

##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,239 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {error_msg = "bad request body: " .. err}
+    end
+end
+
+
+local function set_common_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_common_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function get_file(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        local req_body = f:read("*all")
+        f:close()
+        return req_body
+    end
+
+    return
+end
+
+
+local function batch_requests()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = get_file(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {
+                message = "no request body, you should give at least one pipeline setting"
+            })
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    local ok, err = httpc:connect("127.0.0.1", ngx.var.server_port)
+    if not ok then
+        core.response.exit(500, {message = "connect to apisix failed", err = err})
+    end
+
+    set_common_header(data)
+    set_common_query(data)
+    local responses, err = httpc:request_pipeline(data.pipeline)
+    if not responses then
+        core.response.exit(400, {message = "request failed", err = err})
+    end
+
+    local aggregated_resp = {}
+    for i,r in ipairs(responses) do

Review comment:
       this style is better: `for _, res in ipairs(responses) do`




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-apisix] ShiningRush commented on a change in pull request #1388: feature: add batch request plugin.

Posted by GitBox <gi...@apache.org>.
ShiningRush commented on a change in pull request #1388:
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r416490596



##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function getFile(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        return f:read("*all")
+    end
+
+    return
+end
+
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = getFile(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    httpc:connect("127.0.0.1", ngx.var.server_port)
+    set_base_header(data)

Review comment:
       Because the function is set header for all request, so I rename it to "set_common_header", I think the good case is that " verb+ noun " and as short as possible. 




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-apisix] membphis commented on a change in pull request #1388: feature: add batch request plugin.

Posted by GitBox <gi...@apache.org>.
membphis commented on a change in pull request #1388:
URL: https://github.com/apache/incubator-apisix/pull/1388#discussion_r417041476



##########
File path: apisix/plugins/batch-requests.lua
##########
@@ -0,0 +1,231 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements.  See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License.  You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+local core    = require("apisix.core")
+local http    = require("resty.http")
+local ngx     = ngx
+local io_open = io.open
+local ipairs  = ipairs
+local pairs   = pairs
+
+local plugin_name = "batch-requests"
+
+local schema = {
+    type = "object",
+    additionalProperties = false,
+}
+
+local req_schema = {
+    type = "object",
+    properties = {
+        query = {
+            description = "pipeline query string",
+            type = "object"
+        },
+        headers = {
+            description = "pipeline header",
+            type = "object"
+        },
+        timeout = {
+            description = "pipeline timeout(ms)",
+            type = "integer",
+            default = 30000,
+        },
+        pipeline = {
+            type = "array",
+            minItems = 1,
+            items = {
+                type = "object",
+                properties = {
+                    version = {
+                        description = "HTTP version",
+                        type = "number",
+                        enum = {1.0, 1.1},
+                        default = 1.1,
+                    },
+                    method = {
+                        description = "HTTP method",
+                        type = "string",
+                        enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
+                                "OPTIONS", "CONNECT", "TRACE"},
+                        default = "GET"
+                    },
+                    path = {
+                        type = "string",
+                        minLength = 1,
+                    },
+                    query = {
+                        description = "request header",
+                        type = "object",
+                    },
+                    headers = {
+                        description = "request query string",
+                        type = "object",
+                    },
+                    ssl_verify = {
+                        type = "boolean",
+                        default = false
+                    },
+                }
+            }
+        }
+    },
+    anyOf = {
+        {required = {"pipeline"}},
+    },
+}
+
+local _M = {
+    version = 0.1,
+    priority = 4010,
+    name = plugin_name,
+    schema = schema
+}
+
+
+function _M.check_schema(conf)
+    local ok, err = core.schema.check(schema, conf)
+    if not ok then
+        return false, err
+    end
+    return true
+end
+
+
+local function check_input(data)
+    local ok, err = core.schema.check(req_schema, data)
+    if not ok then
+        return 400, {message = "bad request body", err = err}
+    end
+end
+
+
+local function set_base_header(data)
+    if not data.headers then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.headers then
+            req.headers = data.headers
+        else
+            for k, v in pairs(data.headers) do
+                if not req.headers[k] then
+                    req.headers[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function set_base_query(data)
+    if not data.query then
+        return
+    end
+
+    for i,req in ipairs(data.pipeline) do
+        if not req.query then
+            req.query = data.query
+        else
+            for k, v in pairs(data.query) do
+                if not req.query[k] then
+                    req.query[k] = v
+                end
+            end
+        end
+    end
+end
+
+
+local function getFile(file_name)
+    local f = io_open(file_name, 'r')
+    if f then
+        return f:read("*all")
+    end
+
+    return
+end
+
+
+local function aggregate()
+    ngx.req.read_body()
+    local req_body = ngx.req.get_body_data()
+    if not req_body then
+        local file_name = ngx.req.get_body_file()
+        if file_name then
+            req_body = getFile(file_name)
+        end
+
+        if not req_body then
+            core.response.exit(400, {message = "no request body, you should give at least one pipeline setting"})
+        end
+    end
+
+    local data, err = core.json.decode(req_body)
+    if not data then
+        core.response.exit(400, {message = "invalid request body", req_body = req_body, err = err})
+    end
+
+    local code, body = check_input(data)
+    if code then
+        core.response.exit(code, body)
+    end
+
+    local httpc = http.new()
+    httpc:set_timeout(data.timeout)
+    httpc:connect("127.0.0.1", ngx.var.server_port)
+    set_base_header(data)

Review comment:
       it is fine




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org