From 92a37c83a728715d57cb1969b3d40e6543060106 Mon Sep 17 00:00:00 2001 From: thefosk Date: Thu, 15 Oct 2015 16:40:11 -0700 Subject: [PATCH 1/2] Adding "total" field in API responses --- kong/api/crud_helpers.lua | 30 ++++++++++++++----- kong/dao/cassandra/base_dao.lua | 7 +++-- .../admin_api/apis_routes_spec.lua | 7 +++-- .../admin_api/consumers_routes_spec.lua | 7 +++-- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/kong/api/crud_helpers.lua b/kong/api/crud_helpers.lua index 9a394e4d220..1bb25ba4be0 100644 --- a/kong/api/crud_helpers.lua +++ b/kong/api/crud_helpers.lua @@ -51,22 +51,36 @@ function _M.paginated_set(self, dao_collection) return app_helpers.yield_error(err) end + local count, err = dao_collection:count_by_keys(self.params) + if err then + return app_helpers.yield_error(err) + end + local next_url if data.next_page then - next_url = self:build_url(self.req.parsed_url.path, { - port = self.req.parsed_url.port, - query = ngx.encode_args({ - offset = ngx.encode_base64(data.next_page), - size = size - }) - }) + -- Parse next URL, if there are no elements then don't append it + local next_total, err = dao_collection:count_by_keys(self.params, size, data.next_page) + if err then + return app_helpers.yield_error(err) + end + + if next_total > 0 then + next_url = self:build_url(self.req.parsed_url.path, { + port = self.req.parsed_url.port, + query = ngx.encode_args({ + offset = ngx.encode_base64(data.next_page), + size = size + }) + }) + end + data.next_page = nil end -- This check is required otherwise the response is going to be a -- JSON Object and not a JSON array. The reason is because an empty Lua array `{}` -- will not be translated as an empty array by cjson, but as an empty object. - local result = #data == 0 and "{\"data\":[]}" or {data=data, ["next"]=next_url} + local result = #data == 0 and "{\"data\":[],\"total\":0}" or {data=data, ["next"]=next_url, total=count} return responses.send_HTTP_OK(result, type(result) ~= "table") end diff --git a/kong/dao/cassandra/base_dao.lua b/kong/dao/cassandra/base_dao.lua index c0011e8c38a..d8311f55192 100644 --- a/kong/dao/cassandra/base_dao.lua +++ b/kong/dao/cassandra/base_dao.lua @@ -553,9 +553,12 @@ end -- @return `res` -- @return `err` -- @return `filtering` A boolean indicating if ALLOW FILTERING was needed by the query -function BaseDao:count_by_keys(where_t) +function BaseDao:count_by_keys(where_t, page_size, paging_state) local select_q, where_columns, filtering = query_builder.count(self._table, where_t, self._column_family_details) - local res, err = self:execute(select_q, where_columns, where_t, {}) + local res, err = self:execute(select_q, where_columns, where_t, { + page_size = page_size, + paging_state = paging_state + }) return (#res >= 1 and table.remove(res, 1).count or 0), err, filtering end diff --git a/spec/integration/admin_api/apis_routes_spec.lua b/spec/integration/admin_api/apis_routes_spec.lua index eb3f531bc79..572aed7d214 100644 --- a/spec/integration/admin_api/apis_routes_spec.lua +++ b/spec/integration/admin_api/apis_routes_spec.lua @@ -100,6 +100,7 @@ describe("Admin API", function() local body = json.decode(response) assert.truthy(body.data) assert.equal(10, table.getn(body.data)) + assert.equal(10, body.total) end) it("should retrieve a paginated set", function() @@ -109,6 +110,7 @@ describe("Admin API", function() assert.truthy(body_page_1.data) assert.equal(3, table.getn(body_page_1.data)) assert.truthy(body_page_1.next) + assert.equal(10, body_page_1.total) response, status = http_client.get(BASE_URL, {size=3,offset=body_page_1.next}) assert.equal(200, status) @@ -117,14 +119,15 @@ describe("Admin API", function() assert.equal(3, table.getn(body_page_2.data)) assert.truthy(body_page_2.next) assert.not_same(body_page_1, body_page_2) + assert.equal(10, body_page_2.total) response, status = http_client.get(BASE_URL, {size=4,offset=body_page_2.next}) assert.equal(200, status) local body_page_3 = json.decode(response) assert.truthy(body_page_3.data) assert.equal(4, table.getn(body_page_3.data)) - -- TODO: fixme - --assert.falsy(body_page_3.next) + assert.equal(10, body_page_3.total) + assert.falsy(body_page_3.next) assert.not_same(body_page_2, body_page_3) end) diff --git a/spec/integration/admin_api/consumers_routes_spec.lua b/spec/integration/admin_api/consumers_routes_spec.lua index e6c8efcb8d6..11be1c4636c 100644 --- a/spec/integration/admin_api/consumers_routes_spec.lua +++ b/spec/integration/admin_api/consumers_routes_spec.lua @@ -76,6 +76,7 @@ describe("Admin API", function() local body = json.decode(response) assert.truthy(body.data) assert.equal(10, table.getn(body.data)) + assert.equal(10, body.total) end) it("should retrieve a paginated set", function() @@ -85,6 +86,7 @@ describe("Admin API", function() assert.truthy(body_page_1.data) assert.equal(3, table.getn(body_page_1.data)) assert.truthy(body_page_1.next) + assert.equal(10, body_page_1.total) response, status = http_client.get(BASE_URL, {size=3,offset=body_page_1.next}) assert.equal(200, status) @@ -93,14 +95,15 @@ describe("Admin API", function() assert.equal(3, table.getn(body_page_2.data)) assert.truthy(body_page_2.next) assert.not_same(body_page_1, body_page_2) + assert.equal(10, body_page_2.total) response, status = http_client.get(BASE_URL, {size=4,offset=body_page_2.next}) assert.equal(200, status) local body_page_3 = json.decode(response) assert.truthy(body_page_3.data) assert.equal(4, table.getn(body_page_3.data)) - -- TODO: fixme - --assert.falsy(body_page_3.next) + assert.equal(10, body_page_3.total) + assert.falsy(body_page_3.next) assert.not_same(body_page_2, body_page_3) end) From 21d77a58baf2b064f8a347c113ade3e80e121269 Mon Sep 17 00:00:00 2001 From: thefosk Date: Thu, 15 Oct 2015 17:01:28 -0700 Subject: [PATCH 2/2] Adding database stats into status endpoint --- CHANGELOG.md | 12 ++++++++ kong/api/routes/kong.lua | 16 ++++++++++- .../admin_api/kong_routes_spec.lua | 28 +++++++++++++------ 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfd4a5af7d6..3a304f6e277 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ ## [Unreleased][unreleased] +### Added + +- Added a `total` field in API responses, that counts the total number of entities in the table. [#635](https://github.com/Mashape/kong/pull/635) + +### Changed + +- The `/status` endpoint now includes `database` statistics, while the previous stats have been moved to a `server` field. [#635](https://github.com/Mashape/kong/pull/635) + +### Fixed + +- In the API, the `next` link is not being displayed anymore if there are no more entities to return. [#635](https://github.com/Mashape/kong/pull/635) + ## [0.5.1] - 2015/10/13 Fixing a few glitches we let out with 0.5.0! diff --git a/kong/api/routes/kong.lua b/kong/api/routes/kong.lua index 878b7af7a51..fbd5e65557f 100644 --- a/kong/api/routes/kong.lua +++ b/kong/api/routes/kong.lua @@ -25,7 +25,21 @@ return { GET = function(self, dao, helpers) local res = ngx.location.capture("/nginx_status") if res.status == 200 then - return helpers.responses.send_HTTP_OK(route_helpers.parse_status(res.body)) + + local status_response = { + server = route_helpers.parse_status(res.body), + database = {} + } + + for k, v in pairs(dao.daos) do + local count, err = v:count_by_keys() + if err then + return helpers.responses.send_HTTP_INTERNAL_SERVER_ERROR(err) + end + status_response.database[k] = count + end + + return helpers.responses.send_HTTP_OK(status_response) else return helpers.responses.send_HTTP_INTERNAL_SERVER_ERROR(res.body) end diff --git a/spec/integration/admin_api/kong_routes_spec.lua b/spec/integration/admin_api/kong_routes_spec.lua index e8a5bd098e2..f79827868cc 100644 --- a/spec/integration/admin_api/kong_routes_spec.lua +++ b/spec/integration/admin_api/kong_routes_spec.lua @@ -2,6 +2,8 @@ local json = require "cjson" local http_client = require "kong.tools.http_client" local spec_helper = require "spec.spec_helpers" local utils = require "kong.tools.utils" +local env = spec_helper.get_env() -- test environment +local dao_factory = env.dao_factory describe("Admin API", function() @@ -60,15 +62,25 @@ describe("Admin API", function() assert.are.equal(200, status) local body = json.decode(response) assert.truthy(body) + assert.are.equal(2, utils.table_size(body)) - assert.are.equal(7, utils.table_size(body)) - assert.truthy(body.connections_accepted) - assert.truthy(body.connections_active) - assert.truthy(body.connections_handled) - assert.truthy(body.connections_reading) - assert.truthy(body.connections_writing) - assert.truthy(body.connections_waiting) - assert.truthy(body.total_requests) + -- Database stats + -- Removing migrations DAO + dao_factory.daos.migrations = nil + assert.are.equal(utils.table_size(dao_factory.daos), utils.table_size(body.database)) + for k, _ in pairs(dao_factory.daos) do + assert.truthy(body.database[k]) + end + + -- Server stats + assert.are.equal(7, utils.table_size(body.server)) + assert.truthy(body.server.connections_accepted) + assert.truthy(body.server.connections_active) + assert.truthy(body.server.connections_handled) + assert.truthy(body.server.connections_reading) + assert.truthy(body.server.connections_writing) + assert.truthy(body.server.connections_waiting) + assert.truthy(body.server.total_requests) end) end) end)