JuliaWeb/HTTP.jl

HTTP for Julia

688

stars

2,355

commits

Julia

primary language

Sep 10, 2026

updated

juliaweb.github.io/HTTP.jl/stable/Browse cluster: Julia language ecosystem

README

HTTP

HTTP client and server functionality for Julia

DocumentationBuild Status

Installation

The package can be installed with Julia's package manager, either by using the Pkg REPL mode (press ] to enter):

pkg> add HTTP

or by using Pkg functions

julia> using Pkg; Pkg.add("HTTP")

Overview

HTTP.jl provides HTTP client/server support, HTTP/2, WebSockets, SSE, cookies, multipart forms, retries, and proxy-aware transports for Julia.

Current package compat targets Julia 1.10 and later.

HTTP.jl 2.0 is a breaking release. See the migration guide for the main 1.x to 2.0 changes around response fields, constructors, request context, client pooling, retries, timeouts, servers, WebSockets, and SSE.

Contributing and Questions

Contributions are very welcome, as are feature requests and suggestions. Please open an issue if you encounter any problems or would just like to ask a question.

Client Examples

High-level request helpers return a Response whose body is a Vector{UInt8} by default.

using HTTP

r = HTTP.get("http://httpbin.org/ip")
println(r.status)
println(String(r.body))

⚠️ String(r.body) aliases the underlying byte buffer rather than copying it, so r.body is left empty afterwards. Use String(copy(r.body)) (or response_stream = IOBuffer()) when you need to keep the bytes around.

To send JSON, serialize the payload with JSON.jl and set the Content-Type header explicitly — HTTP.jl ships without a JSON dependency:

using HTTP, JSON

payload = Dict("name" => "alice", "age" => 30)
r = HTTP.post(
    "http://httpbin.org/post";
    headers = ["Content-Type" => "application/json"],
    body = JSON.json(payload),
)
returned = JSON.parse(String(r.body))

For safe, idempotent requests with content, HTTP.jl supports the RFC 10008 QUERY method through HTTP.query:

r = HTTP.query(
    "https://api.example.com/search";
    headers = ["Content-Type" => "application/json"],
    body = JSON.json(Dict("select" => ["name", "email"])),
)

Stream directly into an IO sink with response_stream, or use HTTP.open when you want pull-based control over the response stream. The do-block form of HTTP.open returns the final HTTP.Response, not the value returned by the do block.

using HTTP

open("response.bin", "w") do io
    HTTP.get("https://example.com/data.bin"; response_stream = io)
end

text = ""
response = HTTP.open(:GET, "https://example.com/stream") do stream
    text = String(read(stream))
end
@assert response isa HTTP.Response
println(text)

Handle Server-Sent Events by passing an sse_callback function to HTTP.request:

using HTTP

events = HTTP.SSEEvent[]
HTTP.request("GET", "http://127.0.0.1:8080/events"; sse_callback = event -> push!(events, event))

Each callback receives an HTTP.SSEEvent with the parsed data, event, id, retry, and fields from the stream.

Server Examples

Use HTTP.serve! for request/response handlers:

HTTP.jl schedules server tasks on Julia's :interactive thread pool so they can remain responsive when the default pool is busy. Start production servers with at least one interactive thread, for example julia --threads=4,1 server.jl. Without an interactive thread, Julia falls back to the default pool and non-yielding compute tasks can delay HTTP work, including health checks. See the server guide for configuration and handler guidance.

using HTTP

server = HTTP.serve!("127.0.0.1", 8081) do request
    payload = "Hello from HTTP.jl"
    return HTTP.Response(
        200;
        headers = ["Content-Type" => "text/plain"],
        body = payload,
    )
end

resp = HTTP.get("http://127.0.0.1:8081"; proxy = HTTP.ProxyConfig())
println(resp.status)
println(String(resp.body))

HTTP.forceclose(server)

Use HTTP.listen! or HTTP.streamhandler when you need lower-level stream ownership for incremental reads, writes, or trailers.

WebSocket Examples

using HTTP

server = HTTP.WebSockets.listen!("127.0.0.1", 8081) do ws
    for msg in ws
        HTTP.WebSockets.send(ws, msg)
    end
end

HTTP.WebSockets.open("ws://127.0.0.1:8081"; proxy = HTTP.ProxyConfig()) do ws
    HTTP.WebSockets.send(ws, "Hello")
    println(HTTP.WebSockets.receive(ws))
end

HTTP.WebSockets.forceclose(server)

Contributors

(top 30 of 167)

quinnj

728 commits

samoconnor

426 commits

malmaud

160 commits

dirk

119 commits

JuliaWeb/HTTP.jl

HTTP for Julia

688

stars

2,355

commits

Julia

primary language

Sep 10, 2026

updated

juliaweb.github.io/HTTP.jl/stable/Browse cluster: Julia language ecosystem

README

HTTP

HTTP client and server functionality for Julia

DocumentationBuild Status

Installation

The package can be installed with Julia's package manager, either by using the Pkg REPL mode (press ] to enter):

pkg> add HTTP

or by using Pkg functions

julia> using Pkg; Pkg.add("HTTP")

Overview

HTTP.jl provides HTTP client/server support, HTTP/2, WebSockets, SSE, cookies, multipart forms, retries, and proxy-aware transports for Julia.

Current package compat targets Julia 1.10 and later.

HTTP.jl 2.0 is a breaking release. See the migration guide for the main 1.x to 2.0 changes around response fields, constructors, request context, client pooling, retries, timeouts, servers, WebSockets, and SSE.

Contributing and Questions

Contributions are very welcome, as are feature requests and suggestions. Please open an issue if you encounter any problems or would just like to ask a question.

Client Examples

High-level request helpers return a Response whose body is a Vector{UInt8} by default.

using HTTP

r = HTTP.get("http://httpbin.org/ip")
println(r.status)
println(String(r.body))

⚠️ String(r.body) aliases the underlying byte buffer rather than copying it, so r.body is left empty afterwards. Use String(copy(r.body)) (or response_stream = IOBuffer()) when you need to keep the bytes around.

To send JSON, serialize the payload with JSON.jl and set the Content-Type header explicitly — HTTP.jl ships without a JSON dependency:

using HTTP, JSON

payload = Dict("name" => "alice", "age" => 30)
r = HTTP.post(
    "http://httpbin.org/post";
    headers = ["Content-Type" => "application/json"],
    body = JSON.json(payload),
)
returned = JSON.parse(String(r.body))

For safe, idempotent requests with content, HTTP.jl supports the RFC 10008 QUERY method through HTTP.query:

r = HTTP.query(
    "https://api.example.com/search";
    headers = ["Content-Type" => "application/json"],
    body = JSON.json(Dict("select" => ["name", "email"])),
)

Stream directly into an IO sink with response_stream, or use HTTP.open when you want pull-based control over the response stream. The do-block form of HTTP.open returns the final HTTP.Response, not the value returned by the do block.

using HTTP

open("response.bin", "w") do io
    HTTP.get("https://example.com/data.bin"; response_stream = io)
end

text = ""
response = HTTP.open(:GET, "https://example.com/stream") do stream
    text = String(read(stream))
end
@assert response isa HTTP.Response
println(text)

Handle Server-Sent Events by passing an sse_callback function to HTTP.request:

using HTTP

events = HTTP.SSEEvent[]
HTTP.request("GET", "http://127.0.0.1:8080/events"; sse_callback = event -> push!(events, event))

Each callback receives an HTTP.SSEEvent with the parsed data, event, id, retry, and fields from the stream.

Server Examples

Use HTTP.serve! for request/response handlers:

HTTP.jl schedules server tasks on Julia's :interactive thread pool so they can remain responsive when the default pool is busy. Start production servers with at least one interactive thread, for example julia --threads=4,1 server.jl. Without an interactive thread, Julia falls back to the default pool and non-yielding compute tasks can delay HTTP work, including health checks. See the server guide for configuration and handler guidance.

using HTTP

server = HTTP.serve!("127.0.0.1", 8081) do request
    payload = "Hello from HTTP.jl"
    return HTTP.Response(
        200;
        headers = ["Content-Type" => "text/plain"],
        body = payload,
    )
end

resp = HTTP.get("http://127.0.0.1:8081"; proxy = HTTP.ProxyConfig())
println(resp.status)
println(String(resp.body))

HTTP.forceclose(server)

Use HTTP.listen! or HTTP.streamhandler when you need lower-level stream ownership for incremental reads, writes, or trailers.

WebSocket Examples

using HTTP

server = HTTP.WebSockets.listen!("127.0.0.1", 8081) do ws
    for msg in ws
        HTTP.WebSockets.send(ws, msg)
    end
end

HTTP.WebSockets.open("ws://127.0.0.1:8081"; proxy = HTTP.ProxyConfig()) do ws
    HTTP.WebSockets.send(ws, "Hello")
    println(HTTP.WebSockets.receive(ws))
end

HTTP.WebSockets.forceclose(server)

Contributors

(top 30 of 167)

quinnj

728 commits

samoconnor

426 commits

malmaud

160 commits

dirk

119 commits

Languages

Julia

99.7%