Floki: Requests-like HTTP Client powered by libcurl

Hey Everyone! I’ve just released a new version of Floki which is a straightforward HTTP client with an API similar to the Python requests package. It’s powered by libcurl, so if you want to use the bindings I wrote for this directly, you can find them at my mojo-curl repository.

Maybe feature parity will be achieved one day, but we’ll see where this goes.

Unfortunately, due to libcurl’s client interface making use of C variadics, this package requires the use of a small shim c library to be able to call curl_easy_setopt. So, you can’t just link libcurl and be good to go. You’ll need to make use of the curl_wrapper subpackage through the instructions in the readme!

The underlying libcurl bindings have been updated to support Mojo 1.0.0b1! Floki will follow soon.

I’ve converted the simple examples provided in the curl documentation into running Mojo examples! Well, most of them at least. Some examples rely on local configuration, like serving something over a unix socket or a web server running on localhost.

The examples can be found here: mojo-curl/examples/curl/api at main · thatstoasty/mojo-curl · GitHub

Aside from that, I went through and cleaned up a bunch of half baked and redundant code. Eventually, I’d like to break the c submodule into it’s own package once C FFI is stable so that way there’s a raw bindings package and an opinionated user friendly interface as it’s own package.

Floki has been updated to support Mojo 1.0.0b1! Please check out v0.3.2: Release v0.3.2 · thatstoasty/floki · GitHub

Aside from some bug fixes, the main feature that I’ve added is adding struct deserialization/serialization for JSON request data and response bodies. To say I implemented it might be a stretch, since it heavily leans on emberjson’s struct serialization/deserialization :slight_smile:.

Response Body Deserialization

@fieldwise_init
struct Todo(Movable, Defaultable, ImplicitlyDestructible, Equatable, Writable):
    var userId: Int
    var id: Int
    var title: String
    var completed: Bool

    def __init__(out self):
        self.userId = 0
        self.id = 0
        self.title = ""
        self.completed = False
    

def main() raises -> None:
    var response = Session().get("https://jsonplaceholder.typicode.com/todos/1")
    assert_equal(response.status, Status.OK)

    var todo = response.body.as_json[Todo]()
    assert_equal(todo.userId, 1)
    assert_equal(todo.id, 1)
    assert_equal(todo.title, "delectus aut autem")
    assert_equal(todo.completed, False)

Request Data Serialization

from floki.session import Session

@fieldwise_init
struct Point:
    var x: Int
    var y: Int

def main() raises:
    var session = Session()
    var r = session.post("https://httpbin.org/post", data=Point(0, 1))