Cplusplus highly structured config management

  • cplusplus
  • json
  • config
  • configuration
  • STL
  • english

posted on 19 Sep 2025 under category programming

Post Meta-Data

Date Language Author Description
19.09.2025 English Claus Prüfer (Chief-Prüfer) C++ Highly Structured Configuration Management

Modern C++ Configuration Management with Nlohmann::JSON

This tutorial provides in-depth guidance Microscope on leveraging the Nlohmann::JSON library for efficient configuration handling and internal data modeling in modern C++ projects.

Project repository: nlohmann/json


Preface

Configuration management Diskette has been a pivotal topic for decades. Numerous approaches—each with their own strengths and weaknesses—have evolved over time.

Commonly Used Formats

  • Grouped Key/Value Pairs
  • OS Registry
  • XML
  • JSON (now a first-class citizen in config management)

The Rise of JSON

JSON (JavaScript Object Notation) originated as part of dynamic web content in JavaScript, offering a concise and hierarchical way to define object metadata. Its seamless integration with APIs and native parsing support helped it become a widely adopted data format and a new design pattern.

Python’s Native JSON Adoption

Python was among the first languages to embrace JSON natively. With Python’s built-in support and features like yield, developers gain powerful tools for building rich, dynamic data models.


JSON in Modern C++

C++ is inherently suited for generic programming Computer. However, many C++ JSON libraries neglect this paradigm, resulting in convoluted APIs.

Enter Nlohmann::JSON

Thanks to Niels Lohmann (Berlin), C++ developers can now work with JSON in an intuitive, STL-like manner Microscope. The library’s hierarchical access and clean object modeling unlock powerful design patterns and minimize boilerplate.

Other C++ JSON libraries rarely match this elegance and usability.

Declarative Programming

Declarative programming—popular in systems like Kubernetes (Go)—fits naturally with JSON (or YAML). While Go’s OOP model is limited, languages like JavaScript, Python, and C++ (with Nlohmann::JSON) support declarative configuration beautifully.

Embracing Generic Containers

With Nlohmann::JSON, base STL containers (std::vector, std::map) are used for JSON arrays and objects. Features like std::swap and std::move (C++11+) are transparently supported, enabling efficient memory management and modern iteration syntax.

Why Not XML?

While XML offers features like DTDs, its verbosity and complex parsing routines often outweigh its benefits—especially in embedded systems and performance-critical applications. Many XML libraries are C-style and lack the ergonomic STL-like access that Nlohmann::JSON provides.


Implementation Examples

Let’s move from theory to practice. Below are actionable examples showcasing Nlohmann::JSON’s strengths, inspired by WEBcodeX1/http-1.2.

Sample JSON Configuration

Sample config excerpt (full file):

{
  "global": {
    "path": { "base": "/var/www" },
    "tcp": { "cork": false, "nodelay": true }
  },
  "server": {
    "runas": { "user": "x0-http", "group": "x0-http" },
    "connection": {
      "timeout": "600",
      "ipv4": { "address": "127.0.0.1", "port": 80 }
    },
    "mimetypes": ["html", "js", "json", "css", "png", "jpg", "svg", "woff2"]
  }
}

EmojiBulb For large configs, consider splitting into multiple files for maintainability.

Global Access Example

Direct global access leverages intuitive, chainable syntax:

#include <nlohmann/json.hpp>
#include <fstream>
using json = nlohmann::json;

try {
    std::ifstream configFile(CONFIG_FILE);
    json jsonData = json::parse(configFile);

    const auto& runAsUser   = jsonData["server"]["runas"]["user"];
    const auto& runAsGroup  = jsonData["server"]["runas"]["group"];
    const auto& basePath    = jsonData["global"]["path"]["base"];
    const auto& serverAddr  = jsonData["server"]["connection"]["ipv4"]["address"];
    const auto& serverPort  = jsonData["server"]["connection"]["ipv4"]["port"];
    const auto& mimeTypes   = jsonData["server"]["mimetypes"];
}
catch (const std::exception& e) {
    std::cerr << "Config file error: " << e.what() << std::endl;
    std::exit(EXIT_FAILURE);
}

Hierarchical Access

Minimize value copies and programming mistakes with direct, type-safe access:

const auto& serverAddr = jsonData["server"]["connection"]["ipv4"]["address"];
const auto& serverPort = jsonData["server"]["connection"]["ipv4"]["port"];

Processing Lists in JSON

Example config with a list of namespaces:

{
  "namespaces": [
    {
      "id": "app1",
      "hostname": "testapp1.local",
      "path": "/app1",
      "interpreters": 5,
      "access": {
        "as-post": { "/": "default" }
      }
    },
    {
      "id": "app2",
      "hostname": "testapp2.local",
      "path": "/app2",
      "interpreters": 3,
      "access": {
        "as-post": {
          "/": false,
          "/endpoint1": "method1"
        },
        "as-get": {
          "/endpoint2": {
            "params": ["param1", "param2"],
            "method": "method2"
          }
        }
      }
    }
  ]
}

Iterating Over JSON Lists in C++

Modern for-each loops make iterating clean and efficient:

for (const auto& nsItem : jsonData["namespaces"]) {
    // access properties with nsItem["id"], nsItem["hostname"], etc.
}

Accessing Nested Properties

Access sub-object properties with ease:

for (const auto& nsItem : jsonData["namespaces"]) {
    const auto& accessPost = nsItem["access"]["as-post"];
    // ... further processing
}

STL Move Semantics for JSON Objects

Efficiently move JSON objects into containers to save memory:

struct NamespaceProps {
    nlohmann::json jsonConfig;
    std::shared_ptr<Filesystem> fsRef;
};

std::map<std::string, NamespaceProps> namespaces;

for (const auto& nsItem : jsonData["namespaces"]) {
    NamespaceProps props;
    props.jsonConfig = std::move(nsItem);
    props.fsRef = nullptr;

    namespaces.emplace(nsItem["hostname"], std::move(props));
}

EmojiBulb You can also move directly into any STL container supporting move semantics.

Direct Data Modeling

With Nlohmann::JSON, you model your configuration as clean, native C++ data structures, taking full advantage of STL features like std::swap, std::move, and modern iteration.

// assume objects accept nlohmann::json rvalue references in their constructors
std::unique_ptr<MyObject1> objInstance1;
std::unique_ptr<MyObject2> objInstance2;

// think about defining config class member immutable (const)
objInstance1 = new MyObject1(std::move(jsonData["confgroup1"][0]);
objInstance2 = new MyObject2(std::move(jsonData["confgroup1"][1]);

EmojiBulb Save class instance members by directly std::move-ing hierarchical JSON structures into your objects to avoid unnecessary copies.


External References

Falcon AS (http/1.2)

Example code and configuration: WEBcodeX1/http-1.2

x0 JavaScript Framework

A JavaScript framework using true OOP and the Declarative Programming Design Pattern: WEBcodeX1/x0


Pro-Tip: Adopt modern C++ standards (C++17/20), explore concepts like smart pointers, ranges, and structured bindings to further streamline your configuration management code!