ipkn / crow

Crow is very fast and easy to use C++ micro web framework (inspired by Python Flask)
BSD 3-Clause "New" or "Revised" License
7.48k stars 891 forks source link

How can I return a vector of crow::json::wvalue? #265

Open percyteng opened 6 years ago

percyteng commented 6 years ago

I didn't see any example. Can someone please help?

My code currently is vector resArr(resMeta->getColumnCount()); int count = 0; while (result->next()) { resJson = NULL; / Access column data by alias or column name / for (int i = 1; i <= resMeta->getColumnCount(); i++){ string column = string(resMeta->getColumnName(i)); resJson[column] = result->getString(column); } resArr[count] = crow::json::dump(resJson); count ++; } for (int j = 0; j < resMeta->getColumnCount(); j++){ cout << resArr[j] << endl; }

This way as a kind of work around, I changed json to string and put them in a vector of strings. Any idea how I can send a vector back through response?

pierobot commented 6 years ago

Did you take a look at the crow::json::wvalue class? You'll see that crow::json::wvalue has a move-assignment operator: wvalue& operator=(std::vector<wvalue>&& v)

And crow::response has constructors that accept a reference and rvalue of crow::json::wvalue.

So this should work

CROW_ROUTE(...
{
    std::vector<crow::json::wvalue> vector_of_wvalue;
    // fill vector
    // ...
    crow::json::wvalue final = std::move(vector_of_wvalue);

    return crow::response(std::move(final));
});
raphaeltraviss commented 6 years ago

Moving the contents of the std::vector into crow::json::wvalue doesn't seem to work; the line crow::json::wvalue result = std::move(crew_members); below is problematic?

CROW_ROUTE(app, "/crew")
  ([]{
    crow::json::wvalue troi;
    troi["name"] = "Deanna Troi";
    troi["ship"] = "Enterprise";
    troi["captain"] = "Jean-Luc Picard";

    crow::json::wvalue riker;
    riker["name"] = "William Riker";
    riker["ship"] = "Enterprise";
    riker["captain"] = "Jean-Luc Picard";

    std::vector<crow::json::wvalue> crew_members;
    crew_members.push_back(troi);
    crew_members.push_back(riker);
    crow::json::wvalue result = std::move(crew_members);

    return crow::response(std::move(result));
  });

Produces:

error: no viable conversion from 'typename remove_reference<vector<wvalue, allocator<wvalue> > &>::type' (aka 'std::__1::vector<crow::json::wvalue, std::__1::allocator<crow::json::wvalue> >') to 'crow::json::wvalue'
[build]     crow::json::wvalue result = std::move(crew_members);

Is this class supposed to work this way?

pierobot commented 6 years ago

Looks like you're right.

You can add the following constructor to crow::json::wvalue for it to compile. Up to you to actually test it though.

            wvalue(std::vector<wvalue>&& v)
            {
                l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
                l->resize(v.size());
                size_t idx = 0;
                for(auto& x:v)
                {
                    (*l)[idx++] = std::move(x);
                }
            }

Alternatively, you can also just do.

CROW_ROUTE(app, "/crew")([]() {
    std::vector<crow::json::wvalue> vec;
    crow::json::wvalue wv;
    wv = std::move(vec);
    return crow::response(std::move(wv));
});
raphaeltraviss commented 6 years ago

Even with your constructor code and other examples, I still couldn't get this working.

I resorted to using nlohmann-json:

  CROW_ROUTE(app, "/crew")
  ([]{
    nlohmann::json troi = {
      { "name", "Deanna Troi" },
      { "ship", "Enterprise" },
      { "captain", "Jean-Luc Picard" }
    };
    nlohmann::json riker = {
      { "name", "William Riker" },
      { "ship", "Enterprise" },
      { "captain", "Jean-Luc Picard" }
    };
    nlohmann::json crew = { riker, troi };

    return crow::response(crew.dump());
  });

I'm not thrilled about adding another library to my project, but this seems to be the only solution, until the Crow JSON library supports std::vector.

pierobot commented 6 years ago

I should have tried your code, the problem is that crow::json::wvalue has the copy constructor implicitly deleted; meaning you cannot call push_back. You have to use emplace_back(std::move(troi));

I guess you could also just add a copy constructor :man_shrugging: I can understand using another json library, I eventually did the same.

Jimmy1500 commented 5 years ago

I also found this solution works:

crow::json::wvalue x;
std::vector<int> ids = {1,2,3};
std::vector<string> names = {"test1", "test2", "test3"};
size_t i;
for (i = 0; i < ids.size(); ++i) {
     x[i]["id"] = ids.at(i);
     x[i]["name"] = names.at(i);
}
ghost commented 4 years ago

It's possible loaded json file return ?

std::ifstream ifs("example.json");
     json jf = json::parse(ifs);

    return crow::response(std::move(jf));  

Please anyone Help me

bougayez commented 4 years ago

Hi @vijaysoul, I hope you found an answer to your question. This worked for me:

ifstream ifs;
ifs.open("example.json");
string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
auto jf = crow::json::load(str);
return crow::response(jf);