C++ How to check if json key exists using boost::json::value?

1.1k Views Asked by At

Using boost::json::value, how do I check if a certain key exists?

The following code:

void checkMessage(std::string msg)
{
    boost::json::value json = boost::json::parse(payload);

    auto type = json.at("type").as_string();
    auto param1 = json.at("param1").as_string();
    auto param1 = json.at("param2").as_int64(); <<=== IT CHASHES HERE

    std::cout << "Received: " << std::endl;
    std::cout << "type: " << type << std::endl;
    std::cout << "param1: " << param1 << std::endl;
    std::cout << "param2: " << param2 << std::endl;
}

Crashes when trying to get the param2 from my json data:

terminate called after throwing an instance of 'boost::wrapexcept<std::out_of_range>'
  what():  out of range
Aborted (core dumped)

When the param2 is missing:

std::string msg = "{\"type\", \"t1\", \"param1\": \"test parameter 1\"}";

Is there a way to check if the parameter exists before copying the json key value to the variable?

Is there a better way to do it?

2

There are 2 best solutions below

0
On

As the commented suggested you can catch the out of range error (system_error exception).

Or you can be more cautious and check first:

auto* param1 = json.as_object().if_contains("param1");
auto* param2 = json.as_object().if_contains("param2");

Likewise you can be more cautious about the string interpretation too:

Live On Coliru

#include <boost/json/src.hpp>
#include <iostream>

void checkMessage(std::string msg) {
    auto json = boost::json::parse(msg);

    auto type   = json.at("type").as_string();
    auto* param1 = json.as_object().if_contains("param1");
    auto* param2 = json.as_object().if_contains("param2");
    auto* value1 = (param1? param1->if_string() : nullptr);
    auto* value2 = (param2? param2->if_string() : nullptr);

    std::cout << "Received: " << std::endl;
    std::cout << "type:     " << type       << std::endl;
    std::cout << "value1:   " << (value1 ? *value1 : "(MISSING)") << std::endl;
    std::cout << "value2:   " << (value2 ? *value2 : "(MISSING)") << std::endl;
}

int main() {//
    checkMessage(R"({"type": "t1", "param1": "test parameter 1"})");
}

Printing

type:     "t1"
value1:   "test parameter 1"
value2:   "(MISSING)"
7
On

You can use object::if_contains method:

#include <boost/json.hpp>
#include <boost/json/src.hpp>

#include <iostream>

void Check(::boost::json::object const & object, ::boost::json::string_view const name)
{
    ::boost::json::value const * const p_value{object.if_contains(name)};
    if (p_value)
    {
        ::std::cout << name << ": " << p_value->as_string();
    }
    else
    {
        ::std::cout << name << " is missing";
    }
    ::std::cout << "\n";
}

int main()
{
    ::boost::json::value json{::boost::json::parse(R"({"param1": "foo", "param3": "bar"})")};
    ::boost::json::object const & root{json.as_object()};
    Check(root, "param1");
    Check(root, "param2");
    Check(root, "param3");
}

param1: "foo"
param2 is missing
param3: "bar"

online compiler