Challenge #8: Design Changes

Because you have State-Based Tests, you can change the design of your code without changing your tests. In this challenge, you’ll demonstrate that capability by changing your usage of Rot13Client.

Instructions

  1. Change HomePageController.postAsync() to call rot13Client.transform() instead of rot13Client.transformAsync().

Remember to commit your changes when you’re done.

API Documentation

const { transformPromise, cancelFn } = rot13Client.transform(port, text, correlationId);

Call the ROT-13 service. This is just like transformAsync(), except that it returns multiple values. Use it like this:

const { transformPromise } = rot13Client.transform(port, text, correlationId);
const transformedText = await transformPromise;
  • port (number) - the port of the ROT-13 service
  • text (string) - the text to send to the ROT-13 service
  • correlationId (string) - a unique ID representing the user’s request
  • returns transformPromise (Promise<string>) - the encoded text returned by the ROT-13 service
  • returns cancelFn (() => void) - call this function to cancel the request

JavaScript Primers

No new concepts.

Hints

1
In your production code, call transform() instead of transformAsync().
It’s really that easy.
async function transformAsync(rot13Client, config, log, userInput) {
	try {
		const { transformPromise } = rot13Client.transform(
			config.rot13ServicePort,
			userInput,
			config.correlationId,
		);
		return await transformPromise;
	}
	catch (err) {
		log.emergency({
			message: "ROT-13 service error",
			error: err,
		});
		return null;
	}
}

Complete Solution

Production code (JavaScript):
export class HomePageController {
	// ...

	async postAsync(request, config) {
		const log = config.log.bind({
			endpoint: ENDPOINT,
			method: "POST",
		});

		const userInput = await parseRequestBodyAsync(request, log);
		if (userInput === null) return homePageView.homePage();

		const output = await transformAsync(this._rot13Client, config, log, userInput);
		if (output === null) return homePageView.homePage("ROT-13 service failed");

		return homePageView.homePage(output);
	}

}

async function parseRequestBodyAsync(request, log) {
	const form = await request.readBodyAsUrlEncodedFormAsync();
	const textFields = form[INPUT_FIELD_NAME];

	try {
		if (textFields === undefined) throw new Error(`'${INPUT_FIELD_NAME}' form field not found`);
		if (textFields.length !== 1) throw new Error(`should only be one '${INPUT_FIELD_NAME}' form field`);

		return textFields[0];
	}
	catch (err) {
		log.monitor({
			message: "form parse error",
			error: err.message,
			form,
		});
		return null;
	}
}

async function transformAsync(rot13Client, config, log, userInput) {
	try {
		const { transformPromise } = rot13Client.transform(
			config.rot13ServicePort,
			userInput,
			config.correlationId,
		);
		return await transformPromise;
	}
	catch (err) {
		log.emergency({
			message: "ROT-13 service error",
			error: err,
		});
		return null;
	}
}
Production code (TypeScript):
export class HomePageController {
	// ...

	async postAsync(request: HttpServerRequest, config: WwwConfig): Promise<HttpServerResponse> {
		const log = config.log.bind({
			endpoint: ENDPOINT,
			method: "POST",
		});

		const userInput = await parseRequestBodyAsync(request, log);
		if (userInput === null) return homePageView.homePage();

		const output = await transformAsync(this._rot13Client, config, log, userInput);
		if (output === null) return homePageView.homePage("ROT-13 service failed");

		return homePageView.homePage(output);
	}

}

async function parseRequestBodyAsync(request: HttpServerRequest, log: Log): Promise<string | null> {
	const form = await request.readBodyAsUrlEncodedFormAsync();
	const textFields = form[INPUT_FIELD_NAME];

	try {
		if (textFields === undefined) throw new Error(`'${INPUT_FIELD_NAME}' form field not found`);
		if (textFields.length !== 1) throw new Error(`should only be one '${INPUT_FIELD_NAME}' form field`);

		return textFields[0] as string;
	}
	catch (err) {
		log.monitor({
			message: "form parse error",
			error: err.message,
			form,
		});
		return null;
	}
}

async function transformAsync(
	rot13Client: Rot13Client,
	config: WwwConfig,
	log: Log,
	userInput: string,
): Promise<string | null> {
	try {
		const { transformPromise } = rot13Client.transform(
			config.rot13ServicePort,
			userInput,
			config.correlationId,
		);
		return await transformPromise;
	}
	catch (err) {
		log.emergency({
			message: "ROT-13 service error",
			error: err,
		});
		return null;
	}
}

Test code is unchanged.

Next challenge

Return to module overview