Free & open source — no account required
Free & open source — no account required
This technical guide provides an in-depth analysis of the json to cpp struct engine, best practices for implementation, and data security standards.
C++ gives you value semantics, RAII, and std::optional — which makes JSON mapping far safer than raw C pointers. The dominant C++ JSON library is nlohmann/json: header-only, MIT-licensed, and used in tens of thousands of projects. TypeMorph generates a struct with the correct C++ types and a from_json factory that handles optional fields and nested objects. The result compiles on C++17 with no dependencies beyond the single header file.
// Input JSON
{
"device_id": "sensor_042",
"temperature": 23.7,
"sample_count": 1200,
"is_active": true,
"firmware": "2.1.4",
"error_code": null
}
// Generated C++ (C++17, nlohmann/json)
#include <string>
#include <optional>
#include <cstdint>
#include <nlohmann/json.hpp>
struct Root {
std::string device_id;
double temperature;
int64_t sample_count;
bool is_active;
std::string firmware;
std::optional<std::string> error_code;
static Root from_json(const nlohmann::json& j) {
Root obj;
obj.device_id = j.at("device_id").get<std::string>();
obj.temperature = j.at("temperature").get<double>();
obj.sample_count = j.at("sample_count").get<int64_t>();
obj.is_active = j.at("is_active").get<bool>();
obj.firmware = j.at("firmware").get<std::string>();
if (j.contains("error_code") && !j["error_code"].is_null())
obj.error_code = j["error_code"].get<std::string>();
return obj;
}
nlohmann::json to_json() const {
return {
{"device_id", device_id},
{"temperature", temperature},
{"sample_count", sample_count},
{"is_active", is_active},
{"firmware", firmware},
{"error_code", error_code.has_value() ? nlohmann::json(*error_code) : nlohmann::json(nullptr)},
};
}
};
// Usage
int main() {
std::string raw = R"({"device_id":"sensor_042","temperature":23.7,...})";
auto j = nlohmann::json::parse(raw);
Root r = Root::from_json(j);
std::cout << r.device_id << ": " << r.temperature << "°C\n";
if (r.error_code) std::cout << "Error: " << *r.error_code << "\n";
}
// JSON → C++ type mapping (C++17)
// "string" → std::string
// number → double (safe default for any JSON number)
// integer → int64_t (use int for smaller values, size_t for sizes)
// boolean → bool
// null → std::optional<T> (has_value() == false when JSON is null)
// object → nested struct
// array → std::vector<T>
// NLOHMANN_DEFINE_TYPE_INTRUSIVE — macro shortcut for simple structs
// (no optional fields, no custom logic needed)
struct Point {
double x;
double y;
double z;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Point, x, y, z)
};
// Usage with macro:
nlohmann::json j = {{"x", 1.0}, {"y", 2.5}, {"z", -0.3}};
Point p = j.get<Point>(); // deserialize
nlohmann::json j2 = p; // serialize back
#include <string>
#include <vector>
#include <optional>
#include <nlohmann/json.hpp>
struct Address {
std::string street;
std::string city;
std::optional<std::string> zip;
static Address from_json(const nlohmann::json& j) {
Address a;
a.street = j.at("street").get<std::string>();
a.city = j.at("city").get<std::string>();
if (j.contains("zip") && !j["zip"].is_null())
a.zip = j["zip"].get<std::string>();
return a;
}
};
struct User {
std::string id;
std::string name;
Address address;
std::vector<std::string> roles;
static User from_json(const nlohmann::json& j) {
User u;
u.id = j.at("id").get<std::string>();
u.name = j.at("name").get<std::string>();
u.address = Address::from_json(j.at("address"));
// std::vector deserialization is built-in for primitive types
if (j.contains("roles"))
u.roles = j["roles"].get<std::vector<std::string>>();
return u;
}
nlohmann::json to_json() const {
nlohmann::json j;
j["id"] = id;
j["name"] = name;
j["address"] = {
{"street", address.street},
{"city", address.city},
{"zip", address.zip.has_value() ? nlohmann::json(*address.zip) : nlohmann::json(nullptr)},
};
j["roles"] = roles;
return j;
}
};
#include <string>
#include <stdexcept>
#include <curl/curl.h>
#include <nlohmann/json.hpp>
// libcurl write callback
static size_t write_cb(char *ptr, size_t size, size_t nmemb, std::string *data) {
data->append(ptr, size * nmemb);
return size * nmemb;
}
std::string http_get(const std::string& url) {
CURL *curl = curl_easy_init();
if (!curl) throw std::runtime_error("curl init failed");
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK) throw std::runtime_error(curl_easy_strerror(res));
return response;
}
// Full fetch-and-parse example
int main() {
std::string body = http_get("https://api.example.com/users/usr_042");
auto j = nlohmann::json::parse(body);
User user = User::from_json(j);
std::cout << "Name: " << user.name << "\n";
}
Why nlohmann/json over RapidJSON or simdjson? nlohmann/json is the most ergonomic: it integrates naturally with C++ containers and operator overloads, requires no schema compilation step, and is a single header drop-in. RapidJSON is faster (SAX-style, zero-copy) and better for high-throughput parsing where allocations matter. simdjson is the fastest (SIMD-accelerated) for read-only use cases. For typical API integration work, nlohmann/json's developer ergonomics win — switch to RapidJSON or simdjson only when profiling shows JSON parsing is a bottleneck.
What does j.at("key") vs j["key"] do? j.at("key") throws nlohmann::json::out_of_range if the key is missing — use this for required fields so you get a clear error instead of a default-constructed value. j["key"] creates the key with a null value if it doesn't exist, which silently produces wrong data. In the generated from_json, required fields use .at() and optional fields use .contains() first.
How do I handle arrays of objects? nlohmann/json's .get<std::vector<T>>() works automatically for primitive types. For std::vector<YourStruct>, define a from_json(const nlohmann::json&, YourStruct&) free function and register it via the ADL pattern, or iterate manually: for (auto& item : j["items"]) vec.push_back(YourStruct::from_json(item));
Is my JSON sent to a server? No. TypeMorph runs entirely in your browser — none of your data leaves your machine.
Is the processing local-only?
Absolutely. TypeMorph operates entirely within your browser's sandbox. We use Web Workers for high-performance computation without ever transmitting your JSON, SQL, or API data to a remote server.
Can I use this for enterprise projects?
Yes. The tool is designed for professional software engineers who require GDPR compliance and data privacy. It is trusted by developers at top-tier startups and financial institutions.