C++ REST (Casablanca) - Failure while reading JSON - c++

I was trying my hands with C++ REST APIs
I wrote to json using below way.
json::value resp;
std::vector<Portfolio> portfolio;
// Populate portfolio
this->PortfolioList(usrStr, pwdStr, portfolio);
std::vector<Portfolio>::iterator it;
for (it = portfolio.begin(); it != portfolio.end(); it++)
{
char costBuff[40]; _itoa_s(it->GetTotalCost(), costBuff, 10);
char qtyBuff[40]; _itoa_s(it->GetQuantity(), qtyBuff, 10);
json::value portfolioEntry;
portfolioEntry[U("username")] = json::value::string(utility::conversions::to_string_t(it->GetUserName()));
portfolioEntry[U("stockCode")] = json::value::string(utility::conversions::to_string_t(it->GetStockCode()));
portfolioEntry[U("quantity")] = json::value::string(utility::conversions::to_string_t(qtyBuff));
portfolioEntry[U("totalcost")] = json::value::string(utility::conversions::to_string_t(costBuff));
resp[utility::conversions::to_string_t(it->GetStockCode())] = portfolioEntry;
}
For this I got output as below
{
"11002":{"quantity":11002,"totalcost":"272","username":"arunavk"},
"11003":{"quantity":11003,"totalcost":"18700","username":"arunavk"},
"11004":{"quantity":11004,"totalcost":"760","username":"arunavk"},
"11005":{"quantity":11005,"totalcost":"32","username":"arunavk"}
}
Now, on the receiving end, I tried to read it as below
for (int i = 0; i < size; i++)
{
table->elementAt(i, 0)->addWidget(new Wt::WText(this->response[i][0].as_string()));
table->elementAt(i, 1)->addWidget(new Wt::WText(this->response[i][1].as_string()));
table->elementAt(i, 2)->addWidget(new Wt::WText(this->response[i][2].as_string()));
table->elementAt(i, 3)->addWidget(new Wt::WText(this->response[i][3].as_string()));
}
But it fails. What am I missing ?
Pardon me, I am new to this REST and Casablanca and JSON

From JSON point of view the following
{
"11002":{"quantity":11002,"totalcost":"272","username":"arunavk"},
"11003":{"quantity":11003,"totalcost":"18700","username":"arunavk"},
"11004":{"quantity":11004,"totalcost":"760","username":"arunavk"},
"11005":{"quantity":11005,"totalcost":"32","username":"arunavk"}
}
is java script object with properties "11002", ... "11005", is not array. So if you want to get value of property you have to use property name:
this->response["11002"]["quantity"]
because when you use integer index the json::value::operator [] supposes that you want to access the array element. Here is details https://microsoft.github.io/cpprestsdk/classweb_1_1json_1_1value.html#a56c751a1c22d14b85b7f41a724100e22
UPDATED
If you do not know properties of the recieved object, you can call the value::as_object method (https://microsoft.github.io/cpprestsdk/classweb_1_1json_1_1value.html#a732030bdee11c2f054299a0fb148df0e) to get JSON object and after that you can use specilized interface to iterate through the fields with begin and end iterators: https://microsoft.github.io/cpprestsdk/classweb_1_1json_1_1object.html#details

Related

Getting n objects and their field from JSon, then store them as class object

Im trying to get information about my objects from JSon file. It contains n objects (2 for example) 4 fields each. I parse .json by rapidjson and my IDE is Qt Creator.
I already tried using Pointers desribed at http://rapidjson.org/md_doc_pointer.html#JsonPointer and Query Objects from their basic tutorial, but somehow I can't get it working.
that's how example .json file would look.
{
"opiekun1" : {
"imie": "Maksym",
"nazwisko": "Zawrotny",
"email": "maksym#wp.pl",
"haslo": "herbatka"},
"opiekun2" : {
"imie": "Filip",
"nazwisko": "Szatkowski",
"email": "filip#wp.pl",
"haslo": "kawusia"}
}
I get DOM Document by:
FILE* fp = fopen(json_filename.c_str(), "rb");
char readBuffer[65536];
FileReadStream is(fp, readBuffer, sizeof(readBuffer));
Document d;
d.ParseStream(is);
I tried Pointer() like that:
Value* value = Pointer("/opiekun1/imie").Get(parsedJSon);
but I got:
invalid conversion from 'const rapidjson::GenericValue<rapidjson::UTF8<> >*' to 'rapidjson::Value* {aka rapidjson::GenericValue<rapidjson::UTF8<> >*}'
Mine another try was to iterate through objects in Document:
for (auto& object : parsedJSon.GetObject())
{
CUzytkownik* user;
user = new CUzytkownik;
int counter = 0;
for (Value::ConstMemberIterator itr = object.MemberBegin();
itr != object.MemberEnd(); itr++)
{
if (itr->name.GetString() == "imie")
user->imie = itr->value.GetString();
}
}
But it says:
const struct rapidjson::GenericMember<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<> >' has no member named 'MemberEnd'
I think that I misunderstand something about handling objects in .json files. Could anyone explain it to me and provide some example code? I would like my output to look something like that:
CUzytkownik* opiekun1 = new CUzytkownik;
opiekun1->name = "Maksym";
opiekun1->nazwisko = "Zawrotny";
opiekun1->email = "maksym#wp.pl";
opiekun1->haslo = "herbatka";
If anyone has experience with rapidjson and would like to help I will be most grateful. Any alternative examples like array handling or somethng like that ale most welcome too.
Thank you in advance!

Vibe.D - undefinded identifier (Dlang)

I'm trying to create simple REST api, but when i try to compile my code im getting
frontpage.d(15,3): Error: undefined identifier 'tmp', did you mean
alias 'cmp'?
Here is my code:
module service.frontpage;
import vibe.d;
#path("/api")
interface IFrontPageAPI
{
Json getHome();
}
class FrontPageAPI : IFrontPageAPI
{
this(auto tmp)
{
auto collect = tmp;
}
Json getHome()
{
logInfo("Getting HomePage from DB");
Bson query = Bson(["_id" : Bson("homepage")]);
auto result = collect.find(query);
logInfo("Iterating results...");
foreach (i, doc; result.byPair)
logInfo("Item %d: %s", i, doc.toJson().toString());
return result.toJson();
}
}
Can someone help me with it? tmp is temporary variable to pass mongoDB collection handler.
Same answer as on DLearn.
You need to
- use Class variables
- use types instead auto (here Mongo collection)
- return a proper Json
Have a look at this interactive example - and feel free to play with it. No output means no compilation error.

Replacing value of a member in rapidjson

I am currently working on a project in C++ using rapidjson.
My program receives some JSON data on a socket which includes some authentication details. I log the incoming message, but I want to hide the password so it can't be seen in the log file. So I am trying to get the JSON object, and replace each character of the string and put this replaced string back into the json object where the password was.
Below is the code that I have:
rapidjson::Document jsonObject;
jsonObject.Parse(command.c_str());
string method = jsonObject["method"].GetString();
if (jsonObject.HasMember("sshDetails"))
{
Value& sshDetails = jsonObject["sshDetails"];
string sshPassword = sshDetails["sshPassword"].GetString();
for (int i = 0; i < sshPassword.length(); i++)
{
sshPassword[i] = '*';
}
rapidjson::Value::Member* sshPasswordMember = sshDetails.FindMember("sshPassword");
sshPasswordMember->name.SetString(sshPassword.c_str(), jsonObject.GetAllocator());
//Convert it back to a string
rapidjson::StringBuffer buffer;
buffer.Clear();
rapidjson::Writer<rapidjson::StringBuffer>writer(buffer);
Document jsonDoc;
jsonDoc.Accept(writer);
string jsonString = string(buffer.GetString());
I'm getting an error on the following line:
rapidjson::Value::Member* sshPasswordMember = sshDetails.FindMember("sshPassword");
The error I am getting is:
No suitable conversion function from rapidjson::GenericMemberIterator<false, rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CtrlAllocator>> to rapidjson::GenericMember::UTF8<char>, myProject...SocketProcessor.cpp
rapidjson::MemoryPoolAllocator<rapidjson::CtrlAllocator>>*exists
I took the above from an example on another question on SO which was an accepted answer from rapidjson - change key to another value, so what am I missing.
I've managed to find the answer to this with a bit of playing round and luck.
I changed
rapidjson::Value::Member* sshPasswordMember = sshDetails.FindMember("sshPassword");
sshPasswordMember->name.SetString(sshPassword.c_str(), jsonObject.GetAllocator());
to be
rapidjson::Value::MemberIterator sshPasswordMember = sshDetails.FindMember("sshPassword");
sshPasswordMember->value.SetString(sshPassword.c_str(), jsonObject.GetAllocator());
using rapidjson in my project I found out that many of such problems can be omitted by the use of auto instead of specifying the type

Creating json string using json lib

I am using jsonc-libjson to create a json string like below.
{ "author-details": {
"name" : "Joys of Programming",
"Number of Posts" : 10
}
}
My code looks like below
json_object *jobj = json_object_new_object();
json_object *jStr1 = json_object_new_string("Joys of Programming");
json_object *jstr2 = json_object_new_int("10");
json_object_object_add(jobj,"name", jStr1 );
json_object_object_add(jobj,"Number of Posts", jstr2 );
this gives me json string
{
"name" : "Joys of Programming",
"Number of Posts" : 10
}
How do I add the top part associated with author details?
To paraphrase an old advertisement, "libjson users would rather fight than switch."
At least I assume you must like fighting with the library. Using nlohmann's JSON library, you could use code like this:
nlohmann::json j {
{ "author-details", {
{ "name", "Joys of Programming" },
{ "Number of Posts", 10 }
}
}
};
At least to me, this seems somewhat simpler and more readable.
Parsing is about equally straightforward. For example, let's assume we had a file named somefile.json that contained the JSON data shown above. To read and parse it, we could do something like this:
nlohmann::json j;
std::ifstream in("somefile.json");
in >> j; // Read the file and parse it into a json object
// Let's start by retrieving and printing the name.
std::cout << j["author-details"]["name"];
Or, let's assume we found a post, so we want to increment the count of posts. This is one place that things get...less tasteful--we can't increment the value as directly as we'd like; we have to obtain the value, add one, then assign the result (like we would in lesser languages that lack ++):
j["author-details"]["Number of Posts"] = j["author-details"]["Number of Posts"] + 1;
Then we want to write out the result. If we want it "dense" (e.g., we're going to transmit it over a network for some other machine to read it) we can just use <<:
somestream << j;
On the other hand, we might want to pretty-print it so a person can read it more easily. The library respects the width we set with setw, so to have it print out indented with 4-column tab stops, we can do:
somestream << std::setw(4) << j;
Create a new JSON object and add the one you already created as a child.
Just insert code like this after what you've already written:
json_object* root = json_object_new_object();
json_object_object_add(root, "author-details", jobj); // This is the same "jobj" as original code snippet.
Based on the comment from Dominic, I was able to figure out the correct answer.
json_object *jobj = json_object_new_object();
json_object* root = json_object_new_object();
json_object_object_add(jobj, "author-details", root);
json_object *jStr1 = json_object_new_string("Joys of Programming");
json_object *jstr2 = json_object_new_int(10);
json_object_object_add(root,"name", jStr1 );
json_object_object_add(root,"Number of Posts", jstr2 );

How do you specify multiple Sort fields with Solrj?

I have an application using solr that needs to be able to sort on two fields. The Solrj api is a little confusing, providing multiple different APIs.
I am using Solr 4.10.4
I have tried:
for (int i = 0; i < entry.getValue().size();) {
logger.debug("Solr({}) {}: {} {}", epName, entry.getKey(), entry
.getValue().get(i), entry.getValue().get(i + 1));
if (i == 0) {
query.setSort(new SolrQuery.SortClause(entry.getValue().get(i++), SolrQuery.ORDER.valueOf(entry.getValue().get(i++))));
} else {
query.addSort(new SolrQuery.SortClause(entry.getValue().get(i++), SolrQuery.ORDER.valueOf(entry.getValue().get(i++))));
}
}
When I look at the generated URL I only see the last SortClause sort=sequence+asc
I also tried creating a List and the setSorts SolrQuery method and that too seems to output only as single sort field, always the last one.
I was able to create the correct sort clause by generating it manually with strings.
I have tried addOrUpdateSort as well. I think I've tried most of the obvious combinations. of methods in the Solrj API.
This does work:
StringBuilder sortString = new StringBuilder();
for (int i = 0; i < entry.getValue().size();) {
if (sortString.length() > 0) {
sortString.append(",");
}
logger.debug("Solr({}) {}: {} {}", epName, entry.getKey(), entry
.getValue().get(i), entry.getValue().get(i + 1));
sortString.append(entry.getValue().get(i++)).append(" ").
append(SolrQuery.ORDER.valueOf(entry.getValue().get(i++)));
}
query.set("sort",sortString.toString());
The sort clause I want to see is: sort=is_cited+asc,sequence+asc
The solrj API seems to only output the final clause.
I suspect a bug in solrj 4.10
can you substitute setSort with addSort ie
for (int i = 0; i < entry.getValue().size();) {
logger.debug("Solr({}) {}: {} {}", epName, entry.getKey(), entry
.getValue().get(i), entry.getValue().get(i + 1));
if (i == 0) {
query.addSort(new SolrQuery.SortClause(entry.getValue().get(i++), SolrQuery.ORDER.valueOf(entry.getValue().get(i++))));
} else {
query.addSort(new SolrQuery.SortClause(entry.getValue().get(i++), SolrQuery.ORDER.valueOf(entry.getValue().get(i++))));
}
}
And let me know if this worked
Check out addOrUpdateSort()
Updates or adds a single sort field specification to the current sort
information. If the sort field already exist in the sort information map,
its position is unchanged and the sort order is set; if it does not exist,
it is appended at the end with the specified order..
#return the modified SolrQuery object, for easy chaining
#since 4.2