C#
cURL
HTTP Requests
Programming
API Integration

Making a cURL call in C

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In C, making a “cURL call” usually means using the libcurl library, not launching the curl shell command from your program. libcurl gives you a C API for HTTP and other protocols, and the normal workflow is to initialize a handle, set request options, perform the transfer, inspect the result, and clean up.

A Minimal GET Request

The easiest starting point is the libcurl easy API.

c
1#include <curl/curl.h>
2#include <stdio.h>
3
4int main(void) {
5    CURL *curl;
6    CURLcode res;
7
8    curl_global_init(CURL_GLOBAL_DEFAULT);
9    curl = curl_easy_init();
10
11    if (curl) {
12        curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
13        res = curl_easy_perform(curl);
14
15        if (res != CURLE_OK) {
16            fprintf(stderr, "Request failed: %s\n", curl_easy_strerror(res));
17        }
18
19        curl_easy_cleanup(curl);
20    }
21
22    curl_global_cleanup();
23    return 0;
24}

By default, libcurl writes the response body to standard output. That is convenient for a minimal example, but most real programs capture the response in memory.

Capturing the Response Body

To keep the response in memory, provide a write callback.

c
1#include <curl/curl.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5
6struct Memory {
7    char *data;
8    size_t size;
9};
10
11static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
12    size_t total = size * nmemb;
13    struct Memory *mem = (struct Memory *)userp;
14
15    char *ptr = realloc(mem->data, mem->size + total + 1);
16    if (ptr == NULL) {
17        return 0;
18    }
19
20    mem->data = ptr;
21    memcpy(&(mem->data[mem->size]), contents, total);
22    mem->size += total;
23    mem->data[mem->size] = '\0';
24
25    return total;
26}

Then connect it to the request:

c
1struct Memory chunk = {0};
2
3curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
4curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);

Now you can inspect chunk.data after the request completes.

Sending a POST Request

POST is just more options on the same handle:

c
curl_easy_setopt(curl, CURLOPT_URL, "https://httpbin.org/post");
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=alice&role=admin");

For JSON APIs, add a content-type header:

c
1struct curl_slist *headers = NULL;
2headers = curl_slist_append(headers, "Content-Type: application/json");
3
4curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
5curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"name\":\"alice\"}");

Remember to free the header list later with curl_slist_free_all(headers);.

Checking HTTP Status Codes

curl_easy_perform tells you whether the transfer succeeded at the libcurl level, but an HTTP 500 or 404 is still an application-level failure you need to inspect explicitly.

c
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
printf("HTTP status: %ld\n", status);

A robust program checks both:

  • 'CURLcode from curl_easy_perform'
  • HTTP status from CURLINFO_RESPONSE_CODE

Building and Linking

Compile with libcurl linked:

bash
gcc main.c -lcurl -o app

If compilation fails on headers or symbols, make sure the development package for libcurl is installed, not just the runtime library. Also remember that HTTPS requests depend on certificate support in the underlying libcurl build, so environment setup matters as much as the C code.

Request Options Grow Quickly

Even simple examples tend to add options over time:

  • timeouts
  • custom headers
  • redirects
  • authentication
  • TLS settings

That is one reason it is worth learning the handle-and-option model early instead of treating libcurl as a black box.

Common Pitfalls

One common mistake is calling the external curl command from C instead of using libcurl directly. That is harder to control and less portable.

Another issue is forgetting the write callback and then wondering why the response was not captured in memory.

A third pitfall is checking only transport success and ignoring the HTTP status code.

Summary

  • In C, the usual way to make a cURL call is with libcurl.
  • Use curl_easy_init, curl_easy_setopt, curl_easy_perform, and cleanup functions in that order.
  • Add a write callback when you need the response body in memory.
  • Inspect both libcurl errors and HTTP status codes.
  • Link with -lcurl and free any allocated header lists or buffers.

Course illustration
Course illustration

All Rights Reserved.