Here some samples of how to use nlohmann::json for (de)serialization

Define a struct following macro in it:

NLOHMANN_DEFINE_TYPE_INTRUSIVE(Struct-name, member1, member2,...)

This will add everything needed for nlohmann::json to (de)serialize this struct.

struct Tower{
    std::string name;
    int type_id;
    float range;

    NLOHMANN_DEFINE_TYPE_INTRUSIVE(Tower, name, type_id, range)
};
// create an instance
Tower tower{"Tower",1895,18.95f};

// convert to json, just by assigning:
nlohmann::json json = tower;

// convert to string
std::string json_as_string = json.dump()

// convert to bson (a more compact format)
std::vector<std::uint8_t> as_bson = nlohmann::json::to_bson(json);

To create a json or instance from this data:

// string to json
nlohmann::json back_json = nlohmann::json::parse(json_as_string);

// bson to json (from std::vector<std::uint8_t>)
auto from_bson_json1 = nlohmann::json::from_bson(bson_data);
// bson to json (having void* and size)
auto from_bson_json2 = nlohmann::json::from_bson(bson_data,bson_data+size);

// json -> instance
auto tower = back_json.get<Tower>();

I just started with this, but it looks quite promising. Before I used flatbuffers or rapidjson.