diff --git a/changelog/unreleased/kong/fix-error-flattening-json.yml b/changelog/unreleased/kong/fix-error-flattening-json.yml new file mode 100644 index 00000000000..dbd50176123 --- /dev/null +++ b/changelog/unreleased/kong/fix-error-flattening-json.yml @@ -0,0 +1,3 @@ +message: "Fixed an issue where `POST /config?flatten_errors=1` could return a JSON object instead of an empty array." +type: bugfix +scope: Core diff --git a/kong/db/errors.lua b/kong/db/errors.lua index a1f96cccd1b..0ac400f824a 100644 --- a/kong/db/errors.lua +++ b/kong/db/errors.lua @@ -3,6 +3,7 @@ local pl_keys = require("pl.tablex").keys local nkeys = require("table.nkeys") local table_isarray = require("table.isarray") local uuid = require("kong.tools.uuid") +local json = require("kong.tools.cjson") local type = type @@ -21,6 +22,7 @@ local concat = table.concat local sort = table.sort local insert = table.insert local remove = table.remove +local new_array = json.new_array local sorted_keys = function(tbl) @@ -720,7 +722,7 @@ do ---@param ns? string ---@param flattened? table local function categorize_errors(errs, ns, flattened) - flattened = flattened or {} + flattened = flattened or new_array() for field, err in drain(errs) do local errtype = type(err) @@ -1020,7 +1022,7 @@ do ---@param input table ---@return table function flatten_errors(input, err_t) - local flattened = {} + local flattened = new_array() for entity_type, section_errors in drain(err_t) do if type(section_errors) ~= "table" then diff --git a/kong/tools/cjson.lua b/kong/tools/cjson.lua index 5ce04e1003e..dff99fb6d8a 100644 --- a/kong/tools/cjson.lua +++ b/kong/tools/cjson.lua @@ -1,6 +1,9 @@ local cjson = require "cjson.safe".new() local CJSON_MAX_PRECISION = require "kong.constants".CJSON_MAX_PRECISION +local new_tab = require("table.new") +local setmetatable = setmetatable +local array_mt = cjson.array_mt cjson.decode_array_with_array_mt(true) cjson.encode_sparse_array(nil, nil, 2^15) @@ -14,7 +17,19 @@ _M.encode = cjson.encode _M.decode_with_array_mt = cjson.decode -_M.array_mt = cjson.array_mt - +_M.array_mt = array_mt + +--- Creates a new table with the cjson array metatable. +--- +--- This ensures that the table will be encoded as a JSON array, even if it +--- is empty. +--- +---@param size? integer +---@return table +function _M.new_array(size) + local t = size and new_tab(size, 0) or {} + setmetatable(t, array_mt) + return t +end return _M