Skip to content

Commit 55fb040

Browse files
committed
Added section to README
Improved documentation
1 parent fad438d commit 55fb040

File tree

2 files changed

+100
-14
lines changed

2 files changed

+100
-14
lines changed

pkgs/http/README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,87 @@ the [`RetryClient()`][new RetryClient] constructor.
113113

114114
[new RetryClient]: https://pub.dev/documentation/http/latest/retry/RetryClient/RetryClient.html
115115

116+
## Aborting requests
117+
118+
Some clients, such as [`BrowserClient`][browserclient], [`IOClient`][ioclient], and
119+
[`RetryClient`][retryclient], support abortion of requests in-flight.
120+
121+
Abortion in this way can only be performed when using [`Client.send`][clientsend] or
122+
[`BaseRequest.send`][baserequestsend] with an [`Abortable`][abortable] request (such
123+
as [`AbortableRequest`][abortablerequest]).
124+
125+
To abort a request, complete the [`Abortable.abortTrigger`][aborttrigger].
126+
127+
Depending on when the abortion is triggered, an [`AbortedRequest`][abortedrequest] may be thrown in different places.
128+
129+
```dart
130+
import 'dart:async';
131+
import 'package:http/http.dart' as http;
132+
133+
Future<void> main() async {
134+
final abortTrigger = Completer<void>();
135+
final client = Client();
136+
final request = AbortableRequest(
137+
'GET',
138+
Uri.parse('http://example.org'),
139+
abortTrigger: abortTrigger.future,
140+
);
141+
142+
// Whenever abortion is required:
143+
// > abortTrigger.complete();
144+
145+
// Send request
146+
final StreamedResponse response;
147+
try {
148+
response = await client.send(request);
149+
} on AbortedRequest {
150+
// request aborted before it was fully sent
151+
rethrow;
152+
}
153+
154+
// Using full response bytes listener
155+
response.stream.listen(
156+
(data) {
157+
// consume response bytes
158+
},
159+
onError: (Object err) {
160+
if (err is AbortedRequest) {
161+
// request aborted whilst response bytes are being streamed;
162+
// the stream will always be finished early
163+
}
164+
},
165+
onDone: () {
166+
// response bytes consumed, or partially consumed if finished
167+
// early due to abortion
168+
},
169+
);
170+
171+
// Alternatively, using `asFuture`
172+
try {
173+
await response.stream.listen(
174+
(data) {
175+
// consume response bytes
176+
},
177+
).asFuture<void>();
178+
} on AbortedRequest {
179+
// request aborted whilst response bytes are being streamed
180+
rethrow;
181+
}
182+
// response bytes fully consumed
183+
}
184+
```
185+
186+
[browserclient]: https://pub.dev/documentation/http/latest/browser_client/BrowserClient-class.html
187+
[ioclient]: https://pub.dev/documentation/http/latest/io_client/IOClient-class.html
188+
[retryclient]: https://pub.dev/documentation/http/latest/retry/RetryClient-class.html
189+
[clientsend]: https://pub.dev/documentation/http/latest/http/Client/send.html
190+
[baserequestsend]: https://pub.dev/documentation/http/latest/http/BaseRequest/send.html
191+
[abortable]: https://pub.dev/documentation/http/latest/http/Abortable-class.html
192+
[abortablerequest]: https://pub.dev/documentation/http/latest/http/AbortableRequest-class.html
193+
[aborttrigger]: https://pub.dev/documentation/http/latest/http/Abortable/abortTrigger.html
194+
[abortedrequest]: https://pub.dev/documentation/http/latest/http/AbortedRequest-class.html
195+
196+
116197
## Choosing an implementation
117198

118199
There are multiple implementations of the `package:http` [`Client`][client] interface. By default, `package:http` uses [`BrowserClient`][browserclient] on the web and [`IOClient`][ioclient] on all other platforms. You can choose a different [`Client`][client] implementation based on the needs of your application.

pkgs/http/lib/src/abortable.dart

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,37 @@ import 'dart:async';
66

77
import 'base_request.dart';
88
import 'client.dart';
9-
import 'exception.dart';
9+
import 'streamed_response.dart';
1010

1111
/// Enables a request to be recognised by a [Client] as abortable
1212
abstract mixin class Abortable implements BaseRequest {
13-
/// This request will be aborted if this completes
13+
/// Completion of this future aborts this request (if the client supports
14+
/// abortion)
1415
///
15-
/// A common pattern is aborting a request when another event occurs (such as
16-
/// a user action). A [Completer] may be used to implement this.
16+
/// Requests/responses may be aborted at any time during their lifecycle.
1717
///
18-
/// Another pattern is a timeout. Use [Future.delayed] to achieve this.
18+
/// * If completed before the request has been finalized and sent,
19+
/// [Client.send] completes with an [AbortedRequest] exception
20+
/// * If completed after the response headers are available, or whilst
21+
/// streaming response bytes, clients inject [AbortedRequest] into the
22+
/// [StreamedResponse.stream] then finish it early
23+
/// * If completed after the response is fully complete, there is no effect
1924
///
20-
/// This future must not complete to an error.
25+
/// A common pattern is aborting a request when another event occurs (such as
26+
/// a user action): use a [Completer] to implement this. To implement a
27+
/// timeout (to abort the request after a set time has elapsed), use
28+
/// [Future.delayed].
2129
///
22-
/// This future may complete at any time - a [AbortedRequest] will be thrown
23-
/// by [send]/[Client.send] if it is completed before the request is complete.
30+
/// This future must not complete to an error.
2431
///
25-
/// Non-'package:http' [Client]s may unexpectedly not support this trigger.
32+
/// Some clients may not support abortion, or may not support this trigger.
2633
abstract final Future<void>? abortTrigger;
2734
}
2835

29-
/// Thrown when a HTTP request is aborted
36+
/// Thrown when an HTTP request is aborted
3037
///
31-
/// Usually, this is due to [Abortable.abortTrigger] completing before the
32-
/// request is already complete. However, some clients' [Client.close]
33-
/// implementation may cause open requests to throw this (or a standard
34-
/// [ClientException]).
38+
/// Usually, this is due to [Abortable.abortTrigger]. See documentation on that
39+
/// property for more info.
3540
class AbortedRequest implements Exception {
3641
/// Indicator that the request has been aborted
3742
const AbortedRequest();

0 commit comments

Comments
 (0)