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.47k stars 889 forks source link

Getting "invalid json object" #385

Closed bougayez closed 3 years ago

bougayez commented 3 years ago

when the code tries : auto x = crow::json::load(req.body); I get this error : An uncaught exception occurred: invalid json object

Here is the full piece of code : CROW_ROUTE(app, "/") .methods("GET"_method, "POST"_method) ([](const request& req, response &res){ if(req.method == "POST"_method) { auto x = crow::json::load(req.body); cout << x["fname"] << " " << x["email"] << endl; } else sendHtml(res, "index"); });

Yes i want to output the POST request body to stdout!

The-EDev commented 3 years ago

I believe this exception is thrown when your request body is not a proper json string, what request body are you sending?

bougayez commented 3 years ago

Hi, When outputting the req.body string to stdout it is something like: fname=value&email=value

The-EDev commented 3 years ago

Hmmm, well a proper json body would be something like { "fname": "value", "email": "value" }

fname=value&email=value sound like URL parameters (your link would be http://website.com/endpoint?fname=value&email=value) but I don't really know why they would be in your request body. If you have any control over the client you're using you should either send your parameters with the URL or format them to be like the example above.

bougayez commented 3 years ago

Well, this is a POST method. I was following the example provided by @ipkn in Handling JSON Requests This is it : CROW_ROUTE(app, "/add_json") .methods("POST"_method) ([](const crow::request& req){ auto x = crow::json::load(req.body); if (!x) return crow::response(400); int sum = x["a"].i()+x["b"].i(); std::ostringstream os; os << sum; return crow::response{os.str()}; });

If my code throws an exception for this then, the provided example also does.

The-EDev commented 3 years ago

Yes, I know that, the example is throwing an exception because the request body is not in proper json format, this is because your client is sending the body as fname=value&email=value instead of { "fname": "value", "email": "value" }.

What are you using to make the request?

bougayez commented 3 years ago

I have an HTML form : `

    <fieldset>
      <input name = "email" type="email" tabindex="2" required>
    </fieldset>
    <fieldset>
      <textarea name = "area" tabindex="5" required></textarea>
    </fieldset>
    <fieldset>
      <button type="submit" id="contact-submit" data-submit="...Sending">Submit</button>
    </fieldset>
  </form>`

And it is what makes the POST request in that format. I have managed to make the form send the data in plain text by adding enctype='text/plain' so it is like this now: <form id="contact" action = "/" method='POST' enctype='text/plain'> And it sends the data in this format : fname=value email=value area=value Avoiding the URL encoding. But it is still not a JSON object.

The-EDev commented 3 years ago

so this means you're sending a form, AFAIK crow doesn't currently support parsing forms, but we're working on it (see https://github.com/mrozigor/crow/issues/4).

But if you want to quickly get your form data, you can split the res.body by & then split each result by = and assign the first item as key and second as value into an unordered_map, this should give you a proper map.

crow::json can only parse strings in json format (usually sent from custom clients rather than web pages), so you shouldn't use it with form data.

Edit: To split a string you can use the first example here, then run the same function using a for loop on the items in the split string to get the key,value pairs, and put those into an unoredered_map.

bougayez commented 3 years ago

That makes sense now. Thank you .