Challenge #4: Responses
After making a request to the server, the other half of the HTTP exchange is the response back to the client. That’s what you’ll implement in this challenge.
Instructions
1. Add the response:
- On the server, when the request ends, send an HTTP response and log
"SERVER SENT RESPONSE"
. - On the client, listen for the server’s response and log
"CLIENT RECEIVING RESPONSE"
. - Log
"CLIENT RECEIVED ENTIRE RESPONSE"
when the client sees the end of the server’s response.
2. Re-enable the code that stops the server:
- Use
await new Promise(...)
to wait for the entire response to be received. - Log
"EXCHANGE COMPLETE"
after the promise resolves. - Uncomment out the code that stops the server. This should stop the build from timing out.
3. Check your test output. You should see:
SERVER LISTENING
SERVER STARTED
CLIENT SENDING REQUEST
SERVER RECEIVING REQUEST
SERVER RECEIVED ENTIRE REQUEST
SERVER SENT RESPONSE
CLIENT RECEIVING RESPONSE
CLIENT RECEIVED ENTIRE RESPONSE
EXCHANGE COMPLETE
SERVER CLOSED
SERVER STOPPED
There should no longer be extra whitespace and dots in the test output, and the test output should all appear before the BUILD OK
line.
Remember to commit your changes when you’re done.
API Documentation
serverResponse.end();
Send the HTTP response. This function returns immediately, before all the data has been sent.
clientRequest.on("response", fn);
Run fn
when the client receives a response from the server.
- fn
((clientResponse) => void)
- the function to run - clientResponse
(http.IncomingMessage)
- the client’s view of the server’s response
clientResponse.on("end", fn);
Run fn
when the client sees the end of the server‘s response. Important: for this event to occur, you must consume the response’s data. You can use clientResponse.resume()
to do so.
- fn
((clientResponse) => void)
- the function to run - clientResponse
(http.IncomingMessage)
- the client’s view of the server’s response
clientResponse.resume();
Consume the server’s response to the client.
JavaScript Primers
No new concepts.
Hints
1
The server needs to send a response.
You can do that with serverResponse.end()
.
Send it after the server receives the entire request.
That’s the serverRequest.on("end", ...)
event handler.
it("performs request", async () => {
const server = http.createServer();
await new Promise((resolve, reject) => { // add <void> for TypeScript
server.listen(PORT);
server.on("listening", () => {
console.log("SERVER LISTENING");
return resolve();
});
});
console.log("SERVER STARTED");
server.on("request", (serverRequest, serverResponse) => {
console.log("SERVER RECEIVING REQUEST");
serverRequest.resume();
serverRequest.on("end", () => {
console.log("SERVER RECEIVED ENTIRE REQUEST");
serverResponse.end();
console.log("SERVER SENT RESPONSE");
});
});
console.log("CLIENT SENDING REQUEST");
const clientRequest = http.request({
host: HOST,
port: PORT,
});
clientRequest.end();
// await new Promise((resolve, reject) => { // add <void> for TypeScript
// server.close();
// server.on("close", () => {
// console.log("SERVER CLOSED");
// return resolve();
// });
// });
// console.log("SERVER STOPPED");
});
2
The client needs to listen for and log the server’s response.
You can do that with clientRequest.on("response", ...)
.
it("performs request", async () => {
const server = http.createServer();
await new Promise((resolve, reject) => { // add <void> for TypeScript
server.listen(PORT);
server.on("listening", () => {
console.log("SERVER LISTENING");
return resolve();
});
});
console.log("SERVER STARTED");
server.on("request", (serverRequest, serverResponse) => {
console.log("SERVER RECEIVING REQUEST");
serverRequest.resume();
serverRequest.on("end", () => {
console.log("SERVER RECEIVED ENTIRE REQUEST");
serverResponse.end();
console.log("SERVER SENT RESPONSE");
});
});
console.log("CLIENT SENDING REQUEST");
const clientRequest = http.request({
host: HOST,
port: PORT,
});
clientRequest.end();
clientRequest.on("response", (clientResponse) => {
console.log("CLIENT RECEIVING RESPONSE");
});
// await new Promise((resolve, reject) => { // add <void> for TypeScript
// server.close();
// server.on("close", () => {
// console.log("SERVER CLOSED");
// return resolve();
// });
// });
// console.log("SERVER STOPPED");
});
3
The exchange isn’t complete until the entire response has been received.
You can listen for the end of the response with clientResponse.on("end", ...)
.
That event won’t occur unless the entire response is consumed.
You can cause the response to be consumed with clientResponse.resume()
.
it("performs request", async () => {
const server = http.createServer();
await new Promise((resolve, reject) => { // add <void> for TypeScript
server.listen(PORT);
server.on("listening", () => {
console.log("SERVER LISTENING");
return resolve();
});
});
console.log("SERVER STARTED");
server.on("request", (serverRequest, serverResponse) => {
console.log("SERVER RECEIVING REQUEST");
serverRequest.resume();
serverRequest.on("end", () => {
console.log("SERVER RECEIVED ENTIRE REQUEST");
serverResponse.end();
console.log("SERVER SENT RESPONSE");
});
});
console.log("CLIENT SENDING REQUEST");
const clientRequest = http.request({
host: HOST,
port: PORT,
});
clientRequest.end();
clientRequest.on("response", (clientResponse) => {
console.log("CLIENT RECEIVING RESPONSE");
clientResponse.resume();
clientResponse.on("end", () => {
console.log("CLIENT RECEIVED ENTIRE RESPONSE");
});
});
// await new Promise((resolve, reject) => { // add <void> for TypeScript
// server.close();
// server.on("close", () => {
// console.log("SERVER CLOSED");
// return resolve();
// });
// });
// console.log("SERVER STOPPED");
});
4
If you look at the test output closely, you may see some extra whitespace and dots.
That means the "SERVER RECEIVING REQUEST"
log is occurring after the test ends.
This happens when the code is missing an await
.
The test isn’t waiting for the response to be received.
5
The test needs to wait for the entire response to be received.
You can do that with await new Promise()
.
If the test times out, it’s because you forgot to call resolve()
.
it("performs request", async () => {
const server = http.createServer();
await new Promise((resolve, reject) => { // add <void> for TypeScript
server.listen(PORT);
server.on("listening", () => {
console.log("SERVER LISTENING");
return resolve();
});
});
console.log("SERVER STARTED");
server.on("request", (serverRequest, serverResponse) => {
console.log("SERVER RECEIVING REQUEST");
serverRequest.resume();
serverRequest.on("end", () => {
console.log("SERVER RECEIVED ENTIRE REQUEST");
serverResponse.end();
console.log("SERVER SENT RESPONSE");
});
});
console.log("CLIENT SENDING REQUEST");
const clientRequest = http.request({
host: HOST,
port: PORT,
});
clientRequest.end();
await new Promise((resolve, reject) => { // add <void> for TypeScript
clientRequest.on("response", (clientResponse) => {
console.log("CLIENT RECEIVING RESPONSE");
clientResponse.resume();
clientResponse.on("end", () => {
console.log("CLIENT RECEIVED ENTIRE RESPONSE");
resolve();
});
});
});
// await new Promise((resolve, reject) => { // add <void> for TypeScript
// server.close();
// server.on("close", () => {
// console.log("SERVER CLOSED");
// return resolve();
// });
// });
// console.log("SERVER STOPPED");
});
6
Log that the exchange is complete and uncomment the code that stops the server.
it("performs request", async () => {
const server = http.createServer();
await new Promise((resolve, reject) => { // add <void> for TypeScript
server.listen(PORT);
server.on("listening", () => {
console.log("SERVER LISTENING");
return resolve();
});
});
console.log("SERVER STARTED");
server.on("request", (serverRequest, serverResponse) => {
console.log("SERVER RECEIVING REQUEST");
serverRequest.resume();
serverRequest.on("end", () => {
console.log("SERVER RECEIVED ENTIRE REQUEST");
serverResponse.end();
console.log("SERVER SENT RESPONSE");
});
});
console.log("CLIENT SENDING REQUEST");
const clientRequest = http.request({
host: HOST,
port: PORT,
});
clientRequest.end();
await new Promise((resolve, reject) => { // add <void> for TypeScript
clientRequest.on("response", (clientResponse) => {
console.log("CLIENT RECEIVING RESPONSE");
clientResponse.resume();
clientResponse.on("end", () => {
console.log("CLIENT RECEIVED ENTIRE RESPONSE");
resolve();
});
});
});
console.log("EXCHANGE COMPLETE");
await new Promise((resolve, reject) => { // add <void> for TypeScript
server.close();
server.on("close", () => {
console.log("SERVER CLOSED");
return resolve();
});
});
console.log("SERVER STOPPED");
});
Complete Solution
Test code (JavaScript):
it("performs request", async () => {
const server = http.createServer();
await new Promise((resolve, reject) => {
server.listen(PORT);
server.on("listening", () => {
console.log("SERVER LISTENING");
return resolve();
});
});
console.log("SERVER STARTED");
server.on("request", (serverRequest, serverResponse) => {
console.log("SERVER RECEIVING REQUEST");
serverRequest.resume();
serverRequest.on("end", () => {
console.log("SERVER RECEIVED ENTIRE REQUEST");
serverResponse.end();
console.log("SERVER SENT RESPONSE");
});
});
console.log("CLIENT SENDING REQUEST");
const clientRequest = http.request({
host: HOST,
port: PORT,
});
clientRequest.end();
await new Promise((resolve, reject) => {
clientRequest.on("response", (clientResponse) => {
console.log("CLIENT RECEIVING RESPONSE");
clientResponse.resume();
clientResponse.on("end", () => {
console.log("CLIENT RECEIVED ENTIRE RESPONSE");
resolve();
});
});
});
console.log("EXCHANGE COMPLETE");
await new Promise((resolve, reject) => {
server.close();
server.on("close", () => {
console.log("SERVER CLOSED");
return resolve();
});
});
console.log("SERVER STOPPED");
});
Test code (TypeScript):
it("performs request", async () => {
const server = http.createServer();
await new Promise<void>((resolve, reject) => {
server.listen(PORT);
server.on("listening", () => {
console.log("SERVER LISTENING");
return resolve();
});
});
console.log("SERVER STARTED");
server.on("request", (serverRequest, serverResponse) => {
console.log("SERVER RECEIVING REQUEST");
serverRequest.resume();
serverRequest.on("end", () => {
console.log("SERVER RECEIVED ENTIRE REQUEST");
serverResponse.end();
console.log("SERVER SENT RESPONSE");
});
});
console.log("CLIENT SENDING REQUEST");
const clientRequest = http.request({
host: HOST,
port: PORT,
});
clientRequest.end();
await new Promise<void>((resolve, reject) => {
clientRequest.on("response", (clientResponse) => {
console.log("CLIENT RECEIVING RESPONSE");
clientResponse.resume();
clientResponse.on("end", () => {
console.log("CLIENT RECEIVED ENTIRE RESPONSE");
resolve();
});
});
});
console.log("EXCHANGE COMPLETE");
await new Promise<void>((resolve, reject) => {
server.close();
server.on("close", () => {
console.log("SERVER CLOSED");
return resolve();
});
});
console.log("SERVER STOPPED");
});
No production code yet.