Making HTTP REST Request in C++ With WinHTTP

WinHTTP Wrapper

The example code is hosted at Github.

The WinHTTP Wrapper consists of one main class that is HttpRequest class. In its constructor, the following parameters: user_agent, proxy_username, proxy_password, server_username and server_password are optional. When accessing the website through a proxy that needs logon, pass in the proxy_username, proxy_password to the constructor. Sometimes, the webserver needs to be logon as well, in that case, give server_username and server_password. For server logins, the following authentication types are supported.

  • HTTP Basic Authentication
  • HTTP Digest Authentication
  • Passport Authentication
  • NTLM Authentication
  • Kerberos Authentication

When several authentication methods are available, it tries to select the most secure one first. As a word of caution, never use HTTP Basic Authentication, as this method sends user name and password in plaintext that means it is susceptible to Man-In-The-Middle attacks.

The HttpRequest class has 4 public functions that correspond to the 4 HTTP verbs to perform CRUD operations: PUT, GET, POST and DELETE. Each of them receives and returns a HttpResponse object about HTTP operation.

class HttpRequest
{
public:
    HttpRequest(
        const std::wstring& domain,
        int port,
        bool secure,
        const std::wstring& user_agent = L"WinHttpClient",
        const std::wstring& proxy_username = L"",
        const std::wstring& proxy_password = L"",
        const std::wstring& server_username = L"",
        const std::wstring& server_password = L"");

    bool Get(const std::wstring& rest_of_path,
        const std::wstring& requestHeader,
        HttpResponse& response);

    bool Post(const std::wstring& rest_of_path,
        const std::wstring& requestHeader,
        const std::string& body,
        HttpResponse& response);

    bool Put(const std::wstring& rest_of_path,
        const std::wstring& requestHeader,
        const std::string& body,
        HttpResponse& response);

    bool Delete(const std::wstring& rest_of_path,
        const std::wstring& requestHeader,
        const std::string& body,
        HttpResponse& response);
};

This is the HttpResponse class which consists of 1 Reset function and 4 data members that contains information about the HTTP operation.

struct HttpResponse
{
    HttpResponse() : statusCode(0) {}
    void Reset()
    {
        text = "";
        header = L"";
        statusCode = 0;
        error = L"";
    }

    std::string text;
    std::wstring header;
    DWORD statusCode;
    std::wstring error;
};

Usage

Please open the RestWebApp solution in Visual Studio and run it with Ctrl-F5 before running the example code below. You will encounter an error in the web browser when running it, this is due to RestWebApp is a Web API that contains no HTML pages to be viewed on a web browser.

Create 1 product

This is example code to create 1 product in the website, using HTTP POST

using namespace std;
const wstring domain = L"localhost";
const wstring requestHeader = L"Content-Type: application/json";
int port = 51654;
bool https = false;

using namespace WinHttpWrapper;

HttpRequest req(domain, port, https);
HttpResponse response;

cout << "Action: Create Product with Id = 1" << endl;
req.Post(L"/api/products/create", 
    requestHeader,
    R"({"Id":1, "Name":"ElectricFan","Qty":14,"Price":20.90})", 
    response);
cout << "Returned Status:" << response.statusCode << endl << endl;
response.Reset();

The output is below.

Action: Create Product with Id = 1
Returned Status:200

Retrieve 1 product

Then we retrieve the newly created product which has the id = 1, using HTTP GET.

cout << "Action: Retrieve the product with id = 1" << endl;
req.Get(L"/api/products/1", L"", response);
cout << "Returned Text:" << response.text << endl << endl;
response.Reset();

The output is below.

Action: Retrieve the product with id = 1
Returned Text:{"Id":1,"Name":"ElectricFan","Qty":14,"Price":20.90}

Update 1 product

The product is then updated with a new price, using HTTP POST again.

cout << "Action: Update Product with Id = 1" << endl;
req.Post(L"/api/products/1", 
    requestHeader,
    R"({"Id":1, "Name":"ElectricFan","Qty":15,"Price":29.80})", 
    response);
cout << "Returned Status:" << response.statusCode << endl << endl;
response.Reset();

The output is below.

Action: Update Product with Id = 1
Returned Status:200

Retrieve all products

All products are retrieved, using HTTP GET to see if the new price is reflected.

cout << "Action: Retrieve all products" << endl;
req.Get(L"/api/products", L"", response);
cout << "Returned Text:" << response.text << endl << endl;
response.Reset();

The output is below.

Action: Retrieve all products
Returned Text:[{"Id":1,"Name":"ElectricFan","Qty":15,"Price":29.80}]

Delete 1 product

The only one product is deleted, using HTTP DELETE.

cout << "Action: Delete the product with id = 1" << endl;
req.Delete(L"/api/products/1", L"", "", response);
cout << "Returned Status:" << response.statusCode << endl << endl;
response.Reset();

The output is below.

Action: Delete the product with id = 1
Returned Status:200

Retrieve all products

All products are retrieved, using HTTP GET, to see if the product is deleted.

cout << "Action: Retrieve all products" << endl;
req.Get(L"/api/products", L"", response);
cout << "Returned Text:" << response.text << endl << endl;
response.Reset();

The output is below.

Action: Retrieve all products
Returned Text:[]

Pros and Cons of WinHTTP

Pros

  • WinHTTP comes bundled with Windows which means you do not have to include the code in your project.
  • Comes with Windows NTLM and Kerberos authentication out of the box.
  • Comes with web proxy authentication out of the box.

Cons

  • WinHTTP is tied to each Windows version. Take, for example, Windows XP which is End-Of_life, does not receive updates from Microsoft anymore, so its WinHTTP is stuck without TLS 1.3 support. It may not be a problem if you are only accessing your old intranet website whose web server is not the latest.
  • Windows only. Not cross-platform.
  • A minor code amendment is needed for WinHTTP on older Windows.

Making HTTP REST Request in C++ (With CPR)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: