bmcweb: Redfish away from json cache

In the original incarnation of bmcweb, route registration was done
automatically.  This has proved to be a terrible idea, wraught with
corner cases and issues.

The route registration is currently the only user of the
redfish::Node::json element.  Unfortunately, as written, this structure
consumes a lot of memory that's duplicated and not very useful.  From a
performance perspective, there is almost no difference between
rebuilding the structure for each GET request, and having the "cache"
that needs to be copied into the response and modified before it can be
useful.

In the programming tradeoffs for bmc, lower memory usage is more important
than latency, especially at these levels.

Change-Id: I785e8352123e5e886acf05cd59cb23648f93839d
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
diff --git a/redfish-core/include/node.hpp b/redfish-core/include/node.hpp
index 41257e0..049393f 100644
--- a/redfish-core/include/node.hpp
+++ b/redfish-core/include/node.hpp
@@ -67,69 +67,6 @@
 
     virtual ~Node() = default;
 
-    const std::string* getUrl() const
-    {
-        auto odataId = json.find("@odata.id");
-        if (odataId == json.end())
-        {
-            return nullptr;
-        }
-
-        return odataId->get_ptr<const std::string*>();
-    }
-
-    /**
-     * @brief Inserts subroute fields into for the node's json in the form:
-     *        "subroute_name" : { "odata.id": "node_url/subroute_name/" }
-     *        Excludes metadata urls starting with "$" and child urls having
-     *        more than one level.
-     *
-     * @return  None
-     */
-    void getSubRoutes(const std::vector<std::unique_ptr<Node>>& allNodes)
-    {
-        const std::string* url = getUrl();
-        if (url == nullptr)
-        {
-            // BMCWEB_LOG_CRITICAL << "Unable to get url for route";
-            return;
-        }
-
-        for (const auto& node : allNodes)
-        {
-            const std::string* route = node->getUrl();
-            if (route == nullptr)
-            {
-                // BMCWEB_LOG_CRITICAL << "Unable to get url for route";
-                continue;
-            }
-            if (boost::starts_with(*route, *url))
-            {
-                std::string subRoute = route->substr(url->size());
-                if (subRoute.empty())
-                {
-                    continue;
-                }
-
-                if (boost::starts_with(subRoute, "/"))
-                {
-                    subRoute.erase(0, 1);
-                }
-
-                if (boost::ends_with(subRoute, "/"))
-                {
-                    subRoute.pop_back();
-                }
-
-                if (!boost::starts_with(subRoute, "$") &&
-                    subRoute.find('/') == std::string::npos)
-                {
-                    json[subRoute] = nlohmann::json{{"@odata.id", *route}};
-                }
-            }
-        }
-    }
-
     OperationMap entityPrivileges;
 
   protected:
@@ -162,8 +99,6 @@
         res.end();
     }
 
-    nlohmann::json json;
-
   private:
     void dispatchRequest(CrowApp& app, const crow::Request& req,
                          crow::Response& res,
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index c2d64c2..2a61c52 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -103,11 +103,6 @@
         nodes.emplace_back(std::make_unique<SystemsCollection>(app));
         nodes.emplace_back(std::make_unique<Systems>(app));
         nodes.emplace_back(std::make_unique<SystemActionsReset>(app));
-
-        for (auto& node : nodes)
-        {
-            node->getSubRoutes(nodes);
-        }
     }
 
   private:
diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp
index 4e5d676..aba69c1 100644
--- a/redfish-core/lib/account_service.hpp
+++ b/redfish-core/lib/account_service.hpp
@@ -34,20 +34,6 @@
   public:
     AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
     {
-        Node::json["@odata.id"] = "/redfish/v1/AccountService";
-        Node::json["@odata.type"] = "#AccountService.v1_1_0.AccountService";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#AccountService.AccountService";
-        Node::json["Id"] = "AccountService";
-        Node::json["Description"] = "BMC User Accounts";
-        Node::json["Name"] = "Account Service";
-        Node::json["ServiceEnabled"] = true;
-        Node::json["MinPasswordLength"] = 1;
-        Node::json["MaxPasswordLength"] = 20;
-        Node::json["Accounts"]["@odata.id"] =
-            "/redfish/v1/AccountService/Accounts";
-        Node::json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
-
         entityPrivileges = {
             {boost::beast::http::verb::get,
              {{"ConfigureUsers"}, {"ConfigureManager"}}},
@@ -62,7 +48,21 @@
     void doGet(crow::Response& res, const crow::Request& req,
                const std::vector<std::string>& params) override
     {
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.id"] = "/redfish/v1/AccountService";
+        res.jsonValue["@odata.type"] = "#AccountService.v1_1_0.AccountService";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#AccountService.AccountService";
+        res.jsonValue["Id"] = "AccountService";
+        res.jsonValue["Description"] = "BMC User Accounts";
+        res.jsonValue["Name"] = "Account Service";
+        res.jsonValue["ServiceEnabled"] = true;
+        res.jsonValue["MinPasswordLength"] = 1;
+        res.jsonValue["MaxPasswordLength"] = 20;
+        res.jsonValue["Accounts"]["@odata.id"] =
+            "/redfish/v1/AccountService/Accounts";
+        res.jsonValue["Roles"]["@odata.id"] =
+            "/redfish/v1/AccountService/Roles";
+
         res.end();
     }
 };
@@ -72,16 +72,6 @@
     AccountsCollection(CrowApp& app) :
         Node(app, "/redfish/v1/AccountService/Accounts/")
     {
-
-        Node::json = {{"@odata.context", "/redfish/v1/"
-                                         "$metadata#ManagerAccountCollection."
-                                         "ManagerAccountCollection"},
-                      {"@odata.id", "/redfish/v1/AccountService/Accounts"},
-                      {"@odata.type", "#ManagerAccountCollection."
-                                      "ManagerAccountCollection"},
-                      {"Name", "Accounts Collection"},
-                      {"Description", "BMC User Accounts"}};
-
         entityPrivileges = {
             {boost::beast::http::verb::get,
              {{"ConfigureUsers"}, {"ConfigureManager"}}},
@@ -96,8 +86,17 @@
     void doGet(crow::Response& res, const crow::Request& req,
                const std::vector<std::string>& params) override
     {
-        res.jsonValue = Node::json;
         auto asyncResp = std::make_shared<AsyncResp>(res);
+        res.jsonValue = {{"@odata.context",
+                          "/redfish/v1/"
+                          "$metadata#ManagerAccountCollection."
+                          "ManagerAccountCollection"},
+                         {"@odata.id", "/redfish/v1/AccountService/Accounts"},
+                         {"@odata.type", "#ManagerAccountCollection."
+                                         "ManagerAccountCollection"},
+                         {"Name", "Accounts Collection"},
+                         {"Description", "BMC User Accounts"}};
+
         crow::connections::systemBus->async_method_call(
             [asyncResp](const boost::system::error_code ec,
                         const ManagedObjectType& users) {
@@ -247,19 +246,6 @@
     ManagerAccount(CrowApp& app) :
         Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
     {
-        Node::json = {{"@odata.context",
-                       "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
-                      {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
-
-                      {"Name", "User Account"},
-                      {"Description", "User Account"},
-                      {"Password", nullptr},
-                      {"RoleId", "Administrator"},
-                      {"Links",
-                       {{"Role",
-                         {{"@odata.id", "/redfish/v1/AccountService/Roles/"
-                                        "Administrator"}}}}}};
-
         entityPrivileges = {
             {boost::beast::http::verb::get,
              {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
@@ -274,7 +260,20 @@
     void doGet(crow::Response& res, const crow::Request& req,
                const std::vector<std::string>& params) override
     {
-        res.jsonValue = Node::json;
+        res.jsonValue = {
+            {"@odata.context",
+             "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
+            {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
+
+            {"Name", "User Account"},
+            {"Description", "User Account"},
+            {"Password", nullptr},
+            {"RoleId", "Administrator"},
+            {"Links",
+             {{"Role",
+               {{"@odata.id",
+                 "/redfish/v1/AccountService/Roles/Administrator"}}}}}};
+
         auto asyncResp = std::make_shared<AsyncResp>(res);
 
         if (params.size() != 1)
diff --git a/redfish-core/lib/chassis.hpp b/redfish-core/lib/chassis.hpp
index cec62d5..0f2b92b 100644
--- a/redfish-core/lib/chassis.hpp
+++ b/redfish-core/lib/chassis.hpp
@@ -45,12 +45,6 @@
   public:
     ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
     {
-        Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection";
-        Node::json["@odata.id"] = "/redfish/v1/Chassis";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
-        Node::json["Name"] = "Chassis Collection";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -73,7 +67,12 @@
             "xyz.openbmc_project.Inventory.Item.PowerSupply",
             "xyz.openbmc_project.Inventory.Item.System",
         };
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection";
+        res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
+        res.jsonValue["Name"] = "Chassis Collection";
+
         auto asyncResp = std::make_shared<AsyncResp>(res);
         crow::connections::systemBus->async_method_call(
             [asyncResp](const boost::system::error_code ec,
@@ -118,13 +117,6 @@
     Chassis(CrowApp &app) :
         Node(app, "/redfish/v1/Chassis/<str>/", std::string())
     {
-        Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis";
-        Node::json["@odata.id"] = "/redfish/v1/Chassis";
-        Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
-        Node::json["Name"] = "Chassis Collection";
-        Node::json["ChassisType"] = "RackMount";
-        Node::json["PowerState"] = "On";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -150,7 +142,14 @@
             return;
         }
 
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#Chassis.v1_4_0.Chassis";
+        res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#Chassis.Chassis";
+        res.jsonValue["Name"] = "Chassis Collection";
+        res.jsonValue["ChassisType"] = "RackMount";
+        res.jsonValue["PowerState"] = "On";
+
         const std::string &chassisId = params[0];
         auto asyncResp = std::make_shared<AsyncResp>(res);
         crow::connections::systemBus->async_method_call(
diff --git a/redfish-core/lib/cpudimm.hpp b/redfish-core/lib/cpudimm.hpp
index 120b2b5..6001d63 100644
--- a/redfish-core/lib/cpudimm.hpp
+++ b/redfish-core/lib/cpudimm.hpp
@@ -318,11 +318,6 @@
     ProcessorCollection(CrowApp &app) :
         Node(app, "/redfish/v1/Systems/<str>/Processors/", std::string())
     {
-
-        Node::json["@odata.type"] = "#ProcessorCollection.ProcessorCollection";
-        Node::json["Name"] = "Processor Collection";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#ProcessorCollection.ProcessorCollection";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -349,7 +344,12 @@
         }
         const std::string &name = params[0];
 
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] =
+            "#ProcessorCollection.ProcessorCollection";
+        res.jsonValue["Name"] = "Processor Collection";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#ProcessorCollection.ProcessorCollection";
+
         res.jsonValue["@odata.id"] =
             "/redfish/v1/Systems/" + name + "/Processors/";
         auto asyncResp = std::make_shared<AsyncResp>(res);
@@ -369,10 +369,6 @@
         Node(app, "/redfish/v1/Systems/<str>/Processors/<str>/", std::string(),
              std::string())
     {
-
-        Node::json["@odata.type"] = "#Processor.v1_1_0.Processor";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#Processor.Processor";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -400,8 +396,9 @@
         }
         const std::string &name = params[0];
         const std::string &cpuId = params[1];
-
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#Processor.v1_1_0.Processor";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#Processor.Processor";
         res.jsonValue["@odata.id"] =
             "/redfish/v1/Systems/" + name + "/Processors/" + cpuId;
 
@@ -420,11 +417,6 @@
     MemoryCollection(CrowApp &app) :
         Node(app, "/redfish/v1/Systems/<str>/Memory/", std::string())
     {
-
-        Node::json["@odata.type"] = "#MemoryCollection.MemoryCollection";
-        Node::json["Name"] = "Memory Module Collection";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#MemoryCollection.MemoryCollection";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -452,7 +444,10 @@
         }
         const std::string &name = params[0];
 
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection";
+        res.jsonValue["Name"] = "Memory Module Collection";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#MemoryCollection.MemoryCollection";
         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name + "/Memory/";
         auto asyncResp = std::make_shared<AsyncResp>(res);
 
@@ -471,9 +466,6 @@
         Node(app, "/redfish/v1/Systems/<str>/Memory/<str>/", std::string(),
              std::string())
     {
-
-        Node::json["@odata.type"] = "#Memory.v1_2_0.Memory";
-        Node::json["@odata.context"] = "/redfish/v1/$metadata#Memory.Memory";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -501,7 +493,8 @@
         const std::string &name = params[0];
         const std::string &dimmId = params[1];
 
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#Memory.v1_2_0.Memory";
+        res.jsonValue["@odata.context"] = "/redfish/v1/$metadata#Memory.Memory";
         res.jsonValue["@odata.id"] =
             "/redfish/v1/Systems/" + name + "/Memory/" + dimmId;
         auto asyncResp = std::make_shared<AsyncResp>(res);
diff --git a/redfish-core/lib/ethernet.hpp b/redfish-core/lib/ethernet.hpp
index c44c63f..8712710 100644
--- a/redfish-core/lib/ethernet.hpp
+++ b/redfish-core/lib/ethernet.hpp
@@ -766,16 +766,6 @@
     EthernetCollection(CrowApp &app) :
         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
     {
-        Node::json["@odata.type"] =
-            "#EthernetInterfaceCollection.EthernetInterfaceCollection";
-        Node::json["@odata.context"] =
-            "/redfish/v1/"
-            "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
-        Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/EthernetInterfaces";
-        Node::json["Name"] = "Ethernet Network Interface Collection";
-        Node::json["Description"] =
-            "Collection of EthernetInterfaces for this Manager";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -792,7 +782,17 @@
     void doGet(crow::Response &res, const crow::Request &req,
                const std::vector<std::string> &params) override
     {
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] =
+            "#EthernetInterfaceCollection.EthernetInterfaceCollection";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/"
+            "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
+        res.jsonValue["@odata.id"] =
+            "/redfish/v1/Managers/bmc/EthernetInterfaces";
+        res.jsonValue["Name"] = "Ethernet Network Interface Collection";
+        res.jsonValue["Description"] =
+            "Collection of EthernetInterfaces for this Manager";
+
         // Get eth interface list, and call the below callback for JSON
         // preparation
         getEthernetIfaceList(
@@ -837,13 +837,6 @@
         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
              std::string())
     {
-        Node::json["@odata.type"] =
-            "#EthernetInterface.v1_2_0.EthernetInterface";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
-        Node::json["Name"] = "Manager Ethernet Interface";
-        Node::json["Description"] = "Management Network Interface";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -1236,13 +1229,11 @@
         }
     }
 
-    nlohmann::json parseInterfaceData(
-        const std::string &iface_id, const EthernetInterfaceData &ethData,
+    void parseInterfaceData(
+        nlohmann::json &json_response, const std::string &iface_id,
+        const EthernetInterfaceData &ethData,
         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
     {
-        // Copy JSON object to avoid race condition
-        nlohmann::json json_response(Node::json);
-
         json_response["Id"] = iface_id;
         json_response["@odata.id"] =
             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
@@ -1285,8 +1276,6 @@
                 }
             }
         }
-
-        return json_response;
     }
 
     /**
@@ -1315,8 +1304,16 @@
                                                "EthernetInterface", iface_id);
                     return;
                 }
-                asyncResp->res.jsonValue =
-                    parseInterfaceData(iface_id, ethData, ipv4Data);
+                asyncResp->res.jsonValue["@odata.type"] =
+                    "#EthernetInterface.v1_2_0.EthernetInterface";
+                asyncResp->res.jsonValue["@odata.context"] =
+                    "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
+                asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
+                asyncResp->res.jsonValue["Description"] =
+                    "Management Network Interface";
+
+                parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
+                                   ipv4Data);
             });
     }
 
@@ -1355,8 +1352,8 @@
                     return;
                 }
 
-                asyncResp->res.jsonValue =
-                    parseInterfaceData(iface_id, ethData, ipv4Data);
+                parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
+                                   ipv4Data);
 
                 for (auto propertyIt : patchReq.items())
                 {
@@ -1414,21 +1411,11 @@
      * Default Constructor
      */
     template <typename CrowApp>
-    // TODO(Pawel) Remove line from below, where we assume that there is only
-    // one manager called openbmc.  This shall be generic, but requires to
-    // update GetSubroutes method
     VlanNetworkInterface(CrowApp &app) :
         Node(app,
-             "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>>/VLANs/"
-             "<str>",
+             "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
              std::string(), std::string())
     {
-        Node::json["@odata.type"] =
-            "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
-        Node::json["Name"] = "VLAN Network Interface";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -1439,14 +1426,11 @@
     }
 
   private:
-    nlohmann::json parseInterfaceData(
-        const std::string &parent_iface_id, const std::string &iface_id,
-        const EthernetInterfaceData &ethData,
+    void parseInterfaceData(
+        nlohmann::json &json_response, const std::string &parent_iface_id,
+        const std::string &iface_id, const EthernetInterfaceData &ethData,
         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
     {
-        // Copy JSON object to avoid race condition
-        nlohmann::json json_response(Node::json);
-
         // Fill out obvious data...
         json_response["Id"] = iface_id;
         json_response["@odata.id"] =
@@ -1458,7 +1442,6 @@
         {
             json_response["VLANId"] = *ethData.vlan_id;
         }
-        return json_response;
     }
 
     bool verifyNames(crow::Response &res, const std::string &parent,
@@ -1497,6 +1480,11 @@
 
         const std::string &parent_iface_id = params[0];
         const std::string &iface_id = params[1];
+        res.jsonValue["@odata.type"] =
+            "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
+        res.jsonValue["Name"] = "VLAN Network Interface";
 
         if (!verifyNames(res, parent_iface_id, iface_id))
         {
@@ -1512,8 +1500,9 @@
                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
                 if (success && ethData.vlan_id)
                 {
-                    asyncResp->res.jsonValue = parseInterfaceData(
-                        parent_iface_id, iface_id, ethData, ipv4Data);
+                    parseInterfaceData(asyncResp->res.jsonValue,
+                                       parent_iface_id, iface_id, ethData,
+                                       ipv4Data);
                 }
                 else
                 {
@@ -1568,8 +1557,8 @@
                     return;
                 }
 
-                asyncResp->res.jsonValue = parseInterfaceData(
-                    parentIfaceId, ifaceId, ethData, ipv4Data);
+                parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
+                                   ifaceId, ethData, ipv4Data);
 
                 for (auto propertyIt : patchReq.items())
                 {
@@ -1626,8 +1615,8 @@
                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
                 if (success && ethData.vlan_id)
                 {
-                    asyncResp->res.jsonValue = parseInterfaceData(
-                        parentIfaceId, ifaceId, ethData, ipv4Data);
+                    parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
+                                       ifaceId, ethData, ipv4Data);
 
                     auto callback =
                         [asyncResp](const boost::system::error_code ec) {
@@ -1661,20 +1650,10 @@
 {
   public:
     template <typename CrowApp>
-    // TODO(Pawel) Remove line from below, where we assume that there is only
-    // one manager called openbmc.  This shall be generic, but requires to
-    // update GetSubroutes method
     VlanNetworkInterfaceCollection(CrowApp &app) :
         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
              std::string())
     {
-        Node::json["@odata.type"] =
-            "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata"
-            "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
-        Node::json["Name"] = "VLAN Network Interface Collection";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -1713,7 +1692,15 @@
                     messages::internalError(asyncResp->res);
                     return;
                 }
-                asyncResp->res.jsonValue = Node::json;
+                asyncResp->res.jsonValue["@odata.type"] =
+                    "#VLanNetworkInterfaceCollection."
+                    "VLanNetworkInterfaceCollection";
+                asyncResp->res.jsonValue["@odata.context"] =
+                    "/redfish/v1/$metadata"
+                    "#VLanNetworkInterfaceCollection."
+                    "VLanNetworkInterfaceCollection";
+                asyncResp->res.jsonValue["Name"] =
+                    "VLAN Network Interface Collection";
 
                 nlohmann::json iface_array = nlohmann::json::array();
 
@@ -1759,8 +1746,8 @@
             return;
         }
 
-        auto vlanIdJson = json.find("VLANId");
-        if (vlanIdJson == json.end())
+        auto vlanIdJson = postReq.find("VLANId");
+        if (vlanIdJson == postReq.end())
         {
             messages::propertyMissing(asyncResp->res, "VLANId");
             return;
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index 2dda752..cf4af02 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -617,9 +617,6 @@
     BMCLogServiceCollection(CrowApp &app) :
         Node(app, "/redfish/v1/Managers/bmc/LogServices/")
     {
-        // Collections use static ID for SubRoute to add to its parent, but only
-        // load dynamic data so the duplicate static members don't get displayed
-        Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -670,9 +667,6 @@
     BMCJournalLogService(CrowApp &app) :
         Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
     {
-        // Set the id for SubRoute
-        Node::json["@odata.id"] =
-            "/redfish/v1/Managers/bmc/LogServices/Journal";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -687,10 +681,10 @@
                const std::vector<std::string> &params) override
     {
         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
-        // Copy over the static data to include the entries added by SubRoute
-        asyncResp->res.jsonValue = Node::json;
         asyncResp->res.jsonValue["@odata.type"] =
             "#LogService.v1_1_0.LogService";
+        asyncResp->res.jsonValue["@odata.id"] =
+            "/redfish/v1/Managers/bmc/LogServices/Journal";
         asyncResp->res.jsonValue["@odata.context"] =
             "/redfish/v1/$metadata#LogService.LogService";
         asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
@@ -756,10 +750,6 @@
     BMCJournalLogEntryCollection(CrowApp &app) :
         Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
     {
-        // Collections use static ID for SubRoute to add to its parent, but only
-        // load dynamic data so the duplicate static members don't get displayed
-        Node::json["@odata.id"] =
-            "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -789,6 +779,8 @@
         // it has a duplicate entry for members
         asyncResp->res.jsonValue["@odata.type"] =
             "#LogEntryCollection.LogEntryCollection";
+        asyncResp->res.jsonValue["@odata.id"] =
+            "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
         asyncResp->res.jsonValue["@odata.context"] =
             "/redfish/v1/$metadata#LogEntryCollection.LogEntryCollection";
         asyncResp->res.jsonValue["@odata.id"] =
@@ -796,6 +788,8 @@
         asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
         asyncResp->res.jsonValue["Description"] =
             "Collection of BMC Journal Entries";
+        asyncResp->res.jsonValue["@odata.id"] =
+            "/redfish/v1/Managers/bmc/LogServices/BmcLog/Entries";
         nlohmann::json &logEntryArray = asyncResp->res.jsonValue["Members"];
         logEntryArray = nlohmann::json::array();
 
@@ -924,8 +918,6 @@
     CPULogService(CrowApp &app) :
         Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/")
     {
-        // Set the id for SubRoute
-        Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/CpuLog";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -944,7 +936,8 @@
     {
         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
         // Copy over the static data to include the entries added by SubRoute
-        asyncResp->res.jsonValue = Node::json;
+        asyncResp->res.jsonValue["@odata.id"] =
+            "/redfish/v1/Managers/bmc/LogServices/CpuLog";
         asyncResp->res.jsonValue["@odata.type"] =
             "#LogService.v1_1_0.LogService";
         asyncResp->res.jsonValue["@odata.context"] =
@@ -976,10 +969,6 @@
     CPULogEntryCollection(CrowApp &app) :
         Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries/")
     {
-        // Collections use static ID for SubRoute to add to its parent, but only
-        // load dynamic data so the duplicate static members don't get displayed
-        Node::json["@odata.id"] =
-            "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -1015,6 +1004,8 @@
             }
             asyncResp->res.jsonValue["@odata.type"] =
                 "#LogEntryCollection.LogEntryCollection";
+            asyncResp->res.jsonValue["@odata.id"] =
+                "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries";
             asyncResp->res.jsonValue["@odata.context"] =
                 "/redfish/v1/$metadata#LogEntryCollection.LogEntryCollection";
             asyncResp->res.jsonValue["@odata.id"] =
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index d4e7344..44725b1 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -44,18 +44,6 @@
 
   private:
     /**
-     * Function handles GET method request.
-     * ManagerActionReset supports for POST method,
-     * it is not required to retrieve more information in GET.
-     */
-    void doGet(crow::Response& res, const crow::Request& req,
-               const std::vector<std::string>& params) override
-    {
-        res.jsonValue = Node::json;
-        res.end();
-    }
-
-    /**
      * Function handles POST method request.
      * Analyzes POST body message before sends Reset request data to dbus.
      * OpenBMC allows for ResetType is GracefulRestart only.
@@ -614,21 +602,8 @@
   public:
     Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/")
     {
-        Node::json["@odata.id"] = "/redfish/v1/Managers/bmc";
-        Node::json["@odata.type"] = "#Manager.v1_3_0.Manager";
-        Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager";
-        Node::json["Id"] = "bmc";
-        Node::json["Name"] = "OpenBmc Manager";
-        Node::json["Description"] = "Baseboard Management Controller";
-        Node::json["PowerState"] = "On";
-        Node::json["ManagerType"] = "BMC";
-        Node::json["UUID"] =
-            app.template getMiddleware<crow::persistent_data::Middleware>()
-                .systemUuid;
-        Node::json["Model"] = "OpenBmc"; // TODO(ed), get model
-        Node::json["EthernetInterfaces"] = {
-            {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
-
+        uuid = app.template getMiddleware<crow::persistent_data::Middleware>()
+                   .systemUuid;
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -636,17 +611,6 @@
             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
-
-        // default oem data
-        nlohmann::json& oem = Node::json["Oem"];
-        nlohmann::json& oemOpenbmc = oem["OpenBmc"];
-        oem["@odata.type"] = "#OemManager.Oem";
-        oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
-        oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
-        oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
-        oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
-        oemOpenbmc["@odata.context"] =
-            "/redfish/v1/$metadata#OemManager.OpenBmc";
     }
 
   private:
@@ -719,16 +683,48 @@
     void doGet(crow::Response& res, const crow::Request& req,
                const std::vector<std::string>& params) override
     {
+        res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc";
+        res.jsonValue["@odata.type"] = "#Manager.v1_3_0.Manager";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#Manager.Manager";
+        res.jsonValue["Id"] = "bmc";
+        res.jsonValue["Name"] = "OpenBmc Manager";
+        res.jsonValue["Description"] = "Baseboard Management Controller";
+        res.jsonValue["PowerState"] = "On";
+        res.jsonValue["ManagerType"] = "BMC";
+        res.jsonValue["UUID"] =
+
+            res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model
+
+        res.jsonValue["LogServices"] = {
+            {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}};
+
+        res.jsonValue["NetworkProtocol"] = {
+            {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}};
+
+        res.jsonValue["EthernetInterfaces"] = {
+            {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}};
+        // default oem data
+        nlohmann::json& oem = res.jsonValue["Oem"];
+        nlohmann::json& oemOpenbmc = oem["OpenBmc"];
+        oem["@odata.type"] = "#OemManager.Oem";
+        oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem";
+        oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem";
+        oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc";
+        oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc";
+        oemOpenbmc["@odata.context"] =
+            "/redfish/v1/$metadata#OemManager.OpenBmc";
+
         // Update Actions object.
-        nlohmann::json& manager_reset = Node::json["Actions"]["#Manager.Reset"];
+        nlohmann::json& manager_reset =
+            res.jsonValue["Actions"]["#Manager.Reset"];
         manager_reset["target"] =
             "/redfish/v1/Managers/bmc/Actions/Manager.Reset";
         manager_reset["ResetType@Redfish.AllowableValues"] = {
             "GracefulRestart"};
 
-        Node::json["DateTime"] = getDateTime();
+        res.jsonValue["DateTime"] = getDateTime();
         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
-        asyncResp->res.jsonValue = Node::json;
 
         crow::connections::systemBus->async_method_call(
             [asyncResp](const boost::system::error_code ec,
@@ -1021,6 +1017,8 @@
 
         return redfishDateTime;
     }
+
+    std::string uuid;
 };
 
 class ManagerCollection : public Node
@@ -1028,14 +1026,6 @@
   public:
     ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
     {
-        Node::json["@odata.id"] = "/redfish/v1/Managers";
-        Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
-        Node::json["Name"] = "Manager Collection";
-        Node::json["Members@odata.count"] = 1;
-        Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/bmc"}}};
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
diff --git a/redfish-core/lib/network_protocol.hpp b/redfish-core/lib/network_protocol.hpp
index a46cb47..47244e0 100644
--- a/redfish-core/lib/network_protocol.hpp
+++ b/redfish-core/lib/network_protocol.hpp
@@ -73,24 +73,6 @@
     NetworkProtocol(CrowApp& app) :
         Node(app, "/redfish/v1/Managers/bmc/NetworkProtocol")
     {
-        Node::json["@odata.type"] =
-            "#ManagerNetworkProtocol.v1_1_0.ManagerNetworkProtocol";
-        Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/NetworkProtocol";
-        Node::json["@odata.context"] =
-            "/redfish/v1/"
-            "$metadata#ManagerNetworkProtocol.ManagerNetworkProtocol";
-        Node::json["Id"] = "NetworkProtocol";
-        Node::json["Name"] = "Manager Network Protocol";
-        Node::json["Description"] = "Manager Network Service";
-        Node::json["Status"]["Health"] = "OK";
-        Node::json["Status"]["HealthRollup"] = "OK";
-        Node::json["Status"]["State"] = "Enabled";
-
-        for (auto& protocol : protocolToDBus)
-        {
-            Node::json[protocol.first]["ProtocolEnabled"] = false;
-        }
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -123,8 +105,26 @@
 
     void getData(const std::shared_ptr<AsyncResp>& asyncResp)
     {
-        Node::json["HostName"] = getHostName();
-        asyncResp->res.jsonValue = Node::json;
+        asyncResp->res.jsonValue["@odata.type"] =
+            "#ManagerNetworkProtocol.v1_1_0.ManagerNetworkProtocol";
+        asyncResp->res.jsonValue["@odata.id"] =
+            "/redfish/v1/Managers/bmc/NetworkProtocol";
+        asyncResp->res.jsonValue["@odata.context"] =
+            "/redfish/v1/"
+            "$metadata#ManagerNetworkProtocol.ManagerNetworkProtocol";
+        asyncResp->res.jsonValue["Id"] = "NetworkProtocol";
+        asyncResp->res.jsonValue["Name"] = "Manager Network Protocol";
+        asyncResp->res.jsonValue["Description"] = "Manager Network Service";
+        asyncResp->res.jsonValue["Status"]["Health"] = "OK";
+        asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK";
+        asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
+
+        for (auto& protocol : protocolToDBus)
+        {
+            asyncResp->res.jsonValue[protocol.first]["ProtocolEnabled"] = false;
+        }
+
+        asyncResp->res.jsonValue["HostName"] = getHostName();
 
         crow::connections::systemBus->async_method_call(
             [asyncResp](const boost::system::error_code ec,
diff --git a/redfish-core/lib/power.hpp b/redfish-core/lib/power.hpp
index dc291f1..0cb1aa0 100644
--- a/redfish-core/lib/power.hpp
+++ b/redfish-core/lib/power.hpp
@@ -28,11 +28,6 @@
     Power(CrowApp& app) :
         Node((app), "/redfish/v1/Chassis/<str>/Power/", std::string())
     {
-        Node::json["@odata.type"] = "#Power.v1_2_1.Power";
-        Node::json["@odata.context"] = "/redfish/v1/$metadata#Power.Power";
-        Node::json["Id"] = "Power";
-        Node::json["Name"] = "Power";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -54,9 +49,12 @@
         }
         const std::string& chassis_name = params[0];
 
-        Node::json["@odata.id"] =
+        res.jsonValue["@odata.id"] =
             "/redfish/v1/Chassis/" + chassis_name + "/Power";
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#Power.v1_2_1.Power";
+        res.jsonValue["@odata.context"] = "/redfish/v1/$metadata#Power.Power";
+        res.jsonValue["Id"] = "Power";
+        res.jsonValue["Name"] = "Power";
         auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
             res, chassis_name,
             std::initializer_list<const char*>{
diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp
index 68449c0..5b69c1a 100644
--- a/redfish-core/lib/redfish_sessions.hpp
+++ b/redfish-core/lib/redfish_sessions.hpp
@@ -30,11 +30,6 @@
     Sessions(CrowApp& app) :
         Node(app, "/redfish/v1/SessionService/Sessions/<str>/", std::string())
     {
-        Node::json["@odata.type"] = "#Session.v1_0_2.Session";
-        Node::json["@odata.context"] = "/redfish/v1/$metadata#Session.Session";
-        Node::json["Name"] = "User Session";
-        Node::json["Description"] = "Manager User Session";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -59,12 +54,16 @@
             return;
         }
 
-        Node::json["Id"] = session->uniqueId;
-        Node::json["UserName"] = session->username;
-        Node::json["@odata.id"] =
+        res.jsonValue["Id"] = session->uniqueId;
+        res.jsonValue["UserName"] = session->username;
+        res.jsonValue["@odata.id"] =
             "/redfish/v1/SessionService/Sessions/" + session->uniqueId;
+        res.jsonValue["@odata.type"] = "#Session.v1_0_2.Session";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#Session.Session";
+        res.jsonValue["Name"] = "User Session";
+        res.jsonValue["Description"] = "Manager User Session";
 
-        res.jsonValue = Node::json;
         res.end();
     }
 
@@ -116,15 +115,6 @@
     SessionCollection(CrowApp& app) :
         Node(app, "/redfish/v1/SessionService/Sessions/"), memberSession(app)
     {
-        Node::json["@odata.type"] = "#SessionCollection.SessionCollection";
-        Node::json["@odata.id"] = "/redfish/v1/SessionService/Sessions/";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#SessionCollection.SessionCollection";
-        Node::json["Name"] = "Session Collection";
-        Node::json["Description"] = "Session Collection";
-        Node::json["Members@odata.count"] = 0;
-        Node::json["Members"] = nlohmann::json::array();
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -142,15 +132,21 @@
             crow::persistent_data::SessionStore::getInstance().getUniqueIds(
                 false, crow::persistent_data::PersistenceType::TIMEOUT);
 
-        Node::json["Members@odata.count"] = sessionIds.size();
-        Node::json["Members"] = nlohmann::json::array();
+        res.jsonValue["Members@odata.count"] = sessionIds.size();
+        res.jsonValue["Members"] = nlohmann::json::array();
         for (const std::string* uid : sessionIds)
         {
-            Node::json["Members"].push_back(
+            res.jsonValue["Members"].push_back(
                 {{"@odata.id", "/redfish/v1/SessionService/Sessions/" + *uid}});
         }
-
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#SessionCollection.SessionCollection";
+        res.jsonValue["@odata.id"] = "/redfish/v1/SessionService/Sessions/";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#SessionCollection.SessionCollection";
+        res.jsonValue["Name"] = "Session Collection";
+        res.jsonValue["Description"] = "Session Collection";
+        res.jsonValue["Members@odata.count"] = 0;
+        res.jsonValue["Members"] = nlohmann::json::array();
         res.end();
     }
 
@@ -215,17 +211,6 @@
   public:
     SessionService(CrowApp& app) : Node(app, "/redfish/v1/SessionService/")
     {
-        Node::json["@odata.type"] = "#SessionService.v1_0_2.SessionService";
-        Node::json["@odata.id"] = "/redfish/v1/SessionService/";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#SessionService.SessionService";
-        Node::json["Name"] = "Session Service";
-        Node::json["Id"] = "SessionService";
-        Node::json["Description"] = "Session Service";
-        Node::json["SessionTimeout"] =
-            crow::persistent_data::SessionStore::getInstance()
-                .getTimeoutInSeconds();
-        Node::json["ServiceEnabled"] = true;
 
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
@@ -240,7 +225,18 @@
     void doGet(crow::Response& res, const crow::Request& req,
                const std::vector<std::string>& params) override
     {
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#SessionService.v1_0_2.SessionService";
+        res.jsonValue["@odata.id"] = "/redfish/v1/SessionService/";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#SessionService.SessionService";
+        res.jsonValue["Name"] = "Session Service";
+        res.jsonValue["Id"] = "SessionService";
+        res.jsonValue["Description"] = "Session Service";
+        res.jsonValue["SessionTimeout"] =
+            crow::persistent_data::SessionStore::getInstance()
+                .getTimeoutInSeconds();
+        res.jsonValue["ServiceEnabled"] = true;
+
         res.end();
     }
 };
diff --git a/redfish-core/lib/roles.hpp b/redfish-core/lib/roles.hpp
index 258eed3..5e711b1 100644
--- a/redfish-core/lib/roles.hpp
+++ b/redfish-core/lib/roles.hpp
@@ -26,18 +26,6 @@
     Roles(CrowApp& app) :
         Node(app, "/redfish/v1/AccountService/Roles/Administrator/")
     {
-        Node::json["@odata.id"] =
-            "/redfish/v1/AccountService/Roles/Administrator";
-        Node::json["@odata.type"] = "#Role.v1_0_2.Role";
-        Node::json["@odata.context"] = "/redfish/v1/$metadata#Role.Role";
-        Node::json["Id"] = "Administrator";
-        Node::json["Name"] = "User Role";
-        Node::json["Description"] = "Administrator User Role";
-        Node::json["IsPredefined"] = true;
-        Node::json["AssignedPrivileges"] = {"Login", "ConfigureManager",
-                                            "ConfigureUsers", "ConfigureSelf",
-                                            "ConfigureComponents"};
-        Node::json["OemPrivileges"] = nlohmann::json::array();
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -51,7 +39,18 @@
     void doGet(crow::Response& res, const crow::Request& req,
                const std::vector<std::string>& params) override
     {
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.id"] =
+            "/redfish/v1/AccountService/Roles/Administrator";
+        res.jsonValue["@odata.type"] = "#Role.v1_0_2.Role";
+        res.jsonValue["@odata.context"] = "/redfish/v1/$metadata#Role.Role";
+        res.jsonValue["Id"] = "Administrator";
+        res.jsonValue["Name"] = "User Role";
+        res.jsonValue["Description"] = "Administrator User Role";
+        res.jsonValue["IsPredefined"] = true;
+        res.jsonValue["AssignedPrivileges"] = {
+            "Login", "ConfigureManager", "ConfigureUsers", "ConfigureSelf",
+            "ConfigureComponents"};
+        res.jsonValue["OemPrivileges"] = nlohmann::json::array();
         res.end();
     }
 };
@@ -62,16 +61,6 @@
     RoleCollection(CrowApp& app) :
         Node(app, "/redfish/v1/AccountService/Roles/")
     {
-        Node::json["@odata.id"] = "/redfish/v1/AccountService/Roles";
-        Node::json["@odata.type"] = "#RoleCollection.RoleCollection";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#RoleCollection.RoleCollection";
-        Node::json["Name"] = "Roles Collection";
-        Node::json["Description"] = "BMC User Roles";
-        Node::json["Members@odata.count"] = 1;
-        Node::json["Members"] = {
-            {{"@odata.id", "/redfish/v1/AccountService/Roles/Administrator"}}};
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -85,12 +74,15 @@
     void doGet(crow::Response& res, const crow::Request& req,
                const std::vector<std::string>& params) override
     {
-        res.jsonValue = Node::json;
-        // This is a short term solution to work around a bug.  GetSubroutes
-        // accidentally recognizes the Roles/Administrator route as a subroute
-        // (because it's hardcoded to a single entity).  Remove this line when
-        // that is resolved
-        res.jsonValue.erase("Administrator");
+        res.jsonValue["@odata.id"] = "/redfish/v1/AccountService/Roles";
+        res.jsonValue["@odata.type"] = "#RoleCollection.RoleCollection";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#RoleCollection.RoleCollection";
+        res.jsonValue["Name"] = "Roles Collection";
+        res.jsonValue["Description"] = "BMC User Roles";
+        res.jsonValue["Members@odata.count"] = 1;
+        res.jsonValue["Members"] = {
+            {{"@odata.id", "/redfish/v1/AccountService/Roles/Administrator"}}};
         res.end();
     }
 };
diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp
index 3a31076..296ad92 100644
--- a/redfish-core/lib/service_root.hpp
+++ b/redfish-core/lib/service_root.hpp
@@ -27,20 +27,6 @@
   public:
     ServiceRoot(CrowApp& app) : Node(app, "/redfish/v1/")
     {
-        Node::json["@odata.type"] = "#ServiceRoot.v1_1_1.ServiceRoot";
-        Node::json["@odata.id"] = "/redfish/v1/";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#ServiceRoot.ServiceRoot";
-        Node::json["Id"] = "RootService";
-        Node::json["Name"] = "Root Service";
-        Node::json["RedfishVersion"] = "1.1.0";
-        Node::json["Links"]["Sessions"] = {
-            {"@odata.id", "/redfish/v1/SessionService/Sessions"}};
-        Node::json["JsonSchemas"] = {{"@odata.id", "/redfish/v1/JsonSchemas"}};
-        Node::json["Registries"] = {{"@odata.id", "/redfish/v1/Registries"}};
-
-        Node::json["UUID"] = getUuid();
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {}},
             {boost::beast::http::verb::head, {}},
@@ -54,7 +40,29 @@
     void doGet(crow::Response& res, const crow::Request& req,
                const std::vector<std::string>& params) override
     {
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#ServiceRoot.v1_1_1.ServiceRoot";
+        res.jsonValue["@odata.id"] = "/redfish/v1/";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#ServiceRoot.ServiceRoot";
+        res.jsonValue["Id"] = "RootService";
+        res.jsonValue["Name"] = "Root Service";
+        res.jsonValue["RedfishVersion"] = "1.1.0";
+        res.jsonValue["Links"]["Sessions"] = {
+            {"@odata.id", "/redfish/v1/SessionService/Sessions"}};
+        res.jsonValue["AccountService"] = {
+            {"@odata.id", "/redfish/v1/AccountService"}};
+        res.jsonValue["Chassis"] = {{"@odata.id", "/redfish/v1/Chassis"}};
+        res.jsonValue["JsonSchemas"] = {
+            {"@odata.id", "/redfish/v1/JsonSchemas"}};
+        res.jsonValue["SessionService"] = {
+            {"@odata.id", "/redfish/v1/UpdateService"}};
+        res.jsonValue["Systems"] = {{"@odata.id", "/redfish/v1/Systems"}};
+        res.jsonValue["Registries"] = {{"@odata.id", "/redfish/v1/Registries"}};
+
+        res.jsonValue["UpdateService"] = {
+            {"@odata.id", "/redfish/v1/UpdateService"}};
+
+        res.jsonValue["UUID"] = getUuid();
         res.end();
     }
 
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index 67d0124..7d0cc02 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -480,14 +480,6 @@
   public:
     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
     {
-        Node::json["@odata.type"] =
-            "#ComputerSystemCollection.ComputerSystemCollection";
-        Node::json["@odata.id"] = "/redfish/v1/Systems";
-        Node::json["@odata.context"] =
-            "/redfish/v1/"
-            "$metadata#ComputerSystemCollection.ComputerSystemCollection";
-        Node::json["Name"] = "Computer System Collection";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -503,7 +495,13 @@
     {
         BMCWEB_LOG_DEBUG << "Get list of available boards.";
         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] =
+            "#ComputerSystemCollection.ComputerSystemCollection";
+        res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/"
+            "$metadata#ComputerSystemCollection.ComputerSystemCollection";
+        res.jsonValue["Name"] = "Computer System Collection";
         crow::connections::systemBus->async_method_call(
             [asyncResp](const boost::system::error_code ec,
                         const std::vector<std::string> &resp) {
@@ -652,25 +650,6 @@
     Systems(CrowApp &app) :
         Node(app, "/redfish/v1/Systems/<str>/", std::string())
     {
-        Node::json["@odata.type"] = "#ComputerSystem.v1_3_0.ComputerSystem";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
-        Node::json["SystemType"] = "Physical";
-        Node::json["Description"] = "Computer System";
-        Node::json["Boot"]["BootSourceOverrideEnabled"] =
-            "Disabled"; // TODO(Dawid), get real boot data
-        Node::json["Boot"]["BootSourceOverrideTarget"] =
-            "None"; // TODO(Dawid), get real boot data
-        Node::json["Boot"]["BootSourceOverrideMode"] =
-            "Legacy"; // TODO(Dawid), get real boot data
-        Node::json["Boot"]["BootSourceOverrideTarget@Redfish.AllowableValues"] =
-            {"None",      "Pxe",       "Hdd", "Cd",
-             "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot
-                                               // data
-        Node::json["ProcessorSummary"]["Count"] = 0;
-        Node::json["ProcessorSummary"]["Status"]["State"] = "Disabled";
-        Node::json["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
-        Node::json["MemorySummary"]["Status"]["State"] = "Disabled";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -698,7 +677,26 @@
 
         const std::string &name = params[0];
 
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#ComputerSystem.v1_3_0.ComputerSystem";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
+        res.jsonValue["SystemType"] = "Physical";
+        res.jsonValue["Description"] = "Computer System";
+        res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
+            "Disabled"; // TODO(Dawid), get real boot data
+        res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
+            "None"; // TODO(Dawid), get real boot data
+        res.jsonValue["Boot"]["BootSourceOverrideMode"] =
+            "Legacy"; // TODO(Dawid), get real boot data
+        res.jsonValue["Boot"]
+                     ["BootSourceOverrideTarget@Redfish.AllowableValues"] = {
+            "None",      "Pxe",       "Hdd", "Cd",
+            "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot
+                                              // data
+        res.jsonValue["ProcessorSummary"]["Count"] = 0;
+        res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
+        res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
+        res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
 
         res.jsonValue["Processors"] = {
@@ -757,8 +755,7 @@
 
         const std::string &name = params[0];
 
-        res.jsonValue = Node::json;
-        res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
+        messages::success(asyncResp->res);
 
         std::string indicatorLedTemp;
         boost::optional<std::string> indicatorLed = indicatorLedTemp;
@@ -828,8 +825,6 @@
                         return;
                     }
                     BMCWEB_LOG_DEBUG << "Led state update done.";
-                    asyncResp->res.jsonValue["IndicatorLED"] =
-                        std::move(indicatorLed);
                 },
                 "xyz.openbmc_project.LED.Controller.identify",
                 "/xyz/openbmc_project/led/physical/identify",
diff --git a/redfish-core/lib/thermal.hpp b/redfish-core/lib/thermal.hpp
index cbc45e1..d0fbccf 100644
--- a/redfish-core/lib/thermal.hpp
+++ b/redfish-core/lib/thermal.hpp
@@ -27,11 +27,6 @@
     Thermal(CrowApp& app) :
         Node((app), "/redfish/v1/Chassis/<str>/Thermal/", std::string())
     {
-        Node::json["@odata.type"] = "#Thermal.v1_4_0.Thermal";
-        Node::json["@odata.context"] = "/redfish/v1/$metadata#Thermal.Thermal";
-        Node::json["Id"] = "Thermal";
-        Node::json["Name"] = "Thermal";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -53,12 +48,15 @@
         }
         const std::string& chassisName = params[0];
 
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#Thermal.Thermal";
+        res.jsonValue["Id"] = "Thermal";
+        res.jsonValue["Name"] = "Thermal";
 
-        Node::json["@odata.id"] =
+        res.jsonValue["@odata.id"] =
             "/redfish/v1/Chassis/" + chassisName + "/Thermal";
 
-        res.jsonValue = Node::json;
         auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
             res, chassisName,
             std::initializer_list<const char*>{
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index 74638bb..f600c14 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -29,19 +29,6 @@
   public:
     UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/")
     {
-        Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
-        Node::json["@odata.id"] = "/redfish/v1/UpdateService";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#UpdateService.UpdateService";
-        Node::json["Id"] = "UpdateService";
-        Node::json["Description"] = "Service for Software Update";
-        Node::json["Name"] = "Update Service";
-        Node::json["HttpPushUri"] = "/redfish/v1/UpdateService";
-        // UpdateService cannot be disabled
-        Node::json["ServiceEnabled"] = true;
-        Node::json["FirmwareInventory"] = {
-            {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -55,7 +42,18 @@
     void doGet(crow::Response &res, const crow::Request &req,
                const std::vector<std::string> &params) override
     {
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
+        res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#UpdateService.UpdateService";
+        res.jsonValue["Id"] = "UpdateService";
+        res.jsonValue["Description"] = "Service for Software Update";
+        res.jsonValue["Name"] = "Update Service";
+        res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService";
+        // UpdateService cannot be disabled
+        res.jsonValue["ServiceEnabled"] = true;
+        res.jsonValue["FirmwareInventory"] = {
+            {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
         res.end();
     }
     static void activateImage(const std::string &objPath)
@@ -188,14 +186,6 @@
     SoftwareInventoryCollection(CrowApp &app) :
         Node(app, "/redfish/v1/UpdateService/FirmwareInventory/")
     {
-        Node::json["@odata.type"] =
-            "#SoftwareInventoryCollection.SoftwareInventoryCollection";
-        Node::json["@odata.id"] = "/redfish/v1/UpdateService/FirmwareInventory";
-        Node::json["@odata.context"] =
-            "/redfish/v1/"
-            "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
-        Node::json["Name"] = "Software Inventory Collection";
-
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -210,7 +200,14 @@
                const std::vector<std::string> &params) override
     {
         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] =
+            "#SoftwareInventoryCollection.SoftwareInventoryCollection";
+        res.jsonValue["@odata.id"] =
+            "/redfish/v1/UpdateService/FirmwareInventory";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/"
+            "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
+        res.jsonValue["Name"] = "Software Inventory Collection";
 
         crow::connections::systemBus->async_method_call(
             [asyncResp](
@@ -315,15 +312,6 @@
         Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
              std::string())
     {
-        Node::json["@odata.type"] =
-            "#SoftwareInventory.v1_1_0.SoftwareInventory";
-        Node::json["@odata.context"] =
-            "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
-        Node::json["Name"] = "Software Inventory";
-        Node::json["Updateable"] = false;
-        Node::json["Status"]["Health"] = "OK";
-        Node::json["Status"]["HealthRollup"] = "OK";
-        Node::json["Status"]["State"] = "Enabled";
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
             {boost::beast::http::verb::head, {{"Login"}}},
@@ -338,7 +326,15 @@
                const std::vector<std::string> &params) override
     {
         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
-        res.jsonValue = Node::json;
+        res.jsonValue["@odata.type"] =
+            "#SoftwareInventory.v1_1_0.SoftwareInventory";
+        res.jsonValue["@odata.context"] =
+            "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
+        res.jsonValue["Name"] = "Software Inventory";
+        res.jsonValue["Updateable"] = false;
+        res.jsonValue["Status"]["Health"] = "OK";
+        res.jsonValue["Status"]["HealthRollup"] = "OK";
+        res.jsonValue["Status"]["State"] = "Enabled";
 
         if (params.size() != 1)
         {