Forms and Multipart

HTTP applications spend a lot of time exchanging structured bodies. The @eryx/http module includes helpers for the most common formats on both the client and server sides.

URL-Encoded Forms

Sending

local http = require("@eryx/http")

local response = http.post("https://example.com/login", nil, {
    form = {
        username = "alice",
        password = "secret",
    },
})

This automatically:

Receiving on the Server

Incoming URL-encoded forms are parsed for you:

local server = http.HttpServer.new(function(req, res)
    local form = req.form or {}
    local username = form.username

    res:send(200, "hello " .. tostring(username))
end)

You can also decode a buffered response body manually:

local response = http.get("https://example.com/form-endpoint")
local form = http.decodeFormBody(response)

Query Strings

The same encoding rules are often useful outside of bodies.

local http = require("@eryx/http")

local query = http.parseQuery("tag=a&tag=b&page=2")
print(query.page)

On the server, query parsing is already reflected on req.query.

Multipart Form Data

Sending Multipart Bodies

Use multipart = { ... } when you want to send mixed fields and files.

local response = http.post("https://example.com/upload", nil, {
    multipart = {
        { name = "username", value = "alice" },
        {
            name = "avatar",
            value = imageBytes,
            filename = "avatar.png",
            contentType = "image/png",
        },
    },
})

The multipart body and boundary header are generated automatically.

Manual Multipart Encoding

If you want to build the body yourself, use http.multipartEncode(...):

local body, contentType = http.multipartEncode({
    { name = "file", value = fileData, filename = "report.txt" },
})

Receiving Multipart on the Server

Incoming multipart requests are parsed into req.multipart:

local server = http.HttpServer.new(function(req, res)
    for _, field in req.multipart or {} do
        print(field.name, field.filename, field.contentType)
    end

    res:send(200, "ok")
end)

Decoding Multipart Responses

If a server returns a multipart response, you can decode it explicitly:

local response = http.get("https://example.com/bundle")
local parts = http.decodeMultipartBody(response)

You can also decode raw multipart bodies with http.multipartDecode(body, boundary).

JSON

JSON is simple enough that it is easy to forget it is also part of the "structured body" story.

Sending JSON

local response = http.post("https://example.com/api", nil, {
    json = {
        ok = true,
        count = 3,
    },
})

Receiving JSON

local response = http.get("https://example.com/api")
local data = http.decodeJsonBody(response)

On the server, buffered requests can read JSON directly from req.body, and streamed request-body mode can decode it on demand:

local server = http.HttpServer.new(function(req, res)
    local data = req:readJson()
    res:send(200, tostring(data.ok))
end, {
    streamRequestBodies = true,
})

Lower-Level Helpers

The module also exposes lower-level helpers directly:

These are useful when you need the encoding tools without making an HTTP request at the same time.