Click here to Skip to main content
15,886,056 members
Articles / Programming Languages / C++

Making HTTP REST Request in C++ With WinHTTP

Rate me:
Please Sign up or sign in to vote.
4.85/5 (17 votes)
30 Aug 2022CPOL3 min read 33.4K   1.6K   31   10
How to make an HTTP REST request in C++ with WinHTTP wrapper
In this post, you will learn how to make an HTTP REST Request in C++ with simple WinHTTP Wrapper.

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.

C++
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.

C++
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:

C++
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:

C++
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.

C++
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:

C++
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.

C++
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.

C++
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.

C++
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.

C++
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.

History

  • 30th August, 2022: Updated the source code download to support proxy detection on OSes prior to Windows 8.1.
  • 28th June, 2022: Fixed the Newtonsoft.Json vulnerability reported by Github in RestWebApp project.
  • 6th June, 2022: Added GetHeaderDictionary() and contentLength to HttpResponse in v1.0.4. GetHeaderDictionary() is zero overhead abstraction: It only creates the dictionary when called.
  • 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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Singapore Singapore
Shao Voon is from Singapore. His interest lies primarily in computer graphics, software optimization, concurrency, security, and Agile methodologies.

In recent years, he shifted focus to software safety research. His hobby is writing a free C++ DirectX photo slideshow application which can be viewed here.

Comments and Discussions

 
QuestionHow to extract TLS protocol number using WinHTTP Pin
BrianCharles17-Oct-23 5:36
BrianCharles17-Oct-23 5:36 
AnswerRe: How to extract TLS protocol number using WinHTTP Pin
Shao Voon Wong17-Oct-23 16:20
mvaShao Voon Wong17-Oct-23 16:20 
QuestionThanks a lot. Pin
Member 100756816-Jul-22 19:36
Member 100756816-Jul-22 19:36 
AnswerRe: Thanks a lot. Pin
Shao Voon Wong31-Aug-22 0:21
mvaShao Voon Wong31-Aug-22 0:21 
Sorry, I only see your message now. You're right. I'll fix it now.

AnswerRe: Thanks a lot. Pin
Shao Voon Wong31-Aug-22 0:30
mvaShao Voon Wong31-Aug-22 0:30 
QuestionThank you [Soap] Pin
Member 1215555631-Oct-21 10:52
Member 1215555631-Oct-21 10:52 
AnswerRe: Thank you [Soap] Pin
Shao Voon Wong31-Oct-21 19:25
mvaShao Voon Wong31-Oct-21 19:25 
QuestionHandle Closing Pin
Gabriele Andreoni24-Feb-21 22:46
Gabriele Andreoni24-Feb-21 22:46 
AnswerRe: Handle Closing Pin
Shao Voon Wong25-Feb-21 1:52
mvaShao Voon Wong25-Feb-21 1:52 
GeneralMy vote of 4 Pin
Jan Heckman21-Sep-20 1:04
professionalJan Heckman21-Sep-20 1:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.