Write a cpprestsdk json value object into a file - c++

I receive a JSON response body as part of a REST request. I would like to write the body of the JSON into a file. A quick way to do this would be to use the web::http::response object itself..
pplx::task<void> requestTask = fstream::open_ostream(U("testResults.json")).then([=](ostream outFile)
{
*fileStream = outFile;
//some work
})
.then([=](http_response response)
{
printf("Received response status code:%u\n", response.status_code());
// Write response body into the file.
return response.body().read_to_end(fileStream->streambuf());
})
.then([=](size_t s)
{
return fileStream->close();
});
However, after receiving the response body, I extract the JSON from it to calculate some values, after which, as documented, the json cannot be extracted or used again from the response body, so i have to use the web::json::value object.
http::json::value someValue = response.extract_json().get();
I'd like to write this json::value object, someValue, to a JSON file, but not sure how to get it done. Writing to an ostream object with serialize.c_cstr() on someValue gives weird output.
ostream o("someFile.json");
o << setw(4) << someValue.serialize().c_str() << std<<endl;

If your system typdef std::string as a wide string, then outputting via ostream would lead to weird output.
web::json::value::serialize() returns a utility::string_t
https://microsoft.github.io/cpprestsdk/classweb_1_1json_1_1value.html#a5bbd4bca7b13cd912ffe76af825b0c6c
utility::string_t is typedef as a std::string
https://microsoft.github.io/cpprestsdk/namespaceutility.html#typedef-members
So something like this would work:
std::filesystem::path filePath(L"c:\\someFile.json"); // Assuming wide chars here. Could be U instead of L depending on your setup
std::wofstream outputFile(filePath);
outputFile << someJSONValue.serialize().c_str();
outputFile.close();

Related

c++ JsonCpp parse string with escaped quotes as array

I've got the following json string:
{
"data" :
[
{
"cart" : "[{\"name\":\"Test item 1\",\"price\":15,\"quantity\":1,\"sum\":15,\"tax\":\"none\",\"payment_type\":\"advance\",\"item_type\":\"service\"},{\"name\":\"Test item 2\",\"price\":13.01,\"quantity\":2,\"sum\":26.02,\"tax\":\"none\",\"payment_type\":\"part_prepay\",\"item_type\":\"work\"}]",
"contact" : "noname#google.com",
"p_id" : "603",
"sum" : "100.02",
"tax_system" : "osn"
}
],
"msg" : null,
"result" : "success"
}
I can parse cart as std::string after parsing input json string as stringstream:
const std::string ParseJsonData(std::stringstream ssJsonStream)
{
Json::Value jsonData;
Json::Value responseData;
Json::Value responseDataCart;
Json::CharReaderBuilder jsonReader;
std::string errs;
if (Json::parseFromStream(jsonReader, ssJsonStream, &jsonData, &errs)) {
responseData = jsonData["data"];
responseDataCart = responseData[0]["cart"];
return responseDataCart.toStyledString().c_str();
}
else
return "Could not parse HTTP data as JSON";
}
Please, tell me, how can i parse cart as array with JsonCpp?
The same way you parsed the outer JSON!
You started with a string (well, hidden by a stream) and turned it into JSON.
Now that JSON contains a property that is a string and, itself, contains JSON. The problem is recursive. The fact that the inner string originally came from JSON too can be ignored. Just pretend it's a string you typed in.
So, you can use JSON::Reader to in turn get the JSON out of that string.
Something like:
const std::string responseDataCartStr = responseData[0]["cart"].asString();
Json::Reader reader;
if (!reader.parse(responseDataCartStr, responseDataCart))
throw std::runtime_error("Parsing nested JSON failed");
JsonCpp provides a few ways to parse JSON and it's worth exploring them to find the most appropriate for your use case. The above is just an example.
Ignore the backslashes — the escaping was meaningful within the encapsulating JSON document, but the outermost parse stage should already have taken that into consideration. You'll see if you print responseDataCartStr to console that it is a valid JSON document in its own right.

cpprestsdk: handle chunked response

How should I handle chunked response using cpprestsdk? How to request the next chunk? Is there required functionality at all there?
Here is how we are performing http requests:
web::http::http_request request(web::http::methods::GET);
request.headers().add(LR"(User-Agent)", LR"(ExchangeServicesClient/15.00.0847.030)");
request.headers().add(LR"(Accept)", LR"(text/xml)");
request.set_body(L"request body", L"text/xml");
web::http::client::http_client_config clientConfig;
clientConfig.set_credentials(web::credentials(L"username", L"pass"));
clientConfig.set_validate_certificates(true);
web::http::client::http_client client(L"serviceurl", clientConfig);
auto bodyTask = client.request(request)
.then([](web::http::http_response response) {
auto str = response.extract_string().get();
return str;
});
auto body = bodyTask.get();
If I'm trying naively to perform another request just after this one then I got an error:
WinHttpSendRequest: 5023: The group or resource is not in the correct state to perform the
requested operation.
In order to read received data in chunks, one needs to get the input stream from the server response
concurrency::streams::istream bodyStream = response.body();
then read continuously from that stream until a given char is found or the number of specified bytes is read
pplx::task<void> repeat(Concurrency::streams::istream bodyStream)
{
Concurrency::streams::container_buffer<std::string> buffer;
return pplx::create_task([=] {
auto t = bodyStream.read_to_delim(buffer, '\n').get();
std::cout << buffer.collection() << std::endl;
return t;
}).then([=](int /*bytesRead*/) {
if (bodyStream.is_eof()) {
return pplx::create_task([]{});
}
return repeat(bodyStream);
});
}
Here is the full sample: https://github.com/cristeab/oanda_stream

Not able to get values from JSON in Casablanca, C++

I'm using Casablanca, cpprestsdk to consume REST APIs in C++, in Visual Studio 2015 Professional. I'm trying to develop a simple example here hitting an API and parsing the response as JSON. The URL I'm using, actually returns all the parameters sent to the API.
I've hit the API and got response as well, extracted json from the response successfully. But when i try to read a value at any key from json, it crashes. Hence i put a check whether that key is available or not, and it always says json does not have the field. As an example i printed the data i.e. json. It has the key/field "name" but when i check it via has_field, it returns false.
Please help.
Complete code is below :
json::value postData;
postData[L"name"] = json::value::string(L"Joe Smith");
postData[L"sport"] = json::value::string(L"Baseball");
http_client client(L"https://httpbin.org/post);
http_request request(methods::POST);
request.set_body(postData);
client.request(request).then([](web::http::http_response response) {
json::value j = response.extract_json().get();
json::value data = j.at(U("data"));
std::wcout << "Json : " << data;
// Prints "{\"name\":\"Joe Smith\",\"sport\":\"Baseball\"}"
if (data.has_field(U("name"))) {
std::cout << "Name Found";
}
else {
std::cout << "Name key not Found";
}
});
It seems that your response looks like this:
{ "data": "{\"name\":\"Joe Smith\",\"sport\":\"Baseball\"}" }`
i.e. the actual data is not a JSon object but escaped JSon passed as string. I guess you need to return a payload that looks like this to do what you want to do the way you are doing it:
{
"data": {
"name": "John Smith",
"sport": "Baseball"
}
}

json serialize c++

I have this C++ code, and am having trouble json serializing it.
string uInput;
string const& retInput;
while(!std::cin.eof()) {
getline(cin, uInput);
JSONExample source; //JSON enabled class from jsonserialize.h
source.text = uInput;
//create JSON from producer
std::string json = JSON::producer<JSONExample>::convert(source); //string -> returns {"JSONExample":{"text":"hi"}}
//then create new instance from a consumer...
JSONExample sink = JSON::consumer<JSONExample>::convert(json);
//retInput = serialize(sink);
// Json::FastWriter fastWriter;
// retInput = fastWriter.write(uInput);
retInput = static_cast<string const&>(uInput);
pubnub::futres fr_2 = pb_2.publish(chan, retInput);
cout << "user input as json which should be published is " << retInput<< std::endl;
while(!cin.eof()) {
getline(cin, uInput);
newInput = "\"\\\"";
newInput += uInput;
newInput += "\\\"\"";
Instead of typing in the message like "\"hi\"", this code takes "hi" and does it.
If the change you described made the "Invalid JSON" disappear, then a "more correct" solution would be, AFAICT, to change the publish() line to:
pubnub::futres fr_2 = pb_2.publish(chan, json);
Because json already has JSON serialized data. Of course, if that JSON is what you want to publish.

Sending an image using Poco to a webserver

I'm trying to upload a picture to appengine using POCO::Net::HTMLForm.
Please see the code below. The problem I have is that the imagedata is not send. The token and the character name (its for an open source action rpg) is transmited without any problem. Any idea what I may do wrong?
Thanks in advance :)
c++ code:
// prepare session
Poco::URI uri(backend_url + "/api/update_character_avatar");
Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort());
// prepare path
std::string path(uri.getPathAndQuery());
if (path.empty()) path = "/";
Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_POST, path);
Poco::Net::HTMLForm form;
form.add("token", sw_token);
form.add("charname", sw_charname);
Poco::Buffer<char> imgBuffer(mImgPtr->size());
mImgPtr->read(imgBuffer.begin(), imgBuffer.end()-imgBuffer.begin());
std::string s(imgBuffer.begin(), mImgPtr->size());
std::ostringstream out;
Poco::Base64Encoder b64enc(out);
b64enc.write(imgBuffer.begin(), imgBuffer.end()-imgBuffer.begin());
b64enc.close();
Poco::Net::StringPartSource *prtsrc = new Poco::Net::StringPartSource(out.str());
form.addPart("imagedata", prtsrc);
form.prepareSubmit(req);
std::ostream& send = session.sendRequest(req);
form.write(send);
// get response
Poco::Net::HTTPResponse res;
// print response
std::istream &is = session.receiveResponse(res);
std::ostringstream stream;
Poco::StreamCopier::copyStream(is, stream);
std::cout << stream.str() << std::endl;
Python handler for appengine:
class UpdateCharacterAvatarHandler(webapp2.RequestHandler):
def post(self):
token = self.request.get("token")
charname = self.request.get("charname")
imagedata = self.request.get("imagedata")
logging.error(self.request.body)
self.response.write("test")
Sorry I couldn't understand what exactly you are trying to do in this code. There are lot of useless steps you have taken to upload a file as it can be done simply by using HTMLForm class. Here are the minimum code required to do so -
HTTPRequest request(HTTPRequest::HTTP_POST, "/fileupload/upload_file.php", HTTPMessage::HTTP_1_1);
HTMLForm form;
form.setEncoding(HTMLForm::ENCODING_MULTIPART);
form.addPart("file", new FilePartSource("/home/abc/Pictures/sample.png"));
form.prepareSubmit(request);
HTTPClientSession *httpSession = new HTTPClientSession("localhost");
httpSession->setTimeout(Poco::Timespan(20, 0));
form.write(httpSession->sendRequest(request));
Poco::Net::HTTPResponse res;
std::istream &is = httpSession->receiveResponse(res);
Poco::StreamCopier::copyStream(is, std::cout);
The corresponding upload server is using standard PHP code for uploading HTML form files.
I would expect imagedata to appear as a post field rather than get, so I would try     imagedata = self.request.post("imagedata"). Alternatively try posting it to a server which will allow you to set breakpoints and inspect the content of the request.