• Stars
    star
    1,509
  • Rank 29,907 (Top 0.7 %)
  • Language
    C++
  • License
    MIT License
  • Created over 13 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

C++ client for making HTTP/REST requests

REST client for C++

build status Coverage Status Packagecloud doxygen MIT license

About

This is a simple REST client for C++. It wraps libcurl for HTTP requests.

Usage

restclient-cpp provides two ways of interacting with REST endpoints. There is a simple one, which doesn't need you to configure an object to interact with an API. However the simple way doesn't provide a lot of configuration options either. So if you need more than just a simple HTTP call, you will probably want to check out the advanced usage.

Simple Usage

The simple API is just some static methods modeled after the most common HTTP verbs:

#include "restclient-cpp/restclient.h"

RestClient::Response r = RestClient::get("http://url.com")
RestClient::Response r = RestClient::post("http://url.com/post", "application/json", "{\"foo\": \"bla\"}")
RestClient::Response r = RestClient::put("http://url.com/put", "application/json", "{\"foo\": \"bla\"}")
RestClient::Response r = RestClient::patch("http://url.com/patch", "application/json", "{\"foo\": \"bla\"}")
RestClient::Response r = RestClient::del("http://url.com/delete")
RestClient::Response r = RestClient::head("http://url.com")
RestClient::Response r = RestClient::options("http://url.com")

The response is of type RestClient::Response and has three attributes:

RestClient::Response.code // HTTP response code
RestClient::Response.body // HTTP response body
RestClient::Response.headers // HTTP response headers

Advanced Usage

However if you want more sophisticated features like connection reuse, timeouts or authentication, there is also a different, more configurable way.

#include "restclient-cpp/connection.h"
#include "restclient-cpp/restclient.h"

// initialize RestClient
RestClient::init();

// get a connection object
RestClient::Connection* conn = new RestClient::Connection("http://url.com");

// configure basic auth
conn->SetBasicAuth("WarMachine68", "WARMACHINEROX");

// set connection timeout to 5s
conn->SetTimeout(5);

// set custom user agent
// (this will result in the UA "foo/cool restclient-cpp/VERSION")
conn->SetUserAgent("foo/cool");

// enable following of redirects (default is off)
conn->FollowRedirects(true);
// and limit the number of redirects (default is -1, unlimited)
conn->FollowRedirects(true, 3);

// set headers
RestClient::HeaderFields headers;
headers["Accept"] = "application/json";
conn->SetHeaders(headers)

// append additional headers
conn->AppendHeader("X-MY-HEADER", "foo")

// if using a non-standard Certificate Authority (CA) trust file
conn->SetCAInfoFilePath("/etc/custom-ca.crt")

RestClient::Response r = conn->get("/get")
RestClient::Response r = conn->head("/get")
RestClient::Response r = conn->del("/delete")
RestClient::Response r = conn->options("/options")

// set different content header for POST, PUT and PATCH
conn->AppendHeader("Content-Type", "application/json")
RestClient::Response r = conn->post("/post", "{\"foo\": \"bla\"}")
RestClient::Response r = conn->put("/put", "application/json", "{\"foo\": \"bla\"}")
RestClient::Response r = conn->patch("/patch", "text/plain", "foobar")

// deinit RestClient. After calling this you have to call RestClient::init()
// again before you can use it
RestClient::disable();

The responses are again of type RestClient::Response and have three attributes:

RestClient::Response.code // HTTP response code
RestClient::Response.body // HTTP response body
RestClient::Response.headers // HTTP response headers

The connection object also provides a simple way to get some diagnostics and metrics information via conn->GetInfo(). The result is a RestClient::Connection::Info struct and looks like this:

typedef struct {
  std::string base_url;
  RestClients::HeaderFields headers;
  int timeout;
  struct {
    std::string username;
    std::string password;
  } basicAuth;

  std::string certPath;
  std::string certType;
  std::string keyPath;
  std::string keyPassword;
  std::string customUserAgent;
  std::string uriProxy;
  struct {
    // total time of the last request in seconds Total time of previous
    // transfer. See CURLINFO_TOTAL_TIME
    int totalTime;
    // time spent in DNS lookup in seconds Time from start until name
    // resolving completed. See CURLINFO_NAMELOOKUP_TIME
    int nameLookupTime;
    // time it took until Time from start until remote host or proxy
    // completed. See CURLINFO_CONNECT_TIME
    int connectTime;
    // Time from start until SSL/SSH handshake completed. See
    // CURLINFO_APPCONNECT_TIME
    int appConnectTime;
    // Time from start until just before the transfer begins. See
    // CURLINFO_PRETRANSFER_TIME
    int preTransferTime;
    // Time from start until just when the first byte is received. See
    // CURLINFO_STARTTRANSFER_TIME
    int startTransferTime;
    // Time taken for all redirect steps before the final transfer. See
    // CURLINFO_REDIRECT_TIME
    int redirectTime;
    // number of redirects followed. See CURLINFO_REDIRECT_COUNT
    int redirectCount;
  } lastRequest;
} Info;

Persistent connections/Keep-Alive

The connection object stores the curl easy handle in an instance variable and uses that for the lifetime of the object. This means curl will automatically reuse connections made with that handle.

Progress callback

Two wrapper functions are provided to setup the progress callback for uploads/downloads.

Calling conn->SetFileProgressCallback(callback) with a callback parameter matching the prototype int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) will setup the progress callback.

Calling conn->SetFileProgressCallbackData(data) is optional. This will set the data pointer which is the first parameter fed back to the progress callback - clientp. If this isn't set then clientp will default to the connection object conn.

// set CURLOPT_NOPROGRESS
// set CURLOPT_PROGRESSFUNCTION
conn->SetFileProgressCallback(progressFunc);
// set CURLOPT_PROGRESSDATA
conn->SetFileProgressCallbackData(data);

Write callback

A write callback function can be provided for processing data as it's received from a GET call (for instance the Kubernetes Watch API).

Calling conn->SetWriteFunction(callback) with a function parameter matching the prototype size_t write_function(void *data, size_t size, size_t nmemb, void *userdata)int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) will setup the write function.

Here is an example of a write callback function, processing result data line by line.

auto writeCallback = [](void *data, size_t size, size_t nmemb, void *userdata) -> size_t
{
  size_t bytes = size * nmemb;
  try
  {
      // Add to the buffer
      auto res = reinterpret_cast<RestClient::Response *>(userdata);
      res->body.append(static_cast<char*>(data), bytes);
      // If the last character is not a new line, wait for the rest.
      if ('\n' != *(res->body.end() - 1))
      {
          return bytes;
      }
      // Process data one line at a time.
      std::stringstream stream(res->body);
      std::string line;
      while (std::getline(stream, line))
      {
        // Do something with the line here...
      }
      // Done processing the line
      res->body.clear();
  }
  catch(std::exception e)
  {
      // Log caught exception here
      return 0;
  }
  return bytes;
};

Error handling

When restclient-cpp encounters an error, generally the error (or "status") code is returned in the Response (see Response struct in restclient.h). This error code can be either an HTTP error code, or if a lower-level cURL error was encountered, it may be a CURLCode. Currently, libcurl only defines 92 error codes, which means there is no overlap between cURL error codes and HTTP response codes (which start at 1xx). However, if in the future, libcurl defines more than 99 error codes, meaning that cURL errors overlap with the HTTP 1xx class of responses, restclient-cpp will return a -1 if the CURLCode is 100 or higher. In this case, callers can use GetInfo().lastRequest.curlCode to inspect the actual cURL error.

Thread Safety

restclient-cpp leans heavily on libcurl as it aims to provide a thin wrapper around it. This means it adheres to the basic level of thread safety provided by libcurl. The RestClient::init() and RestClient::disable() methods basically correspond to curl_global_init and curl_global_cleanup and thus need to be called right at the beginning of your program and before shutdown respectively. These set up the environment and are not thread-safe. After that you can create connection objects in your threads. Do not share connection objects across threads as this would mean accessing curl handles from multiple threads at the same time which is not allowed.

The connection level method SetNoSignal can be set to skip all signal handling. This is important in multi-threaded applications as DNS resolution timeouts use signals. The signal handlers quite readily get executed on other threads. Note that with this option DNS resolution timeouts do not work. If you have crashes in your multi-threaded executable that appear to be in DNS resolution, this is probably why.

In order to provide an easy to use API, the simple usage via the static methods implicitly calls the curl global functions and is therefore also not thread-safe.

HTTPS User Certificate

Simple wrapper functions are provided to allow clients to authenticate using certificates. Under the hood these wrappers set cURL options, e.g. CURLOPT_SSLCERT, using curl_easy_setopt. Note: currently libcurl compiled with gnutls (e.g. libcurl4-gnutls-dev on ubuntu) is buggy in that it returns a wrong error code when these options are set to invalid values.

// set CURLOPT_SSLCERT
conn->SetCertPath(certPath);
// set CURLOPT_SSLCERTTYPE
conn->SetCertType(type);
// set CURLOPT_SSLKEY
conn->SetKeyPath(keyPath);
// set CURLOPT_KEYPASSWD
conn->SetKeyPassword(keyPassword);

HTTP Proxy Tunneling Support

An HTTP Proxy can be set to use for the upcoming request. To specify a port number, append :[port] to the end of the host name. If not specified, libcurl will default to using port 1080 for proxies. The proxy string may be prefixed with http:// or https://. If no HTTP(S) scheme is specified, the address provided to libcurl will be prefixed with http:// to specify an HTTP proxy. A proxy host string can embedded user + password. The operation will be tunneled through the proxy as curl option CURLOPT_HTTPPROXYTUNNEL is enabled by default. A numerical IPv6 address must be written within [brackets].

// set CURLOPT_PROXY
conn->SetProxy("https://37.187.100.23:3128");
/* or you can set it without the protocol scheme and
http:// will be prefixed by default */
conn->SetProxy("37.187.100.23:3128");
/* the following request will be tunneled through the proxy */
RestClient::Response res = conn->get("/get");

Unix Socket Support

Note that the URL used with a unix socket has only ONE leading forward slash.

RestClient::Connection* conn = new RestClient::Connection("http:/v1.30");
conn->SetUnixSocketPath("/var/run/docker.sock");
RestClient::HeaderFields headers;
headers["Accept"] = "application/json; charset=UTF-8";
headers["Expect"] = "";
conn->SetHeaders(headers);
auto resp = conn->get("/images/json");

Dependencies

Installation

There are some packages available for Linux on packagecloud. And for OSX you can get it from the mrtazz/oss homebrew tap:

brew tap mrtazz/oss
brew install restclient-cpp

Otherwise you can do the regular autotools dance:

./autogen.sh
./configure
make install

Alternatively, you can build and install restclient-cpp using vcpkg dependency manager:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install restclient-cpp

The restclient-cpp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

Another option is to use Mingw64 and CMake to compile on Windows. This requires you to have Mingw64 installed with CMake and libCurl (MSYS2 would also work fine).

# Make sure cmake, mingw32-make and g++ are in PATH
# Clone the repo
git clone https://github.com/mrtazz/restclient-cpp && cd restclient-cpp
# Build library
mkdir build && cd build
# Run cmake
cmake -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CC_COMPILER=gcc -DCMAKE_MAKE_PROGRAM=mingw32-make -G "MinGW Makefiles" ..
# Builds the dll.a lib and dll file
mingw32-make

Contribute

All contributions are highly appreciated. This includes filing issues, updating documentation and writing code. Please take a look at the contributing guidelines before so your contribution can be merged as fast as possible.

More Repositories

1

checkmake

experimental linter/analyzer for Makefiles
Go
999
star
2

plustache

{{mustaches}} for C++
C++
203
star
3

katana

ready to go heroku hosted URL shortener based on guillotine
Ruby
74
star
4

json-cpp

[DEPRECATED] use https://github.com/open-source-parsers/jsoncpp
C++
71
star
5

InstapaperLibrary

Simple python library utilizing the instapaper.com API
Python
54
star
6

notifo.py

python wrapper for notifo.com
Python
33
star
7

bin

my ~/bin folder
30
star
8

dotfiles

collection of my dotfiles
Vim Script
28
star
9

pocketcleaner

keep your pocket clean
Go
24
star
10

DoxygenToolkit.vim

Doxygen plugin for vim
Vim Script
19
star
11

statsd-amqp-backend

StatsD backend to emit stats to AMQP
JavaScript
16
star
12

cookbooks

collection of chef cookbooks, mainly for FreeBSD and OSX
HTML
13
star
13

molokai.vim

tomas restrepos molokai theme for vim put here for easy installation as a submodule via pathogen
Vim Script
13
star
14

statsd-traffic-loader

simple CLI script to send traffic to StatsD
Go
11
star
15

instapaper.py

cli client for instapaper.com - now contained in the python library
Python
11
star
16

sensu-heroku-app

example app to run sensu on heroku
Ruby
10
star
17

knife-wip

A workflow plugin to track WIP nodes on a chef server
Ruby
10
star
18

gtd-couch

gtd task management with a couchapp
JavaScript
10
star
19

vimfiles

moved into https://github.com/mrtazz/dotfiles
Vim Script
9
star
20

GithubFeedFilter

[not maintained] Sinatra + Redis app to show a filtered github feed
Ruby
9
star
21

yagd

super simple dashboard framework in PHP
PHP
9
star
22

vim-stencil

simple template loading plugin for VIM
Vim Script
8
star
23

fitbit-to-graphite

record fitbit sleep data into graphite
Ruby
8
star
24

knife-node-attribute

knife plugin to show and delete node attributes
Ruby
8
star
25

snyder

metrics library for C++11
C++
8
star
26

muttfiles

moved into https://github.com/mrtazz/dotfiles
7
star
27

certcal

provide an iCal web feed for certificate expiration
Go
7
star
28

thingnatra

Sinatra frontend for Things.app data
Ruby
7
star
29

homebrew-misc

additional formula for https://github.com/mxcl/homebrew
Ruby
6
star
30

weechat-config

config files for weechat
Python
6
star
31

couchapp-cucumber

Cucumber drop-in for testing couchapps
Ruby
6
star
32

instareader.py

Add starred items from google reader to instapaper
Python
6
star
33

vim-plan

experiments in a vim plugin for personal planning
Vim Script
5
star
34

ramrod

Command center for multiple CI instances/agents
JavaScript
5
star
35

kangaroo

location aware task planer for mobile devices
Java
5
star
36

minibashtest

simplest unit testing framework for bash
Shell
5
star
37

irssi-zeromq

Irssi script to distribute events via ZeroMQ pub/sub
Perl
5
star
38

github-unreleased

find commits in a GitHub repository that got added after the most recent release/tag
Go
5
star
39

recipes

Collection of recipes, for actual cooking and stuff
4
star
40

relaxtrack

time tracking couchapp
JavaScript
4
star
41

chef-groveio-handler

Chef report handler to push a notice into a grove.io channel
Ruby
4
star
42

admiral

Inverted Index implementation with web server and frontend in python
Python
4
star
43

chinstrap

[WIP] Pure C mustache parser
C
4
star
44

mrtazz.github.com

homepage
CSS
3
star
45

zerigo_dyndns.sh

dyndns update shell script with zerigo and http://icanhazip.com
Shell
3
star
46

gifs

my collection of gifs
HTML
3
star
47

zshfiles

moved into https://github.com/mrtazz/dotfiles
Shell
3
star
48

notify-by-pushover

Nagios pushover notification script written in Go
Go
3
star
49

leoric-skeletons

my skeleton setup to use with http://code.mrtazz.com/leoric/
PHP
3
star
50

towbar

Python API wrapper for boxcar.io
Python
3
star
51

osxzip-cookbook

Chef LWRP for installing zipped OSX apps
Ruby
3
star
52

introduction-to-algorithms

Algorithm implementations from the book
Python
3
star
53

coppergenie

webhook bridge between copperegg alerts and opsgenie notifications
Ruby
2
star
54

kong-ini

ini file configuration resolver for alecthomas/kong
Go
2
star
55

go-statsd-proxy

consistent hashing based proxy for multiple statsd backends
Go
2
star
56

octonode

[Nothing to see because I never found the time to actually work on this] node.js wrapper for the github v3 API
2
star
57

twsh

A twitter client, which feels a bit like a shell, using the library from http://code.google.com/p/python-twitter/
Python
2
star
58

BackoffTimer

a simple backoff timer written in rust
Rust
2
star
59

php-dyndns

php dyndns system
PHP
2
star
60

unwiredcouch.com

the website
CSS
2
star
61

foodlist

makes importable shopping lists from yaml input
Python
2
star
62

troubagix

troubagix sings into your IRC channel when something happens in your github repositories
2
star
63

groupmecat

bot for groupme
JavaScript
2
star
64

http-test-server

simple HTTP test server for testing client side http calls
Ruby
2
star
65

twanity

see all those important twitter stats about yourself
Go
1
star
66

whoownsmyworklifebalance.com

what it says on the tin
HTML
1
star
67

thunkapi.py

Python API wrapper for thunk.us
Python
1
star
68

pkgr

tool to create pkgng packages from a directory
Go
1
star
69

gistapi.erl

erlang wrapper for the gist.github.com API
Erlang
1
star
70

stz-hubot

hubot for the stz offtopic channel
CoffeeScript
1
star
71

notify-by-opsgenie

simple program to notify opsgenie from nagios
Go
1
star
72

irc-notifier

notifier for my IRC setup
Go
1
star
73

ketchupstatus

Status of ketchup supply with sinatra and mustache
Ruby
1
star
74

php-nagioseasier

PHP wrapper around the nagioseasier query handler
PHP
1
star
75

artefacts

place to build some public containers
Dockerfile
1
star
76

jekyll-layouts

collection of layouts I use for jekyll generated pages
HTML
1
star
77

chef-deploy

tool to deploy changes to a Chef server based on a git diff
Go
1
star
78

disrupt

send notifications via multiple providers
Go
1
star
79

plan

cli tool for some planning tasks
Go
1
star
80

mime-extractor

extract mime bodies from email
Go
1
star
81

emo.theme

an irssi theme based on gothic
PHP
1
star
82

kerl-cookbook

chef cookbook for kerl
Ruby
1
star
83

leoric

Project initialization from skeleton files
Shell
1
star
84

cocoa-currency-converter

Xcode tutorial
Objective-C
1
star