xref: /openbmc/bmcweb/features/redfish/include/utils/json_utils.hpp (revision 9712f8ac42746e65f32c2bc3de0835846652568e)
177dd8813SKowalski, Kamil /*
277dd8813SKowalski, Kamil // Copyright (c) 2018 Intel Corporation
377dd8813SKowalski, Kamil //
477dd8813SKowalski, Kamil // Licensed under the Apache License, Version 2.0 (the "License");
577dd8813SKowalski, Kamil // you may not use this file except in compliance with the License.
677dd8813SKowalski, Kamil // You may obtain a copy of the License at
777dd8813SKowalski, Kamil //
877dd8813SKowalski, Kamil //      http://www.apache.org/licenses/LICENSE-2.0
977dd8813SKowalski, Kamil //
1077dd8813SKowalski, Kamil // Unless required by applicable law or agreed to in writing, software
1177dd8813SKowalski, Kamil // distributed under the License is distributed on an "AS IS" BASIS,
1277dd8813SKowalski, Kamil // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1377dd8813SKowalski, Kamil // See the License for the specific language governing permissions and
1477dd8813SKowalski, Kamil // limitations under the License.
1577dd8813SKowalski, Kamil */
1677dd8813SKowalski, Kamil #pragma once
17*9712f8acSEd Tanous 
1877dd8813SKowalski, Kamil #include <crow/http_request.h>
1977dd8813SKowalski, Kamil #include <crow/http_response.h>
2077dd8813SKowalski, Kamil 
21*9712f8acSEd Tanous #include <bitset>
22*9712f8acSEd Tanous #include <error_messages.hpp>
231abe55efSEd Tanous #include <nlohmann/json.hpp>
241abe55efSEd Tanous namespace redfish
251abe55efSEd Tanous {
261abe55efSEd Tanous 
271abe55efSEd Tanous namespace json_util
281abe55efSEd Tanous {
2977dd8813SKowalski, Kamil 
3077dd8813SKowalski, Kamil /**
3177dd8813SKowalski, Kamil  * @brief Defines JSON utils operation status
3277dd8813SKowalski, Kamil  */
331abe55efSEd Tanous enum class Result
341abe55efSEd Tanous {
351abe55efSEd Tanous     SUCCESS,
361abe55efSEd Tanous     NOT_EXIST,
371abe55efSEd Tanous     WRONG_TYPE,
381abe55efSEd Tanous     NULL_POINTER
391abe55efSEd Tanous };
4077dd8813SKowalski, Kamil 
4177dd8813SKowalski, Kamil /**
4277dd8813SKowalski, Kamil  * @brief Describes JSON utils messages requirement
4377dd8813SKowalski, Kamil  */
441abe55efSEd Tanous enum class MessageSetting
451abe55efSEd Tanous {
4677dd8813SKowalski, Kamil     NONE = 0x0,      ///< No messages will be added
4777dd8813SKowalski, Kamil     MISSING = 0x1,   ///< PropertyMissing message will be added
4877dd8813SKowalski, Kamil     TYPE_ERROR = 0x2 ///< PropertyValueTypeError message will be added
4977dd8813SKowalski, Kamil };
5077dd8813SKowalski, Kamil 
5177dd8813SKowalski, Kamil /**
5277dd8813SKowalski, Kamil  * @brief Wrapper function for extracting string from JSON object without
5377dd8813SKowalski, Kamil  *        throwing exceptions
5477dd8813SKowalski, Kamil  *
5577dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
5677dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
5777dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
5877dd8813SKowalski, Kamil  *                         of success
5977dd8813SKowalski, Kamil  *
6077dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
6177dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
6277dd8813SKowalski, Kamil  */
6377dd8813SKowalski, Kamil Result getString(const char* fieldName, const nlohmann::json& json,
6477dd8813SKowalski, Kamil                  const std::string*& output);
6577dd8813SKowalski, Kamil 
6677dd8813SKowalski, Kamil /**
6777dd8813SKowalski, Kamil  * @brief Wrapper function for extracting object from JSON object without
6877dd8813SKowalski, Kamil  *        throwing exceptions
6977dd8813SKowalski, Kamil  *
7077dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
7177dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
7277dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
7377dd8813SKowalski, Kamil  *                         of success
7477dd8813SKowalski, Kamil  *
7577dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
7677dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
7777dd8813SKowalski, Kamil  */
7877dd8813SKowalski, Kamil Result getObject(const char* fieldName, const nlohmann::json& json,
7977dd8813SKowalski, Kamil                  nlohmann::json* output);
8077dd8813SKowalski, Kamil 
8177dd8813SKowalski, Kamil /**
8277dd8813SKowalski, Kamil  * @brief Wrapper function for extracting array from JSON object without
8377dd8813SKowalski, Kamil  *        throwing exceptions
8477dd8813SKowalski, Kamil  *
8577dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
8677dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
8777dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
8877dd8813SKowalski, Kamil  *                         of success
8977dd8813SKowalski, Kamil  *
9077dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
9177dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
9277dd8813SKowalski, Kamil  */
9377dd8813SKowalski, Kamil Result getArray(const char* fieldName, const nlohmann::json& json,
9477dd8813SKowalski, Kamil                 nlohmann::json* output);
9577dd8813SKowalski, Kamil 
9677dd8813SKowalski, Kamil /**
9777dd8813SKowalski, Kamil  * @brief Wrapper function for extracting int from JSON object without
9877dd8813SKowalski, Kamil  *        throwing exceptions
9977dd8813SKowalski, Kamil  *
10077dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
10177dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
10277dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
10377dd8813SKowalski, Kamil  *                         of success
10477dd8813SKowalski, Kamil  *
10577dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
10677dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
10777dd8813SKowalski, Kamil  */
10877dd8813SKowalski, Kamil Result getInt(const char* fieldName, const nlohmann::json& json,
10977dd8813SKowalski, Kamil               int64_t& output);
11077dd8813SKowalski, Kamil 
11177dd8813SKowalski, Kamil /**
11277dd8813SKowalski, Kamil  * @brief Wrapper function for extracting uint from JSON object without
11377dd8813SKowalski, Kamil  *        throwing exceptions
11477dd8813SKowalski, Kamil  *
11577dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
11677dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
11777dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
11877dd8813SKowalski, Kamil  *                         of success
11977dd8813SKowalski, Kamil  *
12077dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
12177dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
12277dd8813SKowalski, Kamil  */
12377dd8813SKowalski, Kamil Result getUnsigned(const char* fieldName, const nlohmann::json& json,
12477dd8813SKowalski, Kamil                    uint64_t& output);
12577dd8813SKowalski, Kamil 
12677dd8813SKowalski, Kamil /**
12777dd8813SKowalski, Kamil  * @brief Wrapper function for extracting bool from JSON object without
12877dd8813SKowalski, Kamil  *        throwing exceptions
12977dd8813SKowalski, Kamil  *
13077dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
13177dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
13277dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
13377dd8813SKowalski, Kamil  *                         of success
13477dd8813SKowalski, Kamil  *
13577dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
13677dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
13777dd8813SKowalski, Kamil  */
13877dd8813SKowalski, Kamil Result getBool(const char* fieldName, const nlohmann::json& json, bool& output);
13977dd8813SKowalski, Kamil 
14077dd8813SKowalski, Kamil /**
14177dd8813SKowalski, Kamil  * @brief Wrapper function for extracting float from JSON object without
14277dd8813SKowalski, Kamil  *        throwing exceptions (nlohmann stores JSON floats as C++ doubles)
14377dd8813SKowalski, Kamil  *
14477dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
14577dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
14677dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
14777dd8813SKowalski, Kamil  *                         of success
14877dd8813SKowalski, Kamil  *
14977dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
15077dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
15177dd8813SKowalski, Kamil  */
15277dd8813SKowalski, Kamil Result getDouble(const char* fieldName, const nlohmann::json& json,
15377dd8813SKowalski, Kamil                  double& output);
15477dd8813SKowalski, Kamil 
15577dd8813SKowalski, Kamil /**
15677dd8813SKowalski, Kamil  * @brief Wrapper function for extracting string from JSON object without
15777dd8813SKowalski, Kamil  *        throwing exceptions
15877dd8813SKowalski, Kamil  *
15977dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
16077dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
16177dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
16277dd8813SKowalski, Kamil  *                         of success
16377dd8813SKowalski, Kamil  * @param[in]  msgCfgMap   Map for message addition settings
16477dd8813SKowalski, Kamil  * @param[out] msgJson     JSON to which error messages will be added
16577dd8813SKowalski, Kamil  * @param[in]  fieldPath   Field path in JSON
16677dd8813SKowalski, Kamil  *
16777dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
16877dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
16977dd8813SKowalski, Kamil  */
17077dd8813SKowalski, Kamil Result getString(const char* fieldName, const nlohmann::json& json,
17177dd8813SKowalski, Kamil                  const std::string*& output, uint8_t msgCfgMap,
17277dd8813SKowalski, Kamil                  nlohmann::json& msgJson, const std::string&& fieldPath);
17377dd8813SKowalski, Kamil 
17477dd8813SKowalski, Kamil /**
17577dd8813SKowalski, Kamil  * @brief Wrapper function for extracting object from JSON object without
17677dd8813SKowalski, Kamil  *        throwing exceptions
17777dd8813SKowalski, Kamil  *
17877dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
17977dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
18077dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
18177dd8813SKowalski, Kamil  *                         of success
18277dd8813SKowalski, Kamil  * @param[in]  msgCfgMap   Map for message addition settings
18377dd8813SKowalski, Kamil  * @param[out] msgJson     JSON to which error messages will be added
18477dd8813SKowalski, Kamil  * @param[in]  fieldPath   Field path in JSON
18577dd8813SKowalski, Kamil  *
18677dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
18777dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
18877dd8813SKowalski, Kamil  */
18977dd8813SKowalski, Kamil Result getObject(const char* fieldName, const nlohmann::json& json,
19077dd8813SKowalski, Kamil                  nlohmann::json* output, uint8_t msgCfgMap,
19177dd8813SKowalski, Kamil                  nlohmann::json& msgJson, const std::string&& fieldPath);
19277dd8813SKowalski, Kamil 
19377dd8813SKowalski, Kamil /**
19477dd8813SKowalski, Kamil  * @brief Wrapper function for extracting array from JSON object without
19577dd8813SKowalski, Kamil  *        throwing exceptions
19677dd8813SKowalski, Kamil  *
19777dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
19877dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
19977dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
20077dd8813SKowalski, Kamil  *                         of success
20177dd8813SKowalski, Kamil  * @param[in]  msgCfgMap   Map for message addition settings
20277dd8813SKowalski, Kamil  * @param[out] msgJson     JSON to which error messages will be added
20377dd8813SKowalski, Kamil  * @param[in]  fieldPath   Field path in JSON
20477dd8813SKowalski, Kamil  *
20577dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
20677dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
20777dd8813SKowalski, Kamil  */
20877dd8813SKowalski, Kamil Result getArray(const char* fieldName, const nlohmann::json& json,
20977dd8813SKowalski, Kamil                 nlohmann::json* output, uint8_t msgCfgMap,
21077dd8813SKowalski, Kamil                 nlohmann::json& msgJson, const std::string&& fieldPath);
21177dd8813SKowalski, Kamil 
21277dd8813SKowalski, Kamil /**
21377dd8813SKowalski, Kamil  * @brief Wrapper function for extracting int from JSON object without
21477dd8813SKowalski, Kamil  *        throwing exceptions
21577dd8813SKowalski, Kamil  *
21677dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
21777dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
21877dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
21977dd8813SKowalski, Kamil  *                         of success
22077dd8813SKowalski, Kamil  * @param[in]  msgCfgMap   Map for message addition settings
22177dd8813SKowalski, Kamil  * @param[out] msgJson     JSON to which error messages will be added
22277dd8813SKowalski, Kamil  * @param[in]  fieldPath   Field path in JSON
22377dd8813SKowalski, Kamil  *
22477dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
22577dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
22677dd8813SKowalski, Kamil  */
22777dd8813SKowalski, Kamil Result getInt(const char* fieldName, const nlohmann::json& json,
22877dd8813SKowalski, Kamil               int64_t& output, uint8_t msgCfgMap, nlohmann::json& msgJson,
22977dd8813SKowalski, Kamil               const std::string&& fieldPath);
23077dd8813SKowalski, Kamil 
23177dd8813SKowalski, Kamil /**
23277dd8813SKowalski, Kamil  * @brief Wrapper function for extracting uint from JSON object without
23377dd8813SKowalski, Kamil  *        throwing exceptions
23477dd8813SKowalski, Kamil  *
23577dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
23677dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
23777dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
23877dd8813SKowalski, Kamil  *                         of success
23977dd8813SKowalski, Kamil  * @param[in]  msgCfgMap   Map for message addition settings
24077dd8813SKowalski, Kamil  * @param[out] msgJson     JSON to which error messages will be added
24177dd8813SKowalski, Kamil  * @param[in]  fieldPath   Field path in JSON
24277dd8813SKowalski, Kamil  *
24377dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
24477dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
24577dd8813SKowalski, Kamil  */
24677dd8813SKowalski, Kamil Result getUnsigned(const char* fieldName, const nlohmann::json& json,
24777dd8813SKowalski, Kamil                    uint64_t& output, uint8_t msgCfgMap, nlohmann::json& msgJson,
24877dd8813SKowalski, Kamil                    const std::string&& fieldPath);
24977dd8813SKowalski, Kamil 
25077dd8813SKowalski, Kamil /**
25177dd8813SKowalski, Kamil  * @brief Wrapper function for extracting bool from JSON object without
25277dd8813SKowalski, Kamil  *        throwing exceptions
25377dd8813SKowalski, Kamil  *
25477dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
25577dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
25677dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
25777dd8813SKowalski, Kamil  *                         of success
25877dd8813SKowalski, Kamil  * @param[in]  msgCfgMap   Map for message addition settings
25977dd8813SKowalski, Kamil  * @param[out] msgJson     JSON to which error messages will be added
26077dd8813SKowalski, Kamil  * @param[in]  fieldPath   Field path in JSON
26177dd8813SKowalski, Kamil  *
26277dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
26377dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
26477dd8813SKowalski, Kamil  */
26577dd8813SKowalski, Kamil Result getBool(const char* fieldName, const nlohmann::json& json, bool& output,
26677dd8813SKowalski, Kamil                uint8_t msgCfgMap, nlohmann::json& msgJson,
26777dd8813SKowalski, Kamil                const std::string&& fieldPath);
26877dd8813SKowalski, Kamil 
26977dd8813SKowalski, Kamil /**
27077dd8813SKowalski, Kamil  * @brief Wrapper function for extracting float from JSON object without
27177dd8813SKowalski, Kamil  *        throwing exceptions (nlohmann stores JSON floats as C++ doubles)
27277dd8813SKowalski, Kamil  *
27377dd8813SKowalski, Kamil  * @param[in]  fieldName   Name of requested field
27477dd8813SKowalski, Kamil  * @param[in]  json        JSON object from which field should be extracted
27577dd8813SKowalski, Kamil  * @param[out] output      Variable to which extracted will be written in case
27677dd8813SKowalski, Kamil  * of success
27777dd8813SKowalski, Kamil  * @param[in]  msgCfgMap   Map for message addition settings
27877dd8813SKowalski, Kamil  * @param[out] msgJson     JSON to which error messages will be added
27977dd8813SKowalski, Kamil  * @param[in]  fieldPath   Field path in JSON
28077dd8813SKowalski, Kamil  *
28177dd8813SKowalski, Kamil  * @return Result informing about operation status, output will be
28277dd8813SKowalski, Kamil  *         written only in case of Result::SUCCESS
28377dd8813SKowalski, Kamil  */
28477dd8813SKowalski, Kamil Result getDouble(const char* fieldName, const nlohmann::json& json,
28577dd8813SKowalski, Kamil                  double& output, uint8_t msgCfgMap, nlohmann::json& msgJson,
28677dd8813SKowalski, Kamil                  const std::string&& fieldPath);
28777dd8813SKowalski, Kamil 
28877dd8813SKowalski, Kamil /**
28977dd8813SKowalski, Kamil  * @brief Processes request to extract JSON from its body. If it fails, adds
29077dd8813SKowalski, Kamil  *       MalformedJSON message to response and ends it.
29177dd8813SKowalski, Kamil  *
29277dd8813SKowalski, Kamil  * @param[io]  res       Response object
29377dd8813SKowalski, Kamil  * @param[in]  req       Request object
29477dd8813SKowalski, Kamil  * @param[out] reqJson   JSON object extracted from request's body
29577dd8813SKowalski, Kamil  *
29677dd8813SKowalski, Kamil  * @return true if JSON is valid, false when JSON is invalid and response has
29777dd8813SKowalski, Kamil  *         been filled with message and ended.
29877dd8813SKowalski, Kamil  */
29955c7b7a2SEd Tanous bool processJsonFromRequest(crow::Response& res, const crow::Request& req,
30077dd8813SKowalski, Kamil                             nlohmann::json& reqJson);
301*9712f8acSEd Tanous namespace details
302*9712f8acSEd Tanous {
303*9712f8acSEd Tanous template <typename Type> struct unpackValue
304*9712f8acSEd Tanous {
305*9712f8acSEd Tanous     using isRequired = std::true_type;
306*9712f8acSEd Tanous     using JsonType = std::add_const_t<std::add_pointer_t<Type>>;
307*9712f8acSEd Tanous };
308*9712f8acSEd Tanous 
309*9712f8acSEd Tanous template <typename OptionalType>
310*9712f8acSEd Tanous struct unpackValue<boost::optional<OptionalType>>
311*9712f8acSEd Tanous {
312*9712f8acSEd Tanous     using isRequired = std::false_type;
313*9712f8acSEd Tanous     using JsonType = std::add_const_t<std::add_pointer_t<OptionalType>>;
314*9712f8acSEd Tanous };
315*9712f8acSEd Tanous 
316*9712f8acSEd Tanous template <size_t Count, size_t Index>
317*9712f8acSEd Tanous void readJsonValues(const std::string& key, nlohmann::json& jsonValue,
318*9712f8acSEd Tanous                     crow::Response& res, std::bitset<Count>& handled)
319*9712f8acSEd Tanous {
320*9712f8acSEd Tanous     BMCWEB_LOG_DEBUG << "Unable to find variable for key" << key;
321*9712f8acSEd Tanous     messages::addMessageToErrorJson(res.jsonValue,
322*9712f8acSEd Tanous                                     messages::propertyUnknown(key));
323*9712f8acSEd Tanous     res.result(boost::beast::http::status::bad_request);
324*9712f8acSEd Tanous }
325*9712f8acSEd Tanous 
326*9712f8acSEd Tanous template <size_t Count, size_t Index, typename ValueType,
327*9712f8acSEd Tanous           typename... UnpackTypes>
328*9712f8acSEd Tanous void readJsonValues(const std::string& key, nlohmann::json& jsonValue,
329*9712f8acSEd Tanous                     crow::Response& res, std::bitset<Count>& handled,
330*9712f8acSEd Tanous                     const char* keyToCheck, ValueType& valueToFill,
331*9712f8acSEd Tanous                     UnpackTypes&... in)
332*9712f8acSEd Tanous {
333*9712f8acSEd Tanous     if (key != keyToCheck)
334*9712f8acSEd Tanous     {
335*9712f8acSEd Tanous         readJsonValues<Count, Index + 1>(key, jsonValue, res, handled, in...);
336*9712f8acSEd Tanous         return;
337*9712f8acSEd Tanous     }
338*9712f8acSEd Tanous 
339*9712f8acSEd Tanous     handled.set(Index);
340*9712f8acSEd Tanous 
341*9712f8acSEd Tanous     using UnpackType = typename unpackValue<ValueType>::JsonType;
342*9712f8acSEd Tanous     UnpackType value = jsonValue.get_ptr<UnpackType>();
343*9712f8acSEd Tanous     if (value == nullptr)
344*9712f8acSEd Tanous     {
345*9712f8acSEd Tanous         BMCWEB_LOG_DEBUG << "Value for key " << key
346*9712f8acSEd Tanous                          << " was incorrect type: " << jsonValue.type_name();
347*9712f8acSEd Tanous         messages::addMessageToErrorJson(
348*9712f8acSEd Tanous             res.jsonValue,
349*9712f8acSEd Tanous             messages::propertyValueTypeError(jsonValue.dump(), key));
350*9712f8acSEd Tanous         res.result(boost::beast::http::status::bad_request);
351*9712f8acSEd Tanous 
352*9712f8acSEd Tanous         return;
353*9712f8acSEd Tanous     }
354*9712f8acSEd Tanous 
355*9712f8acSEd Tanous     valueToFill = *value;
356*9712f8acSEd Tanous }
357*9712f8acSEd Tanous 
358*9712f8acSEd Tanous template <size_t Index = 0, size_t Count>
359*9712f8acSEd Tanous void handleMissing(std::bitset<Count>& handled, crow::Response& res)
360*9712f8acSEd Tanous {
361*9712f8acSEd Tanous }
362*9712f8acSEd Tanous 
363*9712f8acSEd Tanous template <size_t Index = 0, size_t Count, typename ValueType,
364*9712f8acSEd Tanous           typename... UnpackTypes>
365*9712f8acSEd Tanous void handleMissing(std::bitset<Count>& handled, crow::Response& res,
366*9712f8acSEd Tanous                    const char* key, ValueType& unused, UnpackTypes&... in)
367*9712f8acSEd Tanous {
368*9712f8acSEd Tanous     if (!handled.test(Index) && unpackValue<ValueType>::isRequired::value)
369*9712f8acSEd Tanous     {
370*9712f8acSEd Tanous         messages::addMessageToErrorJson(res.jsonValue,
371*9712f8acSEd Tanous                                         messages::propertyMissing(key));
372*9712f8acSEd Tanous         res.result(boost::beast::http::status::bad_request);
373*9712f8acSEd Tanous     }
374*9712f8acSEd Tanous     details::handleMissing<Index + 1, Count>(handled, res, in...);
375*9712f8acSEd Tanous }
376*9712f8acSEd Tanous } // namespace details
377*9712f8acSEd Tanous 
378*9712f8acSEd Tanous template <typename... UnpackTypes>
379*9712f8acSEd Tanous bool readJson(const crow::Request& req, crow::Response& res, const char* key,
380*9712f8acSEd Tanous               UnpackTypes&... in)
381*9712f8acSEd Tanous {
382*9712f8acSEd Tanous     nlohmann::json jsonRequest;
383*9712f8acSEd Tanous     if (!json_util::processJsonFromRequest(res, req, jsonRequest))
384*9712f8acSEd Tanous     {
385*9712f8acSEd Tanous         BMCWEB_LOG_DEBUG << "Json value not readable";
386*9712f8acSEd Tanous         return false;
387*9712f8acSEd Tanous     }
388*9712f8acSEd Tanous     if (!jsonRequest.is_object())
389*9712f8acSEd Tanous     {
390*9712f8acSEd Tanous         BMCWEB_LOG_DEBUG << "Json value is not an object";
391*9712f8acSEd Tanous         messages::addMessageToErrorJson(res.jsonValue,
392*9712f8acSEd Tanous                                         messages::unrecognizedRequestBody());
393*9712f8acSEd Tanous         res.result(boost::beast::http::status::bad_request);
394*9712f8acSEd Tanous         return false;
395*9712f8acSEd Tanous     }
396*9712f8acSEd Tanous 
397*9712f8acSEd Tanous     if (jsonRequest.empty())
398*9712f8acSEd Tanous     {
399*9712f8acSEd Tanous         BMCWEB_LOG_DEBUG << "Json value is empty";
400*9712f8acSEd Tanous         messages::addMessageToErrorJson(res.jsonValue, messages::emptyJSON());
401*9712f8acSEd Tanous         res.result(boost::beast::http::status::bad_request);
402*9712f8acSEd Tanous         return false;
403*9712f8acSEd Tanous     }
404*9712f8acSEd Tanous 
405*9712f8acSEd Tanous     std::bitset<(sizeof...(in) + 1) / 2> handled(0);
406*9712f8acSEd Tanous     for (const auto& item : jsonRequest.items())
407*9712f8acSEd Tanous     {
408*9712f8acSEd Tanous         details::readJsonValues<(sizeof...(in) + 1) / 2, 0, UnpackTypes...>(
409*9712f8acSEd Tanous             item.key(), item.value(), res, handled, key, in...);
410*9712f8acSEd Tanous     }
411*9712f8acSEd Tanous 
412*9712f8acSEd Tanous     if (!handled.all())
413*9712f8acSEd Tanous     {
414*9712f8acSEd Tanous         details::handleMissing(handled, res, key, in...);
415*9712f8acSEd Tanous 
416*9712f8acSEd Tanous         return false;
417*9712f8acSEd Tanous     }
418*9712f8acSEd Tanous     return res.result() == boost::beast::http::status::ok;
419*9712f8acSEd Tanous }
42077dd8813SKowalski, Kamil 
42177dd8813SKowalski, Kamil } // namespace json_util
42277dd8813SKowalski, Kamil } // namespace redfish
423