BudgetBaller
BudgetBaller

Reputation: 19

Problems with libcurl and JSON for Modern C++

I'm trying to teach myself C++ by writing a simple program that sends a cURL request to a JSON API, parses the data and then stores it either in a text document or database for a web application to access. I have done this task in PHP and figured C++ wouldn't be much harder but I can't even get cURL to return a string and display it.

I get this to compile with no errors, but the response "JSON data: " doesn't display anything where the JSON data should be.

Where did I go wrong? URL-to-API is the actual URL, so I believe I'm using a wrong setopt function, or not setting one. In PHP, "CURLOPT_RETURNTRANSFER" made it return as a string, but I get an error with it:

error: ‘CURLOPT_RETURNTRANSFER’ was not declared in this scope
curl_easy_setopt(curl, CURLOPT_RETURNTRANSFER, true);

I'm using g++ compiler on Ubuntu and added -lcurl to the command line argument.

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <curl/curl.h>
//#include "json.hpp"

using namespace std;
//using json = nlohmann::json;

size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp) {
    ((std::string*)userp)->append((char*)contents, size * nmemb);
    return size * nmemb;
}

string getJSON(string URL) {

    CURL *curl;
    CURLcode res;
    string readBuffer;

    curl = curl_easy_init();
    if(curl) {

        curl_easy_setopt(curl, CURLOPT_HEADER, 1);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); // follow redirect
        //curl_easy_setopt(curl, CURLOPT_RETURNTRANSFER, true); // return as string
        curl_easy_setopt(curl, CURLOPT_HEADER, false);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_URL, URL);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);     

        res = curl_easy_perform(curl);

    /* always cleanup */
        curl_easy_cleanup(curl);

        return readBuffer;
    }

    return 0;
}

int main() {

    string data = getJSON("URL-to-api");

    cout << "JSON Data: \n" << data;

    return 0;
}

When I uncomment the JSON for Modern C++ include and namespace line I get this error:

error This file requires compiler and library support for the ISO C++ 2011 standard. This support must be enabled with the -std=c++11 or -std=gnu++11 compiler options.

Along with a bunch of errors for functions in that library. I just downloaded the most recent version of g++ before embarking on this project, so what do I need to do?

I'm using g++ 5.4.0 on Ubuntu.

UPDATE:

So I added a check under res = curl_easy_perform(curl) and it doesn't return the error message, and res gets displayed as 6. This seems to be much more difficult than it should be:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <curl/curl.h>
//#include "json.hpp"

using namespace std;
//using json = nlohmann::json;

size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp) {
    ((std::string*)userp)->append((char*)contents, size * nmemb);
    return size * nmemb;
}

string getJSON(string URL) {

    CURL *curl;
    CURLcode res;
    string readBuffer;

    curl = curl_easy_init();

    if(curl) {

        curl_easy_setopt(curl, CURLOPT_HEADER, 1);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); // follow redirect
        curl_easy_setopt(curl, CURLOPT_HEADER, false);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_URL, URL);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);     

        res = curl_easy_perform(curl);
        cout << res << endl;
        if (!res) {
            cout << "cURL didn't work\n";
        }

    /* always cleanup */
        curl_easy_cleanup(curl);
        curl = NULL;
        return readBuffer;
    }
}

int main() {

    string data = getData("");

    cout << "JSON Data: \n" << data;

    return 0;
}

I get the following output when I run the program:

6
JSON Data:

Upvotes: 0

Views: 1376

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595320

In PHP "CURLOPT_RETURNTRANSFER" made it return as a string but I get an error:

error: ‘CURLOPT_RETURNTRANSFER’ was not declared in this scope
curl_easy_setopt(curl, CURLOPT_RETURNTRANSFER, true);

There is no CURLOPT_RETURNTRANSFER option documented for curl_easy_setopt(). I think that is an option specify to PHP's curl_exec() function, which doesn't exist in CURL itself. CURLOPT_WRITEFUNCTION is the correct way to go in this situation.

When I uncomment the JSON for Modern C++ include and namespace line I get:

error This file requires compiler and library support for the ISO C++ 2011 standard. This support must be enabled with the -std=c++11 or -std=gnu++11 compiler options.

The error is self-explanatory. Your JSON library requires C++11 but you are not compiling with C++11 enabled. Some modern compilers still default to an older C++ version (usually C++98) and require you to explicitly enable C++11 (or later) when invoking the compiler on the command line, or in your project makefile configuration.

In the case of g++, the current version (8.2) defaults to (the GNU dialect of) C17 for C and C++14 for C++, if not specified otherwise via the -std parameter. Your version (5.4) defaults to (the GNU dialect of) C11 and C++98, respectively.

UPDATE: there are other mistakes in your code:

  1. You are passing a std::string object to curl_easy_setopt() where a char* pointer is expected for CURLOPT_URL. You need to change this:

    curl_easy_setopt(curl, CURLOPT_URL, URL);
    

    To this instead:

    curl_easy_setopt(curl, CURLOPT_URL, URL.c_str());
    
  2. You are not testing the return value of curl_easy_perform() correctly. Per the documentation, curl_easy_perform() returns 0 (CURLE_OK) on success, and non-zero on error, so you need to change this:

    if (!res)
    

    To this instead:

    if (res != CURLE_OK)
    
  3. So I added a check under res = curl_easy_perform(curl) ..., and res gets displayed as 6.

    That is CURLE_COULDNT_RESOLVE_HOST, which makes sense as your updated example is passing a blank URL to getJSON():

    string data = getJSON(""); // should be "URL-to-api" instead!
    

Upvotes: 1

Related Questions