Fetch.jl: a simple HTTP request function
inspired by fetch
from JS
You can use Fetch.jl to request something from the web:
"followers"
1668
"created_at"
"2011-04-21T06:33:51Z"
"repos_url"
"https://api.github.com/users/JuliaLang/repos"
"login"
"JuliaLang"
"gists_url"
"https://api.github.com/users/JuliaLang/gists{/gist_id}"
"public_repos"
59
"following"
0
"site_admin"
false
"name"
"JuliaLang"
"location"
nothing
"blog"
"https://julialang.org"
"subscriptions_url"
"https://api.github.com/users/JuliaLang/subscriptions"
"id"
743164
"html_url"
"https://github.com/JuliaLang"
"node_id"
"MDEyOk9yZ2FuaXphdGlvbjc0MzE2NA=="
"updated_at"
"2025-06-09T21:01:31Z"
"events_url"
"https://api.github.com/users/JuliaLang/events{/privacy}"
"followers_url"
"https://api.github.com/users/JuliaLang/followers"
"organizations_url"
"https://api.github.com/users/JuliaLang/orgs"
"starred_url"
"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}"
"avatar_url"
"https://avatars.githubusercontent.com/u/743164?v=4"
"email"
nothing
"twitter_username"
"JuliaLanguage"
"user_view_type"
"public"
"company"
nothing
"url"
"https://api.github.com/users/JuliaLang"
"hireable"
nothing
"bio"
"The Julia Programming Language"
"received_events_url"
"https://api.github.com/users/JuliaLang/received_events"
"public_gists"
0
Response
The fetch
function returns a special object, a FetchResponse
, containing the response status and headers.
"https://api.github.com/users/JuliaLang"
0x7b
0x0a
0x20
0x20
0x22
0x6c
0x6f
0x67
0x69
0x0a
false
200
"HTTP/2 200"
"date"
"Mon, 16 Jun 2025 12:26:05 GMT"
"content-type"
"application/json; charset=utf-8"
"cache-control"
"public, max-age=60, s-maxage=60"
"vary"
"Accept,Accept-Encoding, Accept, X-Requested-With"
"etag"
"W/\"992cafb164aa4e7209a3de6f752cbd3c9eaf4d2784ec3f1613221fab73738d1a\""
"last-modified"
"Mon, 09 Jun 2025 21:01:31 GMT"
"x-github-media-type"
"github.v3; format=json"
"x-github-api-version-selected"
"2022-11-28"
"access-control-expose-headers"
"ETag, Link, Location, Retry-After, " ⋯ 214 bytes ⋯ "ub-Request-Id, Deprecation, Sunset"
"x-github-request-id"
"0400:1FF7BC:CEB046C:1A09EE3D:68500D5D"
true
false
200
"date"
"Mon, 16 Jun 2025 12:26:05 GMT"
"content-type"
"application/json; charset=utf-8"
"cache-control"
"public, max-age=60, s-maxage=60"
"vary"
"Accept,Accept-Encoding, Accept, X-Requested-With"
"etag"
"W/\"992cafb164aa4e7209a3de6f752cbd3c9eaf4d2784ec3f1613221fab73738d1a\""
"last-modified"
"Mon, 09 Jun 2025 21:01:31 GMT"
"x-github-media-type"
"github.v3; format=json"
"x-github-api-version-selected"
"2022-11-28"
"access-control-expose-headers"
"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset"
"access-control-allow-origin"
"*"
"strict-transport-security"
"max-age=31536000; includeSubdomains; preload"
"x-frame-options"
"deny"
"x-content-type-options"
"nosniff"
"x-xss-protection"
"0"
"referrer-policy"
"origin-when-cross-origin, strict-origin-when-cross-origin"
"content-security-policy"
"default-src 'none'"
"server"
"github.com"
"accept-ranges"
"bytes"
"x-ratelimit-limit"
"60"
"x-ratelimit-remaining"
"58"
"x-ratelimit-reset"
"1750080365"
"x-ratelimit-resource"
"core"
"x-ratelimit-used"
"2"
"content-length"
"1417"
"x-github-request-id"
"0400:1FF7BC:CEB046C:1A09EE3D:68500D5D"
Reading data
You can use .json()
, .text()
or .arrayBuffer()
to read the response data. Let's read the response as JSON:
"followers"
1668
"created_at"
"2011-04-21T06:33:51Z"
"repos_url"
"https://api.github.com/users/JuliaLang/repos"
"login"
"JuliaLang"
"gists_url"
"https://api.github.com/users/JuliaLang/gists{/gist_id}"
"public_repos"
59
"following"
0
"site_admin"
false
"name"
"JuliaLang"
"location"
nothing
"blog"
"https://julialang.org"
"subscriptions_url"
"https://api.github.com/users/JuliaLang/subscriptions"
"id"
743164
"html_url"
"https://github.com/JuliaLang"
"node_id"
"MDEyOk9yZ2FuaXphdGlvbjc0MzE2NA=="
"updated_at"
"2025-06-09T21:01:31Z"
"events_url"
"https://api.github.com/users/JuliaLang/events{/privacy}"
"followers_url"
"https://api.github.com/users/JuliaLang/followers"
"organizations_url"
"https://api.github.com/users/JuliaLang/orgs"
"starred_url"
"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}"
"avatar_url"
"https://avatars.githubusercontent.com/u/743164?v=4"
"email"
nothing
"twitter_username"
"JuliaLanguage"
"user_view_type"
"public"
"company"
nothing
"url"
"https://api.github.com/users/JuliaLang"
"hireable"
nothing
"bio"
"The Julia Programming Language"
"received_events_url"
"https://api.github.com/users/JuliaLang/received_events"
"public_gists"
0
Each response can only be read once. Reading it a second time will raise an error:
AssertionError: Body stream has already been read.
Here is what happened, the most recent locations are first:
- (::Main.workspace#5.var"#4#10"{Main.workspace#5.var"#5#11"{Main.workspace#5.FetchResponse}, Main.workspace#5.FetchResponse})
() from Other cell: line 5function()
ref = getfield(r, :bodyUsed_ref)
@assert !ref[] "Body stream has already been read."
ref[] = true
f()
- Show more...
There are three ways to read a response:
"followers"
1668
"created_at"
"2011-04-21T06:33:51Z"
"repos_url"
"https://api.github.com/users/JuliaLang/repos"
"login"
"JuliaLang"
"gists_url"
"https://api.github.com/users/JuliaLang/gists{/gist_id}"
"public_repos"
59
"following"
0
"site_admin"
false
"name"
"JuliaLang"
"location"
nothing
"blog"
"https://julialang.org"
"subscriptions_url"
"https://api.github.com/users/JuliaLang/subscriptions"
"id"
743164
"html_url"
"https://github.com/JuliaLang"
"node_id"
"MDEyOk9yZ2FuaXphdGlvbjc0MzE2NA=="
"updated_at"
"2025-06-09T21:01:31Z"
"events_url"
"https://api.github.com/users/JuliaLang/events{/privacy}"
"followers_url"
"https://api.github.com/users/JuliaLang/followers"
"organizations_url"
"https://api.github.com/users/JuliaLang/orgs"
"starred_url"
"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}"
"avatar_url"
"https://avatars.githubusercontent.com/u/743164?v=4"
"email"
nothing
"twitter_username"
"JuliaLanguage"
"user_view_type"
"public"
"company"
nothing
"url"
"https://api.github.com/users/JuliaLang"
"hireable"
nothing
"bio"
"The Julia Programming Language"
"received_events_url"
"https://api.github.com/users/JuliaLang/received_events"
"public_gists"
0
"{\n \"login\": \"JuliaLang\",\n \"id\": 743164,\n \"node_id\": \"MDEyOk9yZ2FuaXphdGlvbjc0MzE2NA==\",\n \"avatar_url\": \"https://avatars.githubusercontent.com/u/743164?v=4\",\n \"gravatar_id\": \"\",\n \"url\": \"https://api.github.com/users/JuliaLang\",\n \"html_url\": \"https://github.com/JuliaLang\",\n \"followers_url\": \"" ⋯ 820 bytes ⋯ "ocation\": null,\n \"email\": null,\n \"hireable\": null,\n \"bio\": \"The Julia Programming Language\",\n \"twitter_username\": \"JuliaLanguage\",\n \"public_repos\": 59,\n \"public_gists\": 0,\n \"followers\": 1668,\n \"following\": 0,\n \"created_at\": \"2011-04-21T06:33:51Z\",\n \"updated_at\": \"2025-06-09T21:01:31Z\"\n}\n"
0x7b
0x0a
0x20
0x20
0x22
0x6c
0x6f
0x67
0x69
0x6e
0x22
0x3a
0x20
0x22
0x4a
0x75
0x6c
0x69
0x61
0x4c
0x30
0x31
0x3a
0x33
0x31
0x5a
0x22
0x0a
0x7d
0x0a
Request
Besides getting data from a URL, you can also make requests with a body
. Here is an example of a POST
request:
"headers"
"Content-Length"
"6"
"Host"
"httpbin.org"
"Accept"
"*/*"
"User-Agent"
"curl/7.73.0 julia/1.7"
"X-Amzn-Trace-Id"
"Root=1-68500d60-625d66f446324e3e5b8fab95"
"json"
nothing
"files"
"args"
"data"
"hello!"
"url"
"https://httpbin.org/post"
"form"
"origin"
"52.232.254.232"
Implementation
fetch (generic function with 1 method)
Reading response data
handle_getproperty (generic function with 1 method)
body_data (generic function with 1 method)
body_data (generic function with 2 methods)
Examples
"https://httpbin.org/uuid"
"https://registry.npmjs.org/react"
"https"
"https://httpbin.org/uuid"
200
"HTTP/2 200"
"date"
"Mon, 16 Jun 2025 12:26:03 GMT"
"content-type"
"application/json"
"content-length"
"53"
"server"
"gunicorn/19.9.0"
"access-control-allow-origin"
"*"
"access-control-allow-credentials"
"true"
Multipart form data
FormFile
read_form_data (generic function with 1 method)
HTTP.Multipart(data=::Base.GenericIOBuffer{SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}}, contenttype="text/plain", contenttransferencoding=""))
HTTP.Multipart(data=::Base.GenericIOBuffer{SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}}, contenttype="text/plain", contenttransferencoding=""))
HTTP.Multipart(filename="invoice.pdf", data=::Base.GenericIOBuffer{SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}}, contenttype="text/plain", contenttransferencoding=""))
HTTP.Multipart(filename="invoice.pdf", data=::Base.GenericIOBuffer{SubArray{UInt8, 1, Vector{UInt8}, Tuple{UnitRange{Int64}}, true}}, contenttype="text/plain", contenttransferencoding=""))
syntax: incomplete: premature end of input
0x90
0xd7
0x3f
0x1e
0x13
0xb9
0x26
0x1c
0xef
0xd3
0xef
0x62
0xb2
0x3e
0x0d
0xa8
0xb5
0x90
0x92
0x48
0xc1
0x38
0xc0
0xab
0x30
0x29
0x7c
0xab
0xed
0xf5
"\r\n--WebKitFormBoundary\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\ninvoice_text\r\n--WebKitFormBoundary\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\ninvoice_title\r\n--WebKitFormBoundary\r\nContent-Disposition: form-data; name=\"invoice\"; filename=\"invoice.pdf\"\r\nContent-Type: application/pdf\r\n\r\n\x90\xd7?\x1e\x13\xb9&\x1c\xef\xd3\xefb\xb2>\r\xa8\xb5\x90\x92Hc\xa4{\xcazA\u05cee\xa2\x87\x94SH\xaa8\x90\xb6\x19\xc4\xc18\xc0\xab0)|\xab\xed\xf5\r\n--WebKitFormBoundary--\r\n"
- parse_multipart_form(req::HTTP.Messages.Request) in HTTP.MultiPartParsing at /home/runner/.julia/packages/HTTP/aTjcj/src/parsemultipart.jl:235
Experiments
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
101
f1 (generic function with 1 method)
f2 (generic function with 1 method)
"uuid"
"cb358738-0084-4e4e-86fb-5151c335e147"
0.291953 seconds (346 allocations: 19.594 KiB, 1.33% compilation time)
MethodError: no method matching request(::Task; method=nothing, headers=Pair{String, String}[], input=nothing, output=IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1))
Closest candidates are:
request(::AbstractString; input, output, method, headers, timeout, progress, verbose, debug, throw, downloader) at /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Downloads/src/Downloads.jl:293
Here is what happened, the most recent locations are first:
- fetch
(url::Task; method::Nothing, headers::Vector{Pair{String, String}}, body::Nothing) from Other cell: line 18output = IOBuffer()
result = request(url;
method,
headers,
- Show more...
"_id"
"react"
"time"
"0.0.0-experimental-a7d1240c-20240731"
"2024-07-31T16:20:17.865Z"
"0.0.0-76f85b3e5"
"2021-06-02T15:23:18.973Z"
"19.1.0-canary-9b62ee71-20250122"
"2025-01-22T16:18:17.458Z"
"0.0.0-experimental-efb381bbf-20230505"
"2023-05-05T19:16:55.171Z"
"0.0.0-ee4326357"
"2021-03-03T16:12:25.618Z"
"0.0.0-experimental-98b8359f6-20240223"
"2024-02-23T16:18:17.946Z"
"18.3.0-next-7028ce745-20220907"
"2022-09-08T02:43:51.168Z"
"15.0.0-rc.2"
"2016-03-16T22:19:35.759Z"
"16.7.0-alpha.0"
"2018-10-25T16:13:37.324Z"
"16.10.0"
"2019-09-27T20:28:13.525Z"
"users"
"oka-hide"
true
"tuiteraz"
true
"goblindegook"
true
"lirantal_bot"
true
"buzzpsych"
true
"postcrafter"
true
"federico-garcia"
true
"kogai"
true
"alexparish"
true
"giioaj"
true
"homepage"
"https://react.dev/"
"keywords"
"react"
"repository"
"url"
"git+https://github.com/facebook/react.git"
"type"
"git"
"directory"
"packages/react"
"readme"
""
"name"
"react"
"description"
"React is a JavaScript library for building user interfaces."
"bugs"
"url"
"https://github.com/facebook/react/issues"
"_rev"
"4556-38606e4086d9df83b101248af9d3d7b0"
"readmeFilename"
""
"versions"
"0.0.0-experimental-a7d1240c-20240731"
"_id"
"react@0.0.0-experimental-a7d1240c-20240731"
"homepage"
"https://react.dev/"
"keywords"
"exports"
"dist"
"repository"
"0.0.0-76f85b3e5"
"_id"
"react@0.0.0-76f85b3e5"
"homepage"
"https://reactjs.org/"
"keywords"
"exports"
"dist"
"repository"
"19.1.0-canary-9b62ee71-20250122"
"_id"
"react@19.1.0-canary-9b62ee71-20250122"
"homepage"
"https://react.dev/"
"keywords"
"exports"
"dist"
"repository"
"0.0.0-experimental-efb381bbf-20230505"
"_id"
"react@0.0.0-experimental-efb381bbf-20230505"
"homepage"
"https://reactjs.org/"
"keywords"
"exports"
"dist"
"repository"
"0.0.0-ee4326357"
"_id"
"react@0.0.0-ee4326357"
"homepage"
"https://reactjs.org/"
"keywords"
"exports"
"dist"
"repository"
"0.0.0-experimental-98b8359f6-20240223"
"_id"
"react@0.0.0-experimental-98b8359f6-20240223"
"homepage"
"https://reactjs.org/"
"keywords"
"exports"
"dist"
"repository"
"18.3.0-next-7028ce745-20220907"
"_id"
"react@18.3.0-next-7028ce745-20220907"
"homepage"
"https://reactjs.org/"
"keywords"
"exports"
"dist"
"repository"
"15.0.0-rc.2"
"_id"
"react@15.0.0-rc.2"
"homepage"
"https://facebook.github.io/react/"
"keywords"
"dist"
"repository"
"dependencies"
"16.7.0-alpha.0"
"_id"
"react@16.7.0-alpha.0"
"homepage"
"https://reactjs.org/"
"keywords"
"dist"
"repository"
"dependencies"
"16.10.0"
"_id"
"react@16.10.0"
"homepage"
"https://reactjs.org/"
"keywords"
"dist"
"repository"
"dependencies"
"maintainers"
"name"
"fb"
"email"
"opensource+npm@fb.com"
"name"
"react-bot"
"email"
"react-core@meta.com"
"dist-tags"
"rc"
"19.0.0-rc.1"
"latest"
"19.1.0"
"next"
"19.2.0-canary-12bc60f5-20250613"
"canary"
"19.2.0-canary-12bc60f5-20250613"
"experimental"
"0.0.0-experimental-12bc60f5-20250613"
"beta"
"19.0.0-beta-26f2496093-20240514"
"license"
"MIT"
0.323751 seconds (816.37 k allocations: 63.980 MiB, 9.85% gc time, 17.04% compilation time)
MethodError: no method matching request(::Task; method=nothing, headers=Pair{String, String}[], input=nothing, output=IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1))
Closest candidates are:
request(::AbstractString; input, output, method, headers, timeout, progress, verbose, debug, throw, downloader) at /opt/hostedtoolcache/julia/1.7.3/x64/share/julia/stdlib/v1.7/Downloads/src/Downloads.jl:293
Here is what happened, the most recent locations are first:
- fetch
(url::Task; method::Nothing, headers::Vector{Pair{String, String}}, body::Nothing) from Other cell: line 18output = IOBuffer()
result = request(url;
method,
headers,
- Show more...
"<html>\r\n<head><title>502 Bad Gateway</title></head>\r\n<body>\r\n<center><h1>502 Bad Gateway</h1></center>\r\n</body>\r\n</html>\r\n"
JSON.parse(io::IO)
benchmark
Some benchmarks with https://github.com/JuliaIO/JSON.jl/issues/339 as conclusion.
j1 (generic function with 1 method)
j2 (generic function with 1 method)
"{\"_id\":\"react\",\"_rev\":\"4556-38606e4086d9df83b101248af9d3d7b0\",\"name\":\"react\",\"dist-tags\":{\"beta\":\"19.0.0-beta-26f2496093-20240514\",\"rc\":\"19.0.0-rc.1\",\"latest\":\"19.1.0\",\"experimental\":\"0.0.0-experimental-12bc60f5-20250613\",\"next\":\"19.2.0-canary-12bc60f5-20250613\",\"canary\":\"19.2.0-canary-12bc60f5-2" ⋯ 5779370 bytes ⋯ "ue,\"javascriptismagic\":true,\"sebastian-schmidt\":true,\"arulsakthiprakasam\":true,\"ashtonsoftwarelabs\":true,\"avanthikameenakshi\":true,\"emesfun_blueraster\":true,\"vision_tecnologica\":true,\"azulejosmetrosubway\":true,\"robertocarvalho7458\":true,\"dylanthomasfernandez\":true,\"nguyenvanhoang26041994\":true}}"
BenchmarkTools.Trial: 87 samples with 1 evaluation.
Range (min … max): 41.291 ms … 106.524 ms ┊ GC (min … max): 0.00% … 48.97%
Time (median): 53.670 ms ┊ GC (median): 20.11%
Time (mean ± σ): 57.682 ms ± 13.545 ms ┊ GC (mean ± σ): 19.33% ± 14.43%
█ ▂ █ ▄▆▂ ▂
██▆▁▆██▄██▄▁▁▄███▄▄▁▁▄▄▆█▆▄▆▄▁▁▁▁█▄▆▄▁▄▁▁▁▁▆▄█▁▄▁▄▄▄▁▄▄▁▁▁▁▄ ▁
41.3 ms Histogram: frequency by time 88.7 ms <
Memory estimate: 57.59 MiB, allocs estimate: 762476.
BenchmarkTools.Trial: 46 samples with 1 evaluation.
Range (min … max): 82.137 ms … 249.694 ms ┊ GC (min … max): 0.00% … 66.38%
Time (median): 102.759 ms ┊ GC (median): 17.69%
Time (mean ± σ): 111.442 ms ± 27.698 ms ┊ GC (mean ± σ): 23.09% ± 13.85%
▂ ▂ ▄ █
█▁▃▇█▃▁█▁▁▁▁▅▁▃▁█▆▁▁▃▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃ ▁
82.1 ms Histogram: frequency by time 250 ms <
Memory estimate: 103.57 MiB, allocs estimate: 1282427.