# \[pre-ANN\] RestClient.jl

**URL:** <https://discourse.julialang.org/t/pre-ann-restclient-jl/123828>\
**Category:** Package Announcements\
**Tags:** package\
**Created:** [December 14, 2024, 4:21am UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828 "2024-12-14T04:21:10Z")\
**Posts on this page:** 11\
**Page:** 2

<div class="post-metadata">

**Author:** ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)\
**Post date:** [April 26, 2025, 12:09pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/21 "2025-04-26T12:09:56Z")

</div>

The usual [guideline](https://pkgdocs.julialang.org/v1/creating-packages/#Package-naming-rules) for pluralized names (“Packages that provide most of their functionality in association with a new type”) doesn’t apply here, and I don’t think “RestClients” adds any clarity regarding the functionality of the package - if anything, it could mislead users into thinking it’s an instance of this guideline (that it works by creating a `RestClient` type).

I slightly prefer `RestClientScaffold`, but I can see the argument for it being too long. Any name is ultimately going to involve some tradeoffs and compromises, and RestClient.jl seems a perfectly fine choice.

---

<div class="post-metadata">

**Author:** ![Stephen](https://avatars.discourse-cdn.com/v4/letter/s/96bed5/32.png) [@Stephen](https://discourse.julialang.org/u/Stephen)\
**Post date:** [April 26, 2025, 12:46pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/22 "2025-04-26T12:46:25Z")

</div>

Can this package handle with binary format data in communication that support `WebSocket`, `TCP` protocol ? The data in the `body` of the packet is [`Protobuf`](https://developers.google.com/protocol-buffers) codec.

> **[Protocol Overview | LongPort OpenAPI](https://open.longportapp.com/docs/socket/protocol/overview)**
>
> We use binary format data for communication, protocol support both WebSocket and TCP.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [April 26, 2025, 1:48pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/23 "2025-04-26T13:48:44Z")

</div>

> [@digital\_carver](#):
>
> it could mislead users into thinking it’s an instance of this guideline (that it works by creating a `RestClient` type)

This. Pluralizing the package name in this way would be a mistake.

---

<div class="post-metadata">

**Author:** ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)\
**Post date:** [April 26, 2025, 1:50pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/24 "2025-04-26T13:50:44Z")

</div>

Here’s another formulation of the same general naming advice:

> ✔ CONSIDER using plural namespace names where appropriate.

> **[Names of Namespaces - Framework Design Guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-namespaces)**
>
> Use these guidelines for naming namespaces as part of guidelines for designing libraries that extend and interact with .NET libraries.

I think a plural S is almost always applicable - we are stuck with the name forever - the cost of an extra S is negligible. The cost of singular is potentially added friction down the line.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [April 26, 2025, 3:07pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/25 "2025-04-26T15:07:41Z")

</div>

> [@stemann](#):
>
> where appropriate.

It’s not appropriate here! I don’t even know why we’re having this discussion!

---

<div class="post-metadata">

**Author:** ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)\
**Post date:** [April 26, 2025, 3:26pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/26 "2025-04-26T15:26:51Z")

</div>

Because we disagree 😊

---

<div class="post-metadata">

**Author:** ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)\
**Post date:** [April 26, 2025, 3:48pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/27 "2025-04-26T15:48:27Z")

</div>

Just to clarify, and sorry for repeating an argument made in the General registry PR, but I guess my main argument for the pluralised version is that I do think that, at least eventually, there will be a need for a type of which you can create multiple instances (multiple clients), cf., e.g., connecting to multiple services with the same API.

---

<div class="post-metadata">

**Author:** ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)\
**Post date:** [April 26, 2025, 3:58pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/28 "2025-04-26T15:58:10Z")

</div>

It would also be nice with a poll that includes the other suggested names, e.g., `RestClientScaffold`, `RestClientMacros` (and multiple choice, please). Not sure if there has been other suggestions?

* * *

Edit:

I got some input from long-time community members supporting `RestClientScaffold`, or a non-systematic name - rather than `RestClient`/`RestClients` - similar to @digital_carver.

So I’ll dip a toe into an alternative poll:

_Poll ([view on site](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/28))_

---

<div class="post-metadata">

**Author:** ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)\
**Post date:** [May 21, 2025, 8:49am UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/29 "2025-05-21T08:49:26Z")

</div>

Update: RestClient.jl has just had its registration go through, with a few improvements to the docs/API thanks to some feedback from @stemann 🙂

I hope it will prove useful for anybody looking to wrap a REST-ish API in Julia.

In the future, I’d love to add a framework to make common authentication schemes easier, and with the upcoming Pkg.jl app support I think it would be really neat to make a code-generator tool that produced a package for a particular API from an OpenAPI definition.

I’d like to get to these eventually, but in the meantime PRs are welcome!

---

<div class="post-metadata">

**Author:** ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)\
**Post date:** [August 14, 2025, 3:42pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/30 "2025-08-14T15:42:53Z")

</div>

If you’ve tried RestClient.jl and found that it wasn’t handling rate-limiting properly for an API you tried, or that the debugging help was less useful that you expected, or that you didn’t see the expected kind of error for a failed request, I’d encourage you to check out v1.0.2 that’s just been released 🙂

I’ve mentioned the debugging a few times I think, but never actually shared a screenshot, so as an incentive/taster, here’s what you’ve been missing out on:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/b/c/bcc46a9d5380d1c132ef23577883d83db39cd41a.png)

---

<div class="post-metadata">

**Author:** ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)\
**Post date:** [June 22, 2026, 5:51pm UTC](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828/31 "2026-06-22T17:51:09Z")

</div>

**RestClient v1.1** is just out, and don’t let the minor version bump fool you, it’s a pretty substantial release.

## Features

### F.1 Streaming responses

I’ve had a think about how to make it as easy as possible to support streamed responses, through methods like SSE and NDJSON (which OOTB support is provided for). I’ve landed on a convenient wrapper type: `Stream{T}` for a stream of `T` objects that uses a `Channel` internally and supports iteration.

This means all it takes to read responses from a streaming API is:

```julia
@jsondef struct Delta
    type::String
    text."delta.text"::Union{String, Nothing} = nothing
end

# take a prompt string and post it to /messages, to get a stream of Deltas
@endpoint chat(prompt::String) -> prompt -> :post("messages") -> Stream{Delta}

for msg in chat("send me messages")
     println(msg.text)
end

```

If you want the full SSE frame data, you can just ask for a `Stream{SSEvent{T}}` and you’ll get `SSEvent{T}`s out of your iterator.

If you want to close a stream early, you can call `close` on the stream in another task.

### F.2 HTTP form and multipart payloads

In addition to `@jsondef` and `@xmldef`, you can now define form and multipart payloads with `@formdef` and `@multipartdef`:

```julia
@formdef struct LoginInfo
    username::String
    password::String
    rememberme."remember-me"::Bool = false
end

@jsondef struct UserInfo ... end

@endpoint login(auth::LoginInfo) -> auth -> :post("login") -> UserInfo

```

### F.3 Authentication convenience

APIs that take authentication details often use basic, bearer, header, or query based authentication. Previously, RestClient required you to provide this in every endpoint manually, but no longer.

```julia-auto
@globalconfig RequestConfig(...) auth=BearerAuth() # or,
@globalconfig RequestConfig(...) auth=(QueryAuth("api_key"), :required)

```

If you specify the authentication in `@globalconfig`, all `@endpoint`s defined will use it by default (as always, this can be customised per-endpoint). To make public/authenticated API splits easy though, `@endpoint` now supports a `:auth`/`:noauth`/`:authoption` keyword:

```julia-auto
@endpoint :noauth userinfo(...) -> ...
@endpoint :auth login(...) -> ...

```

## Improvements

- Support for JSON.jl, while keeping the existing support for JSON3.jl
- More structured errors, with `MalformedRequest` for requests that fail validation and `ResponseError`s for unsuccessful calls
- Better rate limiting with an atomic deadline
- More thorough validation, as `validate` may now return a whole list of issues
- `RequestConfig` will try to avoid printing its secret key (if set) in the REPL, while still supporting `repr` round-tripping

```julia-repl
julia> RequestConfig("https://api.example.com", key = "keepmesecret")
RequestConfig("https://api.example.com"; key = " *****", cache = true)

```

## Fixes

- getxattr error detection on Linux
- `setexpiry` erroring on non-unix systems
- handling of function keyword arguments in `@endpoint`

## Other changes

- We now take a bytes-first approach to data type interpretation over IO (the previous approach), which made streaming support a lot easier

[Previous page](https://discourse.julialang.org/t/pre-ann-restclient-jl/123828.md?page=1)
