3 ==================================================================================
4 Copyright (c) 2022 Alexandre Huff
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================================
21 Mnemonic: restclient.cpp
22 Abstract: Implements a tiny wrapper on top of libcurl to handle with rest requests.
25 Author: Alexandre Huff
29 #include "restclient.hpp"
34 namespace restclient {
36 // callback to handle http responses
37 static size_t http_response_callback( const char *in, size_t size, size_t num, std::string *out ) {
41 const size_t totalBytes( size * num );
42 out->append( in, totalBytes );
47 Create a RestClient instance to exchange messages with
48 a given rest api available on baseUrl, which consists of
49 scheme://domain[:port]
51 RestClient::RestClient( std::string baseUrl ) {
52 this->baseUrl = baseUrl;
55 fprintf( stderr, "unable to initialize RestClient\n" );
59 RestClient::~RestClient( ) {
60 curl_slist_free_all( headers );
61 curl_easy_cleanup( curl );
64 std::string RestClient::getBaseUrl( ) {
68 bool RestClient::init( ) {
69 static std::mutex curl_mutex;
71 { // scoped mutex to make curl_global_init thread-safe
72 const std::lock_guard<std::mutex> lock( curl_mutex );
73 curl_global_init( CURL_GLOBAL_DEFAULT );
76 curl = curl_easy_init();
81 // curl_easy_setopt( curl, CURLOPT_VERBOSE, 1L );
82 curl_easy_setopt( curl, CURLOPT_TIMEOUT, 5 );
84 /* provide a buffer to store errors in */
85 if( curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf) != CURLE_OK ) {
86 fprintf( stderr, "unable to set CURLOPT_ERRORBUFFER\n" );
91 if( curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, http_response_callback ) != CURLE_OK ) {
92 fprintf( stderr, "unable to set CURLOPT_WRITEFUNCTION\n" );
96 if( curl_easy_setopt( curl, CURLOPT_WRITEDATA, &response.body ) != CURLE_OK ) {
97 fprintf( stderr, "unable to set CURLOPT_WRITEDATA\n" );
101 headers = curl_slist_append( headers, "Accept: application/json" );
102 headers = curl_slist_append( headers, "Content-Type: application/json" );
103 if( curl_easy_setopt( curl, CURLOPT_HTTPHEADER, headers ) != CURLE_OK ) {
104 fprintf( stderr, "unable to set CURLOPT_HTTPHEADER\n" );
112 Executes a GET request at the path of this RestClient instance.
113 Returns the HTTP status code and the correspoding message body.
115 response_t RestClient::do_get( std::string path ) {
116 response = { 0, "" };
118 const std::string endpoint = baseUrl + path;
120 if( curl_easy_setopt( curl, CURLOPT_URL, endpoint.c_str() ) != CURLE_OK ) {
121 fprintf( stderr, "unable to set CURLOPT_URL\n" );
124 if( curl_easy_setopt( curl, CURLOPT_HTTPGET, 1L ) != CURLE_OK ) {
125 fprintf( stderr, "unable to set CURLOPT_HTTPGET\n" );
129 CURLcode res = curl_easy_perform( curl );
130 if( res == CURLE_OK ) {
131 if( curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &response.status_code ) != CURLE_OK ) {
132 fprintf( stderr, "unable to get CURLINFO_RESPONSE_CODE\n" );
135 size_t len = strlen( errbuf );
136 fprintf( stderr, "unable to complete the request url=%s ", endpoint.c_str() );
138 fprintf( stderr, "error=%s%s", errbuf,
139 ( ( errbuf[len - 1] != '\n' ) ? "\n" : "") );
141 fprintf( stderr, "error=%s\n", curl_easy_strerror( res ) );
148 Executes a POST request of a json message at the path of this RestClient instance.
149 Returns the HTTP status code and the correspoding message body.
151 response_t RestClient::do_post( std::string path, std::string json ) {
152 response = { 0, "" };
154 const std::string endpoint = baseUrl + path;
156 if( curl_easy_setopt( curl, CURLOPT_URL, endpoint.c_str() ) != CURLE_OK ) {
157 fprintf( stderr, "unable to set CURLOPT_URL\n" );
160 if( curl_easy_setopt( curl, CURLOPT_POST, 1L ) != CURLE_OK ) {
161 fprintf( stderr, "unable to set CURLOPT_POST\n" );
164 if( curl_easy_setopt( curl, CURLOPT_POSTFIELDS, json.c_str() ) != CURLE_OK ) {
165 fprintf( stderr, "unable to set CURLOPT_POSTFIELDS\n" );
169 CURLcode res = curl_easy_perform( curl );
170 if( res == CURLE_OK ) {
171 if( curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &response.status_code ) != CURLE_OK ) {
172 fprintf( stderr, "unable to get CURLINFO_RESPONSE_CODE\n" );
175 size_t len = strlen( errbuf );
176 fprintf( stderr, "unable to complete the request url=%s ", endpoint.c_str() );
178 fprintf( stderr, "error=%s%s", errbuf,
179 ( (errbuf[len - 1] != '\n' ) ? "\n" : "") );
181 fprintf( stderr, "error=%s\n", curl_easy_strerror( res ) );