JSON Handling in Glaze¶
Glaze is one of the fastest JSON libraries in the world, offering automatic reflection and direct memory serialization/deserialization with incredible performance. Glaze makes JSON handling in C++ simple, fast, and type-safe. Start with basic automatic reflection and gradually adopt advanced features as your needs grow!
Basic Example¶
With Glaze, your structs automatically get JSON serialization without any metadata:
#include "glaze/glaze.hpp"
struct Person {
std::string name = "John Doe";
int age = 30;
std::vector<std::string> hobbies = {"reading", "gaming"};
};
int main() {
Person person{};
// Write to JSON
std::string buffer{};
auto ec = glz::write_json(person, buffer);
if (!ec) {
// buffer now contains: {"name":"John Doe","age":30,"hobbies":["reading","gaming"]}
}
// Read from JSON
std::string json_data = R"({"name":"Jane","age":25,"hobbies":["hiking","cooking"]})";
Person jane{};
ec = glz::read_json(jane, json_data);
if (!ec) {
// jane.name is now "Jane", jane.age is 25, etc.
}
return 0;
}
Alternative API Styles¶
Glaze offers multiple ways to read and write JSON:
Writing JSON:
Person person{};
// Primary method: Write into existing buffer
std::string buffer{};
auto ec = glz::write_json(person, buffer);
if (!ec) {
// buffer contains the JSON string
}
// Alternative: Function returns std::expected<std::string, glz::error_ctx>
std::string json = glz::write_json(person).value_or("error");
Reading JSON:
std::string json_data = R"({"name":"Alice","age":28})";
// Primary method: Read into existing object
Person person{};
auto ec = glz::read_json(person, json_data);
if (!ec) {
// person is now populated from json_data
}
// Alternative: Function returns std::expected<T, glz::error_ctx>
auto result = glz::read_json<Person>(json_data);
if (result) {
const Person& person = result.value();
}
File I/O¶
Person person{};
// Read from file
auto ec = glz::read_file_json(person, "./person.json", std::string{});
if (!ec) {
// person is now populated from the file
}
// Write to file
auto ec = glz::write_file_json(person, "./person.json", std::string{});
if (!ec) {
// person data has been written to the file
}
Automatic Reflection¶
Glaze uses compile-time reflection to automatically serialize your structs. No macros, no manual registration - it just works!
Supported out of the box: - All aggregate-initializable structs - Standard library containers - Primitive types - Nested objects
struct Address {
std::string street;
std::string city;
int zip_code;
};
struct Employee {
std::string name;
int employee_id;
Address address;
std::optional<std::string> department;
std::map<std::string, int> skills_rating;
};
// This struct automatically works with JSON - no additional code needed!
Manual Metadata (When Needed)¶
For non-aggregate structs, private members, or custom behavior, you can provide explicit metadata:
struct CustomStruct {
private:
int value;
std::string name;
friend struct glz::meta<CustomStruct>; // friend only needed to access private members
public:
CustomStruct(int v, const std::string& n) : value(v), name(n) {}
};
template <>
struct glz::meta<CustomStruct> {
using T = CustomStruct;
static constexpr auto value = glz::object(
&T::value, // will use the key "value" automatically
&T::name // will use the key "name" automatically
);
};
Custom Field Names¶
You can override the default field names:
template <>
struct glz::meta<Person> {
using T = Person;
static constexpr auto value = glz::object(
"full_name", &T::name,
"years_old", &T::age,
"interests", &T::hobbies
);
};
// JSON output: {"full_name":"John","years_old":30,"interests":["reading"]}
Error Handling¶
Glaze provides comprehensive error handling with detailed error messages:
std::string invalid_json = R"({"name":"John", "age":})"; // Missing value
Person person{};
auto ec = glz::read_json(person, invalid_json);
if (ec) {
// Get a detailed error message
std::string error_msg = glz::format_error(ec, invalid_json);
std::cout << error_msg << '\n';
}
Input Buffer Requirements¶
For optimal performance, use null-terminated buffers (like std::string
):
// Recommended - null terminated
std::string json_data = "...";
Person person{};
auto ec = glz::read_json(person, json_data);
// If you must use non-null terminated buffers
constexpr auto options = glz::opts{.null_terminated = false};
auto ec = glz::read<options>(person, buffer);
Type Support¶
Containers and Arrays¶
All standard C++ containers are supported, and if your containers match C++ standard APIs they will work as well:
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::array<std::string, 3> colors = {"red", "green", "blue"};
std::set<int> unique_numbers = {1, 2, 3};
std::deque<double> values = {1.1, 2.2, 3.3};
// All serialize to JSON arrays: [1,2,3,4,5], ["red","green","blue"], etc.
Maps and Objects¶
std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
std::unordered_map<std::string, std::string> config = {{"host", "localhost"}};
// Serialize to JSON objects: {"Alice":95,"Bob":87}
Optional and Nullable Types¶
struct OptionalData {
std::optional<std::string> nickname;
std::unique_ptr<int> priority;
std::shared_ptr<std::vector<int>> tags;
};
// null values are written as JSON null, valid values are serialized normally
Enums¶
Enums can be serialized as integers (default) or strings:
enum class Status { Active, Inactive, Pending };
// Default: serialize as integers (0, 1, 2)
Status status = Status::Active;
// For string serialization, add metadata:
template <>
struct glz::meta<Status> {
using enum Status;
static constexpr auto value = glz::enumerate(
Active,
Inactive,
Pending
);
};
// Now serializes as: "Active", "Inactive", "Pending"
Variants¶
std::variant<int, std::string, double> data = "hello";
// Glaze automatically handles variant serialization
Advanced Features¶
JSON with Comments (JSONC)¶
Read JSON files with comments:
std::string jsonc_data = R"({
"name": "John", // Person's name
/* Multi-line comment
about age */
"age": 30
})";
Person person{};
auto ec = glz::read_jsonc(person, jsonc_data);
// Or: glz::read<glz::opts{.comments = true}>(person, jsonc_data);
Pretty Printing¶
Person person{};
// Write prettified JSON directly
std::string buffer{};
auto ec = glz::write<glz::opts{.prettify = true}>(person, buffer);
// Or prettify existing JSON
std::string minified = R"({"name":"John","age":30})";
std::string pretty = glz::prettify_json(minified);
Output:
Minification¶
// Write minified JSON (default behavior)
Person person{};
std::string buffer{};
auto ec = glz::write_json(person, buffer); // Already minified by default
// Minify existing JSON text
std::string pretty_json = "..."; // JSON with whitespace
std::string minified = glz::minify_json(pretty_json);
// For reading minified JSON (performance optimization)
auto ec = glz::read<glz::opts{.minified = true}>(person, minified_buffer);
Custom Serialization¶
For complex custom behavior, use glz::custom
:
struct TimestampObject {
std::chrono::system_clock::time_point timestamp;
void read_timestamp(const std::string& iso_string) {
// Parse ISO 8601 string to time_point
}
std::string write_timestamp() const {
// Convert time_point to ISO 8601 string
}
};
template <>
struct glz::meta<TimestampObject> {
using T = TimestampObject;
static constexpr auto value = glz::object(
"timestamp", glz::custom<&T::read_timestamp, &T::write_timestamp>
);
};
Boolean Flags¶
Represent multiple boolean flags as a JSON array:
struct Permissions {
bool read = true;
bool write = false;
bool execute = true;
};
template <>
struct glz::meta<Permissions> {
using T = Permissions;
static constexpr auto value = glz::flags(
"read", &T::read,
"write", &T::write,
"execute", &T::execute
);
};
// JSON output: ["read", "execute"]
Object Merging¶
Combine multiple objects into a single JSON object:
glz::obj metadata{"version", "1.0", "author", "John"};
std::map<std::string, int> scores = {{"test1", 95}, {"test2", 87}};
auto merged = glz::merge{metadata, scores};
std::string buffer{};
auto ec = glz::write_json(merged, buffer);
// Results in: {"version":"1.0","author":"John","test1":95,"test2":87}
Performance Features¶
Direct Memory Access¶
Glaze reads and writes directly to/from object memory, avoiding intermediate representations:
// No DOM tree, no temporary objects - direct serialization
LargeObject large_object{};
std::string buffer{};
auto ec = glz::write_json(large_object, buffer);
Compile-Time Optimizations¶
- Perfect hash tables for object keys
- Compile-time reflection eliminates runtime overhead
- SIMD and SWAR optimizations where possible
JSON Conformance¶
Glaze is fully RFC 8259 compliant with UTF-8 validation. By default, it uses two optimizations:
validate_skipped = false
: Faster parsing by not fully validating skipped values (does not affect resulting C++ objects)validate_trailing_whitespace = false
: Stops parsing after the target object
For strict compliance, enable these options: