-
Notifications
You must be signed in to change notification settings - Fork 701
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tests for dart-vm httpserver tutorial code excerpts #463
Conversation
We're doing this to minimize changes to the sample code during this first pass.
..close(); | ||
} | ||
} catch (e) { | ||
print(e.toString); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code excerpt in the tutorial page didn't contain a try-catch statement. I've reverted the code to match the excerpt, because
- Catching an exception and only printing a message is bad practice. (Note only that, but the code is wrong; it prints the value of the toString function).
- There are better examples of error handling elsewhere in the tutorial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. We'll need to update the dart-tutorials-samples repo to match, of course. (But that's true everywhere.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you prefer that we point to the files in this repo? The files themselves will contain #docregion
and #docplaster
tags. As for a zip of the projects, it can be relatively easy to create a zip of the sources with those tags removed. We could then host those project .zip files from dartlang.org (along with the rest of the site files).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel strongly about where we point to, as long as (1) those tags aren't visible and (2) we're careful about keeping everything in sync.
Looking now... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! I want to make a second pass (for missing highlights, at least) but I'm done for the night.
While you're in there, could you fix the formatting of the command-line snippets? "Wrote data for Han Solo." is unnecessarily colorized.
@@ -5,7 +5,6 @@ description: Communicate over the internet | |||
prevpage: | |||
url: /tutorials/dart-vm/cmdline | |||
title: "Dart-VM: Write Command-Line Apps" | |||
css: ["httpserver.css"] | |||
--- | |||
{% capture gh-path -%} | |||
https://github.com/dart-lang/dart-tutorials-samples/blob/master/httpserver |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to update this path, no? (E.g., the link in "Example file for this section: hello_world_server.dart" points here.)
I think we had a separate repo to make it easy to download all the samples easily. Now that the sites have split, all-in-one downloads seem less useful.
I guess we should aim to remove the dart-tutorials-samples repo, eventually, but that'll require some doing. For now, we should probably update that repo so that it points to the example files here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should probably update that repo
Yes, I'll do that for now (after this PR is accepted), and we'll keep this URL as is (so that readers will be directed to sources w/o #docregion
tags).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, makes sense to keep that repo for the cleaned up version of these files.
src/_tutorials/dart-vm/httpserver.md
Outdated
@@ -154,21 +152,22 @@ listening, and responding. | |||
|
|||
## Binding a server to a host and port {#binding} | |||
|
|||
_Example for this section: hello_world_server.dart._ | |||
_Example for this section:_ | |||
[hello_world_server.dart.]({{gh-path}}/bin/hello_world_server.dart) | |||
|
|||
The first line of code in `main()` uses `HttpServer.bind()` to create an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line of code -> statement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
{% endprettify %} | ||
<div class="prettify-filename">hello_world_server.dart</div> | ||
|
||
The code uses `await` to call the `bind` method asynchronously. | ||
When the bind is successful, the new HttpServer object is assigned |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why remove this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name of the declared variable changed and so that line of prose required editing. I decided to just drop that sentence because IMHO: (1) The code self explanatory. (2) This is especially the case given that the paragraph immediately before the code snippet reads:
The first statement in
main()
usesHttpServer.bind()
to create an [HttpServer][] object and bind it to a host and port.
(Otherwise, the statement is essentially describing how a variable declaration with an initializer works.)
src/_tutorials/dart-vm/httpserver.md
Outdated
@@ -204,17 +203,17 @@ The server begins listening for HTTP requests using `await for`. | |||
For each request received, the highlighted code is executed for that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any code highlighting. (Should I?) Maybe say instead:
For each request received, the code sends a response ('Hello, world!').
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is better (and yes I had forgotten to add the highlighting in that snippet). I've changed it to:
For each request received, the code sends a "Hello, world!" response.
src/_tutorials/dart-vm/httpserver.md
Outdated
- The form's `method` attribute defines | ||
the kind of request, here a `GET`. Other common | ||
kinds of request include POST, PUT, and DELETE. | ||
- Any element within the form, like `<select>`, that has a `name` becomes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> Any element within the form that has a name
, like the <select>
element, becomes...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/_tutorials/dart-vm/httpserver.md
Outdated
HttpResponse response = req.response; | ||
|
||
if (req.method == 'POST' && | ||
[!contentType != null && /*1*/!] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be shortened to something like 'application/json' == contentType?.mimeType
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see contentType?.mimeType == 'application/json'
in the new code.
From ancient code reviews (don't remember whether they were even in Dart), I remember being told to use the constant as the LHS, so you don't have to worry about invoking a method on null. Is that not a concern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that isn't a problem in Dart.
Operator ==
is defined in Object
, and hence it is defined for all types, including Null
.
src/_tutorials/dart-vm/httpserver.md
Outdated
HttpResponse response = req.response; | ||
|
||
if (req.method == 'POST' && | ||
[!contentType != null && /*1*/!] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's easy to miss the /*1*/
when there's no break between the highlighted code and the footnote number. Would it be too horrible to NOT highlight the character before the /*
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better, thanks!
main() async { | ||
File targetFile = new File('index.html'); | ||
|
||
Future main() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of hate seeing main
annotated with a type. It obscures the entry point for little to no benefit, as far as I can see.
Does the analyzer complain if we leave out the type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the analyzer will complain, specifically about the following lint rule:
lint • Type annotate public APIs at ... • type_annotate_public_apis
With the increased importance of static type annotations in Dart 2, I feel that we get more benefits from enforcing the type_annotate_public_apis
lint than any gains we achieve (like more terse code) from excluding it.
Without the return type, I find it easy to quickly scan the method signature main() async { ... }
and "read" main() { ... }
. The return type sticks out like a warning sign, alerting the reader to the fact that main is asynchronous.
It obscures the entry point
I find that the code highlighting helps make it just as easy to locate the entry point, because main()
is in black font, whereas the tokens around it are more lightly colored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@filiph what do you think we should do? I don't like turning off lints. Maybe we can get a special case for "main" in the lint?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noting that this issue isn't gating. (We are still discussing this offline.)
..close(); | ||
} | ||
} catch (e) { | ||
print(e.toString); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. We'll need to update the dart-tutorials-samples repo to match, of course. (But that's true everywhere.)
src/_tutorials/dart-vm/httpserver.md
Outdated
var certificateChain = | ||
Platform.script.resolve('server_chain.pem').toFilePath(); | ||
var serverKey = Platform.script.resolve('server_key.pem').toFilePath(); | ||
[!var serverContext = new SecurityContext(); /*1*/!] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new syntax is so much easier for me to read!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm very glad that you like it. I juggled with a few options, but this was the simplest to deal with and using /*#*/ seems natural enough a marker for code.
Let's address this separately. I've created #466 to track this issue. |
Updates completed. Staging server refreshed. |
Future main() async { | ||
var certificateChain = | ||
Platform.script.resolve('server_chain.pem').toFilePath(); | ||
var serverKey = Platform.script.resolve('server_key.pem').toFilePath(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This server script, with its use of Platform.script
, doesn't lend itself well to testing. We don't use Platform.script
in any other app, and it is beside the point that we are trying to illustrate here, so I dropped it.
src/_tutorials/dart-vm/httpserver.md
Outdated
returns an [HttpClientResponse][] object that's assigned to the `reponse` | ||
variable. | ||
|
||
5. The UTF-8 response from the server is decoded. Use a transformer defined in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think my objection was to the passive voice. How about:
/*5*/ A decoder from the ... library converts the data...
(This rewording also avoids the word transformer, which I don't think we need/want to use here.)
request.write(JSON.encode(jsonData)); | ||
HttpClientResponse response = await request.close(); | ||
await for (var contents in response.transform(UTF8.decoder)) { | ||
.post(InternetAddress.LOOPBACK_IP_V4.host, 4049, 'file.txt'); /*1*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the window width I use when reviewing (just barely 3-column), this line is cut off. The last fully visible character is the ;
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
request.headers.contentType = ContentType.JSON; /*2*/ | ||
request.write(JSON.encode(jsonData)); /*3*/ | ||
HttpClientResponse response = await request.close(); /*4*/ | ||
await for (var contents in response.transform(UTF8.decoder /*5*/)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At my window width, I can't see anything to the right of the ))
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is a bit trickier to fix. I've reworked the code, PTAL.
src/_tutorials/dart-vm/httpserver.md
Outdated
await for (HttpRequest request in requestServer) { | ||
request.response..write('Hello, world!') | ||
..close(); | ||
import 'dart:io'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Highlight is missing on this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added back.
Use a transformer defined in the `dart:convert` library | ||
to convert the data into regular Dart string format. | ||
{:.code-notes} | ||
1. The `post()` method requires the host, port, and the path to the requested |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the main reason to keep it would be to emphasize that the returned value is a HttpClientRequest, since that isn't visible in the code. (You mention that type later, but you don't explicitly tie it to this variable.)
src/_tutorials/dart-vm/httpserver.md
Outdated
}; | ||
|
||
var request = await new HttpClient() | ||
.[!post!](InternetAddress.LOOPBACK_IP_V4.host, 4049, 'file.txt'); [!/*1*/!] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't see anything after the ;
in this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reworked the code, PTAL.
src/_tutorials/dart-vm/httpserver.md
Outdated
import 'dart:convert'; | ||
|
||
Future main() async { | ||
var server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 4049); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last visible characters on this line are V4,
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/_tutorials/dart-vm/httpserver.md
Outdated
if (req.method == 'POST' && | ||
[!contentType?.mimeType == 'application/json'!] [!/*1*/!]) { | ||
try { | ||
var [!jsonString = await req.transform(UTF8.decoder).join();!] [!/*2*/!] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Last visible characters: ();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
src/_tutorials/dart-vm/httpserver.md
Outdated
{% prettify dart %} | ||
void addCorsHeaders(HttpResponse response) { | ||
response.headers.add('Access-Control-Allow-Origin', '*'); | ||
response.headers.add( | ||
'Access-Control-Allow-Methods', 'POST, OPTIONS'); | ||
response.headers.add('Access-Control-Allow-Methods', 'POST, OPTIONS'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line is cut off
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
main() async { | ||
File targetFile = new File('index.html'); | ||
|
||
Future main() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few code snippets need a shorter line length, and I'd like some wording tweaks, but once you fix those LGTM.
src/_tutorials/dart-vm/httpserver.md
Outdated
3. The data sent by the client is JSON formatted. The server decodes it using | ||
the JSON codec available in the [dart:convert][] library. | ||
|
||
4. The URL for the request is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, the text of these bullets has not changed. I've just swapped the steps because of a reordering of statements in the code.
This brings in the changes made under: - dart-lang/site-www#463 - dart-lang/site-www#470
Contributes to #407, covering the Tutorial (VM): Write HTTP Clients and Servers (no.12)
Some code excerpts have note markers. It was a bit tricky to deal with those in the context of code excerpts that get refreshed. I've experimented with a few approaches and settled on the use of comment markers
/*1*/
,/*2*/
, etc. Let me know what you think.