6

Making HTTP REST Request in C++ With WinHTTP

 2 years ago
source link: https://www.codeproject.com/Articles/5280036/Making-HTTP-REST-Request-in-Cplusplus-With-WinHTTP
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

The example code is hosted at Github.

Table of Contents

WinHTTP Wrapper

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 four public functions that correspond to the 4 HTTP verbs to perform CRUD operations: PUT, GET, POST and DELETE. Each of them receives and returns an HttpResponse object about HTTP operation.

Shrink ▲   Copy Code
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 contain information about the HTTP operation.

Copy Code
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 in 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 on the website, using HTTP POST:

Copy Code
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:

Copy Code
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.

Copy Code
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:

Copy Code
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.

Copy Code
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:

Copy Code
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.

Copy Code
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:

Copy Code
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.

Copy Code
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:

Copy Code
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.

Copy Code
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:

Copy Code
Action: Retrieve all products
Returned Text:[]

Pros and Cons of WinHTTP

  • 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
  • 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.

Related Article

History

  • 6th March, 2021: Updated the source code download to set the text regardless of the HTTP status in v1.0.3.
  • 25th February, 2021: Fixed the handle leak caused by returning prematurely from http().
  • 20th September, 2020: First release

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK