Add example of REST client
by using libcurl for HTTP connection and M*LIB for JSON formating.
This commit is contained in:
1 parent
b16048a55b
commit
0c8eca893d
2 files changed
+164
-4
No files matched your search
+4
-4
@@ -31,7 +31,7 @@ RM=rm -f
|
|||||||
.SUFFIXES: .c .exe
|
.SUFFIXES: .c .exe
|
||||||
|
|
||||||
.c.exe:
|
.c.exe:
|
||||||
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ `cat config` $(LDFLAGS)
|
$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ `cat config` `cat config.curl` $(LDFLAGS)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
@$(MAKE) config
|
@$(MAKE) config
|
||||||
@@ -53,11 +53,11 @@ config:
|
|||||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=0 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0 -DHAVE_MPFR=0 " > config
|
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -L$(GMP_DIR)/lib config-test.c -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=0 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -lgmp" > config || echo "-DHAVE_GMP=0 -DHAVE_MPFR=0 " > config
|
||||||
printf "#include <mpfr.h>\nint main(void){mpfr_t z; mpfr_init(z); return 0;}\n" > config-test.c
|
printf "#include <mpfr.h>\nint main(void){mpfr_t z; mpfr_init(z); return 0;}\n" > config-test.c
|
||||||
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -I$(MPFR_DIR)/include -L$(GMP_DIR)/lib -L$(MPFR_DIR)/lib config-test.c -lmpfr -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -I$(MPFR_DIR)/include -L$(MPFR_DIR)/lib -lmpfr -lgmp" > config || echo "MPFR not available"
|
$(CC) $(CFLAGS) $(CPPFLAGS) -I$(GMP_DIR)/include -I$(MPFR_DIR)/include -L$(GMP_DIR)/lib -L$(MPFR_DIR)/lib config-test.c -lmpfr -lgmp -o config-test.exe $(LDFLAGS) 2> /dev/null && echo "-DHAVE_GMP=1 -DHAVE_MPFR=1 -I$(GMP_DIR)/include -L$(GMP_DIR)/lib -I$(MPFR_DIR)/include -L$(MPFR_DIR)/lib -lmpfr -lgmp" > config || echo "MPFR not available"
|
||||||
|
printf "#include <curl/curl.h>\nint main(void){curl_global_init(CURL_GLOBAL_DEFAULT);}" > config-test.c
|
||||||
|
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c `curl-config --cflags --libs` -o config-test.exe 2> /dev/null && echo "-DHAVE_CURL=1 `curl-config --cflags --libs`" > config.curl || echo "-DHAVE_CURL=0 " > config.curl
|
||||||
printf "#include <stdio.h>\nint main(void){printf(\"Ok\"); return 0;}\n" > config-test.c
|
printf "#include <stdio.h>\nint main(void){printf(\"Ok\"); return 0;}\n" > config-test.c
|
||||||
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c -ffunction-sections -fdata-sections -Wl,--gc-sections 2> /dev/null && echo "-ffunction-sections -fdata-sections -Wl,--gc-sections" > config.link || echo "" > config.link
|
$(CC) $(CFLAGS) $(CPPFLAGS) config-test.c -ffunction-sections -fdata-sections -Wl,--gc-sections 2> /dev/null && echo "-ffunction-sections -fdata-sections -Wl,--gc-sections" > config.link || echo "" > config.link
|
||||||
$(RM) config-test.c config-test.exe
|
$(RM) config-test.c config-test.exe
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) *.exe *.s *~ *.o ./a.dat config config.link
|
$(RM) *.exe *.s *~ *.o ./a.dat config config.link config.curl
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
#if HAVE_CURL
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include "m-dict.h"
|
||||||
|
#include "m-tuple.h"
|
||||||
|
#include "m-string.h"
|
||||||
|
#include "m-list.h"
|
||||||
|
#include "m-serial-json.h"
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
|
||||||
|
// Define container types
|
||||||
|
// First a generic map string to string
|
||||||
|
DICT_DEF2(map_str, string_t, string_t)
|
||||||
|
#define M_OPL_map_str_t() DICT_OPLIST(map_str, STRING_OPLIST, STRING_OPLIST)
|
||||||
|
|
||||||
|
// This structure matches the JSON structure returns by the used WEB server
|
||||||
|
// for the GET command.
|
||||||
|
// It can be whatever you want provided it matches what is expected by the WEB server
|
||||||
|
TUPLE_DEF2(web_data,
|
||||||
|
(args, map_str_t),
|
||||||
|
(headers, map_str_t),
|
||||||
|
(origin, string_t),
|
||||||
|
(url, string_t))
|
||||||
|
#define M_OPL_web_data_t() TUPLE_OPLIST(web_data, M_OPL_map_str_t(), M_OPL_map_str_t(), STRING_T, STRING_T)
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||||
|
{
|
||||||
|
(void) size; // Parameter not used
|
||||||
|
char *src = buffer;
|
||||||
|
string_ptr str = userp;
|
||||||
|
for(size_t i = 0; i < nmemb; i++) {
|
||||||
|
string_push_back(str, src[i]);
|
||||||
|
}
|
||||||
|
return nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_data(web_data_t data, const char url[])
|
||||||
|
{
|
||||||
|
m_serial_return_code_t r = M_SERIAL_FAIL;
|
||||||
|
CURLcode res;
|
||||||
|
string_t str;
|
||||||
|
CURL *handle = curl_easy_init();
|
||||||
|
if (handle) {
|
||||||
|
string_init(str);
|
||||||
|
// Perform an http GET request and fill in str with the JSON answer
|
||||||
|
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
|
||||||
|
curl_easy_setopt(handle, CURLOPT_WRITEDATA, str);
|
||||||
|
res = curl_easy_perform(handle);
|
||||||
|
curl_easy_cleanup(handle);
|
||||||
|
if (res == CURLE_OK) {
|
||||||
|
// Parse the string and fill in the object
|
||||||
|
m_serial_str_json_read_t serial;
|
||||||
|
m_serial_str_json_read_init(serial, string_get_cstr(str));
|
||||||
|
r = web_data_in_serial(data, serial);
|
||||||
|
m_serial_str_json_read_clear(serial);
|
||||||
|
}
|
||||||
|
string_clear(str);
|
||||||
|
}
|
||||||
|
return r == M_SERIAL_OK_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
ignore_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||||
|
{
|
||||||
|
(void) buffer; // Parameter not used
|
||||||
|
(void) size; // Parameter not used
|
||||||
|
(void) userp; // Parameter not used
|
||||||
|
return nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool post_data(web_data_t data, const char url[], bool display_answer)
|
||||||
|
{
|
||||||
|
m_serial_return_code_t r = M_SERIAL_FAIL;
|
||||||
|
CURLcode res = 0;
|
||||||
|
string_t str;
|
||||||
|
CURL *handle = curl_easy_init();
|
||||||
|
if (handle) {
|
||||||
|
string_init(str);
|
||||||
|
// Get a JSON string
|
||||||
|
m_serial_str_json_write_t serial;
|
||||||
|
m_serial_str_json_write_init(serial, str);
|
||||||
|
r = web_data_out_serial(serial, data);
|
||||||
|
m_serial_str_json_write_clear(serial);
|
||||||
|
if (r == M_SERIAL_OK_DONE) {
|
||||||
|
// Post JSON string
|
||||||
|
struct curl_slist *headers=NULL;
|
||||||
|
headers = curl_slist_append(headers, "Content-Type: text/json");
|
||||||
|
if (headers != NULL) {
|
||||||
|
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, string_get_cstr(str));
|
||||||
|
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
|
||||||
|
if (display_answer == false) {
|
||||||
|
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ignore_data);
|
||||||
|
curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
|
||||||
|
}
|
||||||
|
res = curl_easy_perform(handle);
|
||||||
|
curl_slist_free_all(headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curl_easy_cleanup(handle);
|
||||||
|
string_clear(str);
|
||||||
|
}
|
||||||
|
return (r == M_SERIAL_OK_DONE) && (res == CURLE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
|
||||||
|
// Remote server URL
|
||||||
|
#define URL_GET "https://httpbin.org/get"
|
||||||
|
#define URL_POST "https://httpbin.org/post"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
CURLcode ret = curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
|
if (ret != CURLE_OK) abort();
|
||||||
|
|
||||||
|
web_data_t data;
|
||||||
|
web_data_init(data);
|
||||||
|
|
||||||
|
// Test http GET
|
||||||
|
bool b = get_data(data, URL_GET);
|
||||||
|
if (b) {
|
||||||
|
// We success receiving the JSON object and fill in the C object web_data with it.
|
||||||
|
// Let's display the object content:
|
||||||
|
printf("SUCCESS. Receive data =\n");
|
||||||
|
web_data_out_str(stdout, data);
|
||||||
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
printf("ERROR: Cannot GET data or get data are not in expected format\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test http POST
|
||||||
|
web_data_emplace_origin(data, "This is the origin");
|
||||||
|
web_data_emplace_url(data, "This is the URL");
|
||||||
|
//web_data_set_origin(data, STRING_CTE("This is the origin"));
|
||||||
|
//web_data_set_url(data, STRING_CTE("This is the URL"));
|
||||||
|
b = post_data(data, URL_POST, false);
|
||||||
|
if (b) {
|
||||||
|
printf("SUCCESS: Post\n");
|
||||||
|
} else {
|
||||||
|
printf("ERROR post\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
web_data_clear(data);
|
||||||
|
|
||||||
|
curl_global_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
int main(void) { return 0; }
|
||||||
|
#endif
|
||||||
Reference in new issue
Block a user