Challenge #3: Requests

Now that the server is running, you can start making HTTP requests. This also will require you to add support for handling requests on the server.

Instructions

1. Make an HTTP request:

  1. Log "CLIENT SENDING REQUEST", then make an HTTP request to the HOST and PORT constants.
  2. The code will fail with ECONNREFUSED because it’s stopping the server before the request is sent.
  3. Temporarily comment out the code that stops the server. (You’ll re-enable it in the next challenge.) This will cause the build to time out, but it will make it easier to see your progress.

2. Handle the client’s request:

  1. On the server, listen for client requests and log "SERVER RECEIVING REQUEST".
  2. When the request ends, log "SERVER RECEIVED ENTIRE REQUEST".

3. Check your test output. You should see:

SERVER LISTENING
SERVER STARTED
CLIENT SENDING REQUEST
SERVER RECEIVING REQUEST
SERVER RECEIVED ENTIRE REQUEST

There may be some extra whitespace and dots in the test output. You might even see some of the test output appear after the BUILD OK line. You can ignore that for now.

Remember to commit your changes when you’re done.

API Documentation

const clientRequest = http.request({ host, port })

Start making an HTTP request. Note that the request isn’t complete until clientRequest.end() is called.

  • host (string) - the server host
  • port (number) - the server port
  • returns clientRequest (http.ClientRequest) - the client’s request
clientRequest.end();

Complete the HTTP request. This function returns immediately, before all the data has been sent.

server.on("request", fn);

Run fn when the server receives a request.

  • fn ((serverRequest, serverResponse) => void) - the function to run
  • serverRequest (http.IncomingMessage) - the server’s view of the client’s request
  • serverResponse (http.ServerResponse) - the server’s response
serverRequest.on("end", fn);

Run fn when the server sees the end of the client‘s request. Important: for this event to occur, you must consume the request’s data. You can use serverRequest.resume() to do so.

  • fn (() => void) - the function to run
serverRequest.resume();

Consume the client’s request on the server.

const HOST = "localhost"

This constant is available in the test code. It’s the host of the tests’ HTTP server. Use it when your tests make HTTP requests.

JavaScript Primers

No new concepts.

Hints

1
Log the request you’re about to send.
You can use console.log() to do that.
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");


	console.log("CLIENT SENDING REQUEST");


	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
Make the request.
You can use http.request() to do that.
Don’t forget to end the request.
You can use clientRequest.end() for that.
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");


	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");
});
3
You might be getting a "ECONNREFUSED" error.
It stands for “connection refused.” It means the server isn’t accepting connections.

That’s because your code is stopping the server before it can receive the request.

4
Temporarily comment out the code that stops the server.
This will cause the build to time out.
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");


	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");
});
5
The server needs to listen for and log client requests.
You can do that with server.on("request", ...).
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");
	});


	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");
});
6
Before the server can send a response, it needs to see the end of the request.
You can listen for it with serverRequest.on("end", ...).
That event won’t occur unless the entire request is consumed.
You can cause the request to be consumed with serverRequest.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");
		});
	});


	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");
});

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");
		});
	});


	console.log("CLIENT SENDING REQUEST");
	const clientRequest = http.request({
		host: HOST,
		port: PORT,
	});
	clientRequest.end();


	// 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");
		});
	});


	console.log("CLIENT SENDING REQUEST");
	const clientRequest = http.request({
		host: HOST,
		port: PORT,
	});
	clientRequest.end();


	// 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.

Next challenge

Return to module overview