Skip to content

Commit

Permalink
Make the recommendation to not use dart:io/dart:html for HTTP req…
Browse files Browse the repository at this point in the history
…uests stronger (#5391)

Part of dart-lang/sdk#52023
---------

Co-authored-by: Marya <[email protected]>
Co-authored-by: Parker Lougheed <[email protected]>
  • Loading branch information
3 people authored Dec 11, 2023
1 parent 2f38c2e commit 507072c
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 144 deletions.
9 changes: 5 additions & 4 deletions examples/misc/lib/library_tour/async/basic.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import 'dart:html';
import 'package:http/http.dart';

void miscDeclAnalyzedButNotTested() {
const url = 'humans.txt';
final url = Uri.parse('humans.txt');
final httpClient = Client();

{
// #docregion then
HttpRequest.getString(url).then((String result) {
httpClient.read(url).then((String result) {
print(result);
});
// #enddocregion then
}

{
// #docregion catchError
HttpRequest.getString(url).then((String result) {
httpClient.read(url).then((String result) {
print(result);
}).catchError((e) {
// Handle or ignore the error.
Expand Down
1 change: 1 addition & 0 deletions examples/misc/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ dependencies:
args: ^2.4.2
characters: ^1.3.0
examples_util: { path: ../util }
http: ^1.1.2

dev_dependencies:
lints: ^3.0.0
Expand Down
123 changes: 10 additions & 113 deletions src/guides/libraries/_dart-html-tour.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,119 +322,15 @@ subclasses. Some common events include:

### Using HTTP resources with HttpRequest

Formerly known as XMLHttpRequest, the [HttpRequest][] class
gives you access to HTTP resources from within your browser-based app.
Traditionally, AJAX-style apps make heavy use of HttpRequest. Use
HttpRequest to dynamically load JSON data or any other resource from a
web server. You can also dynamically send data to a web server.


#### Getting data from the server

The HttpRequest static method `getString()` is an easy way to get data
from a web server. Use `await` with the `getString()` call
to ensure that you have the data before continuing execution.

<?code-excerpt "html/test/html_test.dart (getString)" plaster="none" replace="/await.*;/[!$&!]/g; /Future<\w+\W/void/g"?>
{% prettify dart tag=pre+code %}
void main() async {
String pageHtml = [!await HttpRequest.getString(url);!]
// Do something with pageHtml...
}
{% endprettify %}

Use try-catch to specify an error handler:

<?code-excerpt "html/lib/html.dart (try-getString)"?>
```dart
try {
var data = await HttpRequest.getString(jsonUri);
// Process data...
} catch (e) {
// Handle exception...
}
```

If you need access to the HttpRequest, not just the text data it
retrieves, you can use the `request()` static method instead of
`getString()`. Here's an example of reading XML data:

<?code-excerpt "html/test/html_test.dart (request)" replace="/Future<\w+\W/void/g; /await.*;/[!$&!]/g"?>
```dart
void main() async {
HttpRequest req = await HttpRequest.request(
url,
method: 'HEAD',
);
if (req.status == 200) {
// Successful URL access...
}
// ···
}
```

You can also use the full API to handle more interesting cases. For
example, you can set arbitrary headers.

The general flow for using the full API of HttpRequest is as follows:

1. Create the HttpRequest object.
2. Open the URL with either `GET` or `POST`.
3. Attach event handlers.
4. Send the request.

For example:

<?code-excerpt "html/lib/html.dart (new-HttpRequest)"?>
```dart
var request = HttpRequest();
request
..open('POST', url)
..onLoadEnd.listen((e) => requestComplete(request))
..send(encodedData);
```

#### Sending data to the server

HttpRequest can send data to the server using the HTTP method POST. For
example, you might want to dynamically submit data to a form handler.
Sending JSON data to a RESTful web service is another common example.

Submitting data to a form handler requires you to provide name-value
pairs as URI-encoded strings. (Information about the URI class is in
the [URIs section][URIs] of the [Dart Library Tour.][Dart Library Tour])
You must also set the `Content-type` header to
`application/x-www-form-urlencoded` if you wish to send data to a form
handler.

<?code-excerpt "html/test/html_test.dart (POST)"?>
```dart
String encodeMap(Map<String, String> data) => data.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
void main() async {
const data = {'dart': 'fun', 'angular': 'productive'};
var request = HttpRequest();
request
..open('POST', url)
..setRequestHeader(
'Content-type',
'application/x-www-form-urlencoded',
)
..send(encodeMap(data));
await request.onLoadEnd.first;
if (request.status == 200) {
// Successful URL access...
}
// ···
}
```
You should avoid directly using `dart:html` to make HTTP requests.
The [`HttpRequest`][] class in `dart:html` is platform-dependent
and tied to a single implementation.
Instead, use a higher-level library like
[`package:http`]({{site.pub-pkg}}/http).

The [Fetch data from the internet][] tutorial
explains how to make HTTP requests
using `package:http`.

### Sending and receiving real-time data with WebSockets

Expand Down Expand Up @@ -542,9 +438,10 @@ For more information about Dart web libraries, see the
[AnchorElement]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-html/AnchorElement-class.html
[dart:html]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-html/dart-html-library.html
[Dart Library Tour]: /guides/libraries/library-tour
[Fetch data from the internet]: /tutorials/server/fetch-data
[Document]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-html/Document-class.html
[Element]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-html/Element-class.html
[HttpRequest]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-html/HttpRequest-class.html
[`HttpRequest`]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-html/HttpRequest-class.html
[IndexedDB]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-indexed_db/dart-indexed_db-library.html
[MessageEvent]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-html/MessageEvent-class.html
[Nodes]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-html/Node-class.html
Expand Down
29 changes: 9 additions & 20 deletions src/guides/libraries/_dart-io-tour.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,27 +234,15 @@ void processRequest(HttpRequest request) {

#### HTTP client

The [HttpClient][] class
helps you connect to HTTP resources from your Dart command-line or
server-side application. You can set headers, use HTTP methods, and read
and write data. The HttpClient class does not work in browser-based
apps. When programming in the browser, use the
[dart:html HttpRequest class.][HttpRequest]
Here's an example of using HttpClient:

<?code-excerpt "misc/test/library_tour/io_test.dart (client)" replace="/Future<\w+\W/void/g"?>
```dart
void main() async {
var url = Uri.parse('http://localhost:8888/dart');
var httpClient = HttpClient();
var request = await httpClient.getUrl(url);
var response = await request.close();
var data = await utf8.decoder.bind(response).toList();
print('Response ${response.statusCode}: $data');
httpClient.close();
}
```
You should avoid directly using `dart:io` to make HTTP requests.
The [HttpClient][] class in `dart:io` is platform-dependent
and tied to a single implementation.
Instead, use a higher-level library like
[`package:http`]({{site.pub-pkg}}/http).

The [Fetch data from the internet][] tutorial
explains how to make HTTP requests
using `package:http`.

### More information

Expand All @@ -269,6 +257,7 @@ For more information about server-side and command-line app development, see the
[library tour]: /guides/libraries/library-tour
[dart:io]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/dart-io-library.html
[Directory]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/Directory-class.html
[Fetch data from the internet]: /tutorials/server/fetch-data
[File]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/File-class.html
[HttpClient]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/HttpClient-class.html
[HttpRequest]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-html/HttpRequest-class.html
Expand Down
7 changes: 4 additions & 3 deletions src/guides/libraries/library-tour.md
Original file line number Diff line number Diff line change
Expand Up @@ -1196,13 +1196,13 @@ see the [asynchronous programming codelab](/codelabs/async-await).
{% endcomment %}

You can use `then()` to schedule code that runs when the future completes. For
example, `HttpRequest.getString()` returns a Future, since HTTP requests
example, [`Client.read()`][] returns a Future, since HTTP requests
can take a while. Using `then()` lets you run some code when that Future
has completed and the promised string value is available:

<?code-excerpt "misc/lib/library_tour/async/basic.dart (then)"?>
```dart
HttpRequest.getString(url).then((String result) {
httpClient.read(url).then((String result) {
print(result);
});
```
Expand All @@ -1212,7 +1212,7 @@ object might throw.

<?code-excerpt "misc/lib/library_tour/async/basic.dart (catchError)"?>
```dart
HttpRequest.getString(url).then((String result) {
httpClient.read(url).then((String result) {
print(result);
}).catchError((e) {
// Handle or ignore the error.
Expand Down Expand Up @@ -1806,6 +1806,7 @@ To learn more about the Dart language, see the

[ArgumentError]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-core/ArgumentError-class.html
[Assert]: /language/error-handling#assert
[`Client.read()`]: {{site.pub-api}}/http/latest/http/Client/read.html
[Comparable]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-core/Comparable-class.html
[Dart API]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}
[DateTime]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-core/DateTime-class.html
Expand Down
13 changes: 9 additions & 4 deletions src/tutorials/server/fetch-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,17 @@ see [What is a URL?][] on the mdn web docs.

## Retrieve the necessary dependencies

You can directly use `dart:io` or `dart:html` to make HTTP requests,
however those libraries are platform dependent.
`package:http` provides a cross-platform library
The `package:http` library provides a cross-platform solution
for making composable HTTP requests,
with optional fine-grained control.

{{site.alert.note}}
You should avoid directly using `dart:io` or `dart:html`
to make HTTP requests.
Those libraries are platform-dependent
and tied to a single implementation.
{{site.alert.end}}

To add a dependency on `package:http`,
run the following [`dart pub add`][] command
from the top of your repo:
Expand Down Expand Up @@ -230,7 +235,7 @@ which can also be seen in your browser at
```json
{
"name": "http",
"latestVersion": "0.13.5",
"latestVersion": "1.1.2",
"description": "A composable, multi-platform, Future-based API for HTTP requests.",
"publisher": "dart.dev",
"repository": "https://github.com/dart-lang/http"
Expand Down

0 comments on commit 507072c

Please sign in to comment.