make the webAPI more generic so that we can use it in a more standardized fashion

This commit is contained in:
DarthArgus
2016-08-20 11:19:23 +00:00
parent e0d9f58ba0
commit 5f0e741a72
5 changed files with 302 additions and 132 deletions
+138 -83
View File
@@ -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;
}