revali_client 3.0.0
revali_client: ^3.0.0 copied to clipboard
A Revali Server Client Construct to generate client code using `revali_router`
CHANGELOG #
3.0.0 | 08.15.26 #
Breaking Changes #
HttpInterceptor.onRequestandonResponsereturnFutureOr<HttpResponse?>instead ofvoid. Returningnull— the common case — means "carry on"; returning a response fromonRequestanswers without sending anything, and fromonResponsesubstitutes what arrived. The old signature made retries, caching and circuit breaking impossible to build at all, by us or by anyone else, which is why this changes now rather than after more code depends on it. Migration is mechanical: change the return type and addreturn null.- Interceptor errors are no longer swallowed. A throwing interceptor now fails the request instead of letting it continue in whatever half-prepared state it was left in — a failed auth interceptor previously put an unauthenticated request on the wire and surfaced as a puzzling
401from the peer rather than an error where it actually broke.
Features #
- Add
RevaliClient.timeout. Covers reaching the far side and getting its status back, not the time spent streaming a large body afterwards — a slow download is not the same failure as a peer that never answers. Null keeps the previous unbounded behaviour, which is a poor default in a service mesh: a peer that accepts connections and never replies otherwise holds the request forever. - Add
RetryPolicyandRevaliClient.retry, off by default. Two rules keep it honest: only idempotent methods (GET,HEAD,OPTIONS,PUT,DELETE), because retrying aPOSTthat reached the server and failed on the way back creates the resource twice; and only transient statuses (502,503,504), because a400will say the same thing next time and retrying it just multiplies load during an incident. A request with a streamed body is never retried at all — the stream is consumed as it is sent, so a second attempt would transmit nothing. Backoff is exponential and capped, andRetry-Afteroverrides it when the server sends the delta-seconds form. Retried responses are drained, so the loop does not leak a socket per attempt. - Retry and timeout live in
RevaliClient, above the transport, so a customHttpClientgets both instead of having to reimplement them. ServerExceptionreads the error envelope. When the peer sent one,code,reasonanddetailscarry it andisStructuredis true, so a caller can branch one.code == 'user_not_found'instead of pattern-matching a body. When it did not — a plain-text response, an intermediary's HTML error page, a third-party API — those are null and the rawbodyis available exactly as before. Parsing is best-effort by design: a malformed body surfaces as the HTTP failure it already is, never as aFormatExceptionfrom the client.- Add
HeaderInterceptor, which computes headers per request instead of fixing them when the client is built. The motivating case is correlation: a server handling a request and calling a peer forwards its trace headers withHeaderInterceptor(() => TraceContext.current?.outboundHeaders() ?? const {}). It never overwrites a header the call site set explicitly. The callback is deliberately the coupling —revali_clientruns on the web, wheredart:ioand sorevali_corecannot follow, so a function ofMap<String, String>connects the two without dragging a server-only dependency into a browser bundle.
Fixes #
- Build the outgoing request after the interceptors run, so one that rewrites the body or the encoding is reflected in what is actually sent rather than only its headers.
- Stop the error path throwing a
TypeErrorinstead of reading the body.response.stream.transform(utf8.decoder)fails when the transport hands back aStream<Uint8List>— whichpackage:httpdoes — becausetransformis generic on the stream's runtime type. Only the error path decodes a body this way, and no test exercised an error response through a generated client, so every structured failure surfaced astype 'Utf8Decoder' is not a subtype of ...rather than as aServerException. Found by the newtest_suite/constructs/revali_client/errorspackage.
2.1.0 | 08.13.26 #
Features #
- Send streamed request bodies. A
Stream<List<int>>orStream<String>body is now handed to the transport and sent incrementally, so a large upload never has to fit in memory; previously this threwUnimplementedError. The server side already worked —@Body() Stream<List<int>>reads the payload as it arrives — so this completes the round trip.HttpRequestgainsbodyStream. Any otherStream<T>throws anArgumentErrornaming the supported types rather than inventing a framing format the server has no binding for.
Fixes #
- Parse every
Set-Cookievalue, and stop storing cookie attributes as cookies. A response setting several cookies arrives as one comma-joined header, whichCookieParsercould not match at all, so none were saved; the attributes it did match putPathandExpiresinto storage. Splitting now happens only at a comma beginning a newname=pair, so the comma inside anExpiresdate cannot split a cookie in half. - Actually enable cross-origin cookie credentials on web by setting
BrowserClient.withCredentials = true, instead of adding a literalcredentials: 'include'HTTP header (a no-op --credentialsis afetch()-level option, not a header, so it never did anything). Non-web platforms are unaffected (no browser cookie jar to opt into).
2.0.5 | 08.07.26 #
Fixes #
- Actually enable cross-origin cookie credentials on web by setting
BrowserClient.withCredentials = true, instead of adding a literalcredentials: 'include'HTTP header (a no-op --credentialsis afetch()-level option, not a header, so it never did anything). Non-web platforms are unaffected (no browser cookie jar to opt into).
2.0.4 | 02.18.26 #
Enhancements #
- Add
credentials: 'include'to HTTP requests for cookie support with fetch
1.3.0 | 05.08.25 #
1.2.0 | 04.15.25 #
Features #
- Add
server_nameoption torevali.yaml#constructs.revali_clientto set the name of the server class
Enhancements #
- Add check for empty query parameters before appending
?to the URL - Remove
finalkeyword from generated server class
Fixes #
- Issue where
@ExcludeFromClientwas being ignored for interface methods - Issue where empty controller paths would result in
//<path>being generated in the client
1.1.0 | 04.07.25 #
Features #
- Add
ExcludeFromClientannotation to exclude controllers/methods from being generated in the client
1.0.1 | 03.24.25 #
Initial Release!
1.0.0 | 03.24.25 #
Initial Release!