DEV Community

Selivestrov Dmitriy
Selivestrov Dmitriy

Posted on

How to use CURL in Vala

Hi everyone! Nowadays there are a lot of applications written in Vala that make HTTP requests and various libraries that can help with it. At the same time, there is a certain lack of information on how to make requests via curl. This article is aimed to cover the gap.

I've encountered this lack of info while working on the Whaler app. The app calls Docker Engine API methods to manage Docker containers under the hood.

At the start of the project, I faced a question: Which library should I use to make HTTP requests? There was an important requirement - the library had to support UNIX sockets.

There were three options:

  • GLib.Socket
  • libsoup-2.4
  • libcurl

GLib.Socket required implementing a wrapper to work with the HTTP protocol. Libsoup-2.4 didn't support UNIX sockets (they became available starting from the 3.0 version). That’s why I skipped the first two and chose libcurl. It had Vala bindings and supported UNIX sockets.

How to add libcurl to a project

First of all, check if libcurl is installed on your system. If not, make sure to install it.

Let’s have a look at a small demo project.

Folder structure:

project/
    meson.build
    app.vala
    vapi/
        libcurl.vapi
        libcurl.deps
Enter fullscreen mode Exit fullscreen mode

You can download libcurl.vapi and libcurl.deps on List of Vala Bindings.

meson.build:

project('com.github.sdv43.vala-recipes.curl', 'vala', 'c', version: '1.0.0')

vapi_dir = meson.current_source_dir() / 'vapi'
add_project_arguments(['--vapidir', vapi_dir], language: 'vala')

executable(
    meson.project_name(),
    'app.vala',
    dependencies: [
        dependency('glib-2.0'),
        meson.get_compiler('vala').find_library('posix'),
        meson.get_compiler('vala').find_library('libcurl', dirs: vapi_dir),
        meson.get_compiler('c').find_library('libcurl'),
    ],
)
Enter fullscreen mode Exit fullscreen mode

Now we can use CURL in the app.vala:

void main() {
    var curl = new Curl.EasyHandle();

    // set curl options

    var code = curl.perform();
    assert_true(code == Curl.Code.OK);
}
Enter fullscreen mode Exit fullscreen mode

Easy interface vs. Multi interface

CURL provides two different interfaces: Easy and Multi. The first one works synchronously and the second one, if I got it right, can make several requests simultaneously and works in asynchronous manner.

I chose to use the Easy interface because I found an example written in Vala.

The last problem to be solved was the one with blocking the thread when calling curl_perform.

I decided to go with the first solution that came to mind. That is to call curl_perform in a separate thread by using GLib.Task. It prevents the main thread from blocking and allows the app to work correctly. Here is an example:

app.vala:

void main() {
    var curl = new Curl.EasyHandle();

    // set curl options

    var task = new Task (null, null, (source_obj, cl_task) => {
        var curl_code = (Curl.Code)cl_task.propagate_int ();
        assert_true(curl_code == Curl.Code.OK);
    });

    task.set_task_data (curl, null);

    task.run_in_thread ((cl_task, source_obj, curl, cancellable) => {
        unowned var cl_curl = (Curl.EasyHandle)curl;

        var code = cl_curl.perform ();
        cl_task.return_int (code);
    });
}
Enter fullscreen mode Exit fullscreen mode

The final solution used in Whaler is available on Github: HttpClient.vala

Links

Questions & What's next

I believe it is just one of many possible ways to make HTTP requests in Vala. So I would be happy to hear your thoughts:

  • Are there any other HTTP libraries for Vala?
  • Is it possible to create a solution without using GLib.Task? Can the Multi interface help with it?

Oldest comments (0)