Challenge #3: Parsing Responses
Your Rot13Client
makes an HTTP request, but it doesn’t do anything with the response. In this challenge, you’ll parse the response and return the encoded text to your caller. You’ll only handle the happy path for this challenge.
Instructions
1. Update the transformAsync()
test helper to support specifying HTTP parameters:
- Update the
transformAsync()
to the following signature:const { response, httpRequests } = await transformAsync({ port, // the port to pass to rot13Client.transformAsync() text, // the text to pass to rot13Client.transformAsync() correlationId, // the correlation ID to pass to rot13Client.transformAsync() rot13ServiceStatus, // the HTTP status returned by the simulated ROT-13 service rot13ServiceHeaders, // the HTTP headers returned by the simulated ROT-13 service rot13ServiceBody, // the HTTP body returned by the simulated ROT-13 service });
- Provide defaults for the
transformAsync()
parameters:const { response, httpRequests } = await transformAsync({ port = IRRELEVANT_PORT, text = IRRELEVANT_TEXT, correlationId = IRRELEVANT_CORRELATION_ID, rot13ServiceStatus = VALID_ROT13_STATUS, rot13ServiceHeaders = VALID_ROT13_HEADERS, rot13ServiceBody = VALID_ROT13_BODY, } = {});
- Configure the
/rot13/transform
endpoint to returnVALID_ROT13_STATUS
,VALID_ROT13_HEADERS
, andVALID_ROT13_BODY
.
2. Implement the "parses response"
test:
- Assert that the
rot13Client.transformAsync()
response isVALID_RESPONSE
.
3. Update rot13Client.transformAsync()
:
- Parse HTTP response’s body and return the transformed text. The body is a JSON-encoded object:
{ transformed: "the encoded text" }
- Don’t worry about edge cases—just program the happy path.
Remember to commit your changes when you’re done.
API Documentation
const client = HttpClient.createNull({ endpoints });
Create a Nulled HttpClient
that simulates a response to the specified endpoints. The name of each endpoint is the URL and the value is an array of simulated responses. Each response consists of status, headers, and body. The next response in the array is returned for each request.
const client = HttpClient.createNull({
"/rot13/transform": [{
status, // number
headers, // object with a name/value pair for each header
body, // string
}],
});
- endpoints
(number)
- simulated responses for each endpoint - returns httpClient
(HttpClient)
- the HTTP client
const object = JSON.parse(json);
Convert a JSON-encoded string to a variable (typically an object).
- json
(string)
- the JSON string - returns object
(object)
- the variable - throws
(Error)
- throws an error if the string could not be parsed
assert.equal(actual, expected)
;
Assert that two variables are strictly equal (===
). This is usually used for primitive types. To compare objects and arrays, including their contents, use assert.deepEqual()
instead.
- actual
(any)
- the actual value - expected
(any)
- the expected value
const VALID_ROT13_STATUS = 200;
This constant is available in the test code. Use it when you need to simulate a valid HTTP response from the ROT-13 service.
const VALID_ROT13_HEADERS = { "content-type": "application/json" };
This constant is available in the test code. Use it when you need to simulate a valid HTTP response from the ROT-13 service.
const VALID_ROT13_BODY = JSON.stringify({ transformed: VALID_RESPONSE });
This constant is available in the test code. Use it when you need to simulate a valid HTTP response from the ROT-13 service.
const VALID_RESPONSE = "transformed_text";
This constant is available in the test code. It corresponds to the response rot13Client.transformAsync()
should return when it receives VALID_ROT13_BODY
from the ROT-13 service.
JavaScript Primers
Hints
Modify the transformAsync()
helper:
1
The transformAsync()
helper needs to return a response
variable that contains the result of calling rot13Client.transformAsync()
.
You can use object shorthand to do so.
async function transformAsync({ port, text, correlationId }) {
const httpClient = HttpClient.createNull();
const httpRequests = httpClient.trackRequests();
const rot13Client = new Rot13Client(httpClient);
const response = await rot13Client.transformAsync(port, text, correlationId);
return { response, httpRequests };
}
2
Add the ROT-13 parameters to the helper. (rot13ServiceStatus
, rot13ServiceHeaders
, and rot13ServiceBody
.) Add the default function parameters at the same time.
async function transformAsync({
port = IRRELEVANT_PORT,
text = IRRELEVANT_TEXT,
correlationId = IRRELEVANT_CORRELATION_ID,
rot13ServiceStatus = VALID_ROT13_STATUS,
rot13ServiceHeaders = VALID_ROT13_HEADERS,
rot13ServiceBody = VALID_ROT13_BODY,
} = {}) {
const httpClient = HttpClient.createNull();
const httpRequests = httpClient.trackRequests();
const rot13Client = new Rot13Client(httpClient);
const response = await rot13Client.transformAsync(port, text, correlationId);
return { response, httpRequests };
}
TypeScript no longer needs type annotations, because of the defaults, so the TypeScript code is the same as the JavaScript code.
3
Configure the HTTP response.
You can do that with HttpClient.createNull()
.
It’s configured with an object that has endpoints (URLs) as keys and an array of responses as values. The endpoint to configure is /rot13/transform
.
async function transformAsync({
port = IRRELEVANT_PORT,
text = IRRELEVANT_TEXT,
correlationId = IRRELEVANT_CORRELATION_ID,
rot13ServiceStatus = VALID_ROT13_STATUS,
rot13ServiceHeaders = VALID_ROT13_HEADERS,
rot13ServiceBody = VALID_ROT13_BODY,
} = {}) {
const httpClient = HttpClient.createNull({
"/rot13/transform": {
status: rot13ServiceStatus,
headers: rot13ServiceHeaders,
body: rot13ServiceBody,
},
});
const httpRequests = httpClient.trackRequests();
const rot13Client = new Rot13Client(httpClient);
const response = await rot13Client.transformAsync(port, text, correlationId);
return { response, httpRequests };
}
Implement the "parses response"
test:
4
Call the production code in your test.
You can use the transformAsync()
helper.
Although the values needed by the test are the same as the helper’s defaults, that’s just a coincidence. Protect against future changes and make your test more clear by making the values explicit.
it("parses response", async () => {
const { response } = await transformAsync({
rot13ServiceStatus: VALID_ROT13_STATUS,
rot13ServiceHeaders: VALID_ROT13_HEADERS,
rot13ServiceBody: VALID_ROT13_BODY,
});
});
5
You’re ready to assert that the reponse is correct.
You can use assert.equal()
to make the comparison.
it("parses response", async () => {
const { response } = await transformAsync({
rot13ServiceStatus: VALID_ROT13_STATUS,
rot13ServiceHeaders: VALID_ROT13_HEADERS,
rot13ServiceBody: VALID_ROT13_BODY,
});
assert.equal(response, VALID_RESPONSE);
});
6
The test is ready to run.
It should fail, saying that it got an undefined
response.
That’s because the production code isn’t returning a value.
Implement the production code:
7
Your production code needs to parse and return the HTTP response.
The response is a JSON-encoded object containing a transformed
field.
You can use JSON.parse()
to convert the string into an object.
async transformAsync(port, text, correlationId) {
const response = await this._httpClient.requestAsync({
host: HOST,
port,
method: "POST",
path: TRANSFORM_ENDPOINT,
headers: {
"content-type": "application/json",
"x-correlation-id": correlationId,
},
body: JSON.stringify({ text }),
});
const parsedBody = JSON.parse(response.body);
return parsedBody.transformed;
}
Complete Solution
Test code:
it("parses response", async () => {
const { response } = await transformAsync({
rot13ServiceStatus: VALID_ROT13_STATUS,
rot13ServiceHeaders: VALID_ROT13_HEADERS,
rot13ServiceBody: VALID_ROT13_BODY,
});
assert.equal(response, VALID_RESPONSE);
});
// ...
async function transformAsync({
port = IRRELEVANT_PORT,
text = IRRELEVANT_TEXT,
correlationId = IRRELEVANT_CORRELATION_ID,
rot13ServiceStatus = VALID_ROT13_STATUS,
rot13ServiceHeaders = VALID_ROT13_HEADERS,
rot13ServiceBody = VALID_ROT13_BODY,
} = {}) {
const httpClient = HttpClient.createNull({
"/rot13/transform": {
status: rot13ServiceStatus,
headers: rot13ServiceHeaders,
body: rot13ServiceBody,
},
});
const httpRequests = httpClient.trackRequests();
const rot13Client = new Rot13Client(httpClient);
const response = await rot13Client.transformAsync(port, text, correlationId);
return { response, httpRequests };
}
Production code (JavaScript):
async transformAsync(port, text, correlationId) {
const response = await this._httpClient.requestAsync({
host: HOST,
port,
method: "POST",
path: TRANSFORM_ENDPOINT,
headers: {
"content-type": "application/json",
"x-correlation-id": correlationId,
},
body: JSON.stringify({ text }),
});
const parsedBody = JSON.parse(response.body);
return parsedBody.transformed;
}
Production code (TypeScript):
async transformAsync(
port: number,
text: string,
correlationId: string,
): Promise<string> {
const response = await this._httpClient.requestAsync({
host: HOST,
port,
method: "POST",
path: TRANSFORM_ENDPOINT,
headers: {
"content-type": "application/json",
"x-correlation-id": correlationId,
},
body: JSON.stringify({ text }),
});
const parsedBody = JSON.parse(response.body);
return parsedBody.transformed;
}