make the webAPI more generic so that we can use it in a more standardized fashion
This commit is contained in:
+138
-83
@@ -1,4 +1,6 @@
|
||||
/*
|
||||
Version: 1.3
|
||||
|
||||
This code is just a simple wrapper around nlohmann's wonderful json lib
|
||||
(https://github.com/nlohmann/json) and libcurl. While originally included directly,
|
||||
we have come to realize that we may require web API functionality elsewhere in the future.
|
||||
@@ -15,64 +17,102 @@ License: what's a license? we're a bunch of dirty pirates!
|
||||
|
||||
#include "webAPI.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace StellaBellum;
|
||||
|
||||
/*
|
||||
endpoint: URI
|
||||
data: get/post
|
||||
messageSlot: key for fetching a verbose user friendly message
|
||||
statusSlot: slot containing the success/fail value
|
||||
statusVal: the expected value in the case of success
|
||||
*/
|
||||
webAPI::statusMessage webAPI::simplePost(const string &endpoint, const string &data, const string &slotName, const string &messageSlot, const string &statusSlot, const string &statusVal)
|
||||
webAPI::webAPI(std::string endpoint, std::string userAgent) : uri(endpoint), userAgent(userAgent) {}
|
||||
webAPI::~webAPI()
|
||||
{
|
||||
// declare our output and go ahead and attempt to get data from remote
|
||||
nlohmann::json response = request(endpoint, data);
|
||||
|
||||
// if we got data back...
|
||||
if (response.count(statusSlot) && response[statusSlot].get<std::string>() == statusVal && response.count(slotName))
|
||||
{
|
||||
return {true, response[slotName].get<std::string>()};
|
||||
|
||||
}
|
||||
else //default message is an error, the other end always assumes "success" or the specified slot
|
||||
{
|
||||
if (response.count(messageSlot))
|
||||
{
|
||||
return {false, response[messageSlot].get<std::string>()};
|
||||
}
|
||||
}
|
||||
|
||||
return {false, "Message not provided by remote."};
|
||||
requestData.clear();
|
||||
responseData.clear();
|
||||
}
|
||||
|
||||
// this can be broken out to separate the json bits later if we need raw or other http type requests
|
||||
// all it does is fetch via get or post, and if the status is 200 returns the json, else error json
|
||||
nlohmann::json webAPI::request(const string &endpoint, const string &data, const int &reqType)
|
||||
bool webAPI::setEndpoint(std::string endpoint)
|
||||
{
|
||||
nlohmann::json response;
|
||||
uri = endpoint;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!endpoint.empty()) //data is allowed to be an empty string if we're doing a normal GET
|
||||
std::string webAPI::getRaw()
|
||||
{
|
||||
return sResponse;
|
||||
}
|
||||
|
||||
bool webAPI::setData(std::string &data)
|
||||
{
|
||||
if (!data.empty())
|
||||
{
|
||||
sRequest = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool webAPI::submit(const int &reqType, const int &getPost, const int &respType)
|
||||
{
|
||||
|
||||
if (reqType == 0) // json request
|
||||
{
|
||||
if (!requestData.is_null())
|
||||
{
|
||||
// serialize our data into sRequest
|
||||
sRequest = requestData.dump();
|
||||
|
||||
// clear our the object for next time
|
||||
requestData.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fetch(getPost, respType) && !(sResponse.empty()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
sResponse.clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool webAPI::fetch(const int &getPost, const int &mimeType) // 0 for json 1 for string
|
||||
{
|
||||
if (!uri.empty()) //data is allowed to be an empty string if we're doing a normal GET
|
||||
{
|
||||
CURL *curl = curl_easy_init(); // start up curl
|
||||
|
||||
if (curl)
|
||||
{
|
||||
string readBuffer; // container for the remote response
|
||||
long http_code = 0; // we get this after performing the get or post
|
||||
|
||||
std::string readBuffer; // container for the remote response
|
||||
struct curl_slist *slist = nullptr;
|
||||
|
||||
// set the content type
|
||||
if (mimeType == 0)
|
||||
{
|
||||
slist = curl_slist_append(slist, "Content-Type: application/json");
|
||||
}
|
||||
else
|
||||
{
|
||||
slist = curl_slist_append(slist, "Content-Type: application/x-www-form-urlencoded");
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); // place the data into readBuffer using writeCallback
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); // specify readBuffer as the container for data
|
||||
|
||||
switch (reqType)
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
|
||||
|
||||
switch (getPost)
|
||||
{
|
||||
case 1:
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str());
|
||||
case 0:
|
||||
curl_easy_setopt(curl, CURLOPT_URL, std::string(uri + "?" + sRequest).c_str());
|
||||
break;
|
||||
case 2:
|
||||
std::string getURI = endpoint + "?" + data;
|
||||
curl_easy_setopt(curl, CURLOPT_URL, getURI.c_str());
|
||||
case 1:
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sRequest.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_URL, uri.c_str());
|
||||
break;
|
||||
// want to do a put, or whatever other type? feel free to add here
|
||||
}
|
||||
@@ -80,53 +120,68 @@ nlohmann::json webAPI::request(const string &endpoint, const string &data, const
|
||||
CURLcode res = curl_easy_perform(curl); // make the request!
|
||||
char *contentType;
|
||||
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); //get status code
|
||||
curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &contentType);
|
||||
|
||||
if (res == CURLE_OK && http_code == 200 && !(readBuffer.empty())) // check it all out and parse
|
||||
{
|
||||
// if we ever use anything other than json we can break the stuff below output
|
||||
// into a separate function...
|
||||
try
|
||||
{
|
||||
response = nlohmann::json::parse(readBuffer);
|
||||
}
|
||||
catch (string &e)
|
||||
{
|
||||
response["message"] = e;
|
||||
response["status"] = "failure";
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
response["message"] = "JSON parse error for endpoint.";
|
||||
response["status"] = "failure";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
response["message"] = "Error fetching data from remote.";
|
||||
response["status"] = "failure";
|
||||
}
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode); //get status code
|
||||
curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &contentType); // get response mime type
|
||||
|
||||
curl_slist_free_all(slist);
|
||||
curl_easy_cleanup(curl); // always wipe our butt
|
||||
}
|
||||
else //default err messages below
|
||||
{
|
||||
response["message"] = "Failed to initialize cURL.";
|
||||
response["status"] = "failure";
|
||||
|
||||
if (res == CURLE_OK && statusCode == 200 && !(readBuffer.empty())) // check it all out and parse
|
||||
{
|
||||
sResponse = readBuffer;
|
||||
|
||||
if (std::string(contentType) == "application/json")
|
||||
{
|
||||
processJSON();
|
||||
}
|
||||
else
|
||||
{
|
||||
responseData.clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
response["message"] = "Invalid endpoint URL.";
|
||||
response["status"] = "failure";
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
sResponse.clear();
|
||||
responseData.clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is used by curl to grab the response and put it into a var
|
||||
size_t webAPI::writeCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
((string*)userp)->append((char*)contents, size * nmemb);
|
||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
bool webAPI::processJSON()
|
||||
{
|
||||
if (!(sResponse.empty())) // check it all out and parse
|
||||
{
|
||||
try
|
||||
{
|
||||
responseData = nlohmann::json::parse(sResponse);
|
||||
return true;
|
||||
}
|
||||
catch (std::string &e)
|
||||
{
|
||||
responseData["message"] = e;
|
||||
responseData["status"] = "failure";
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
responseData["message"] = "JSON parse error for endpoint.";
|
||||
responseData["status"] = "failure";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
responseData["message"] = "Error fetching data from remote.";
|
||||
responseData["status"] = "failure";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user