Start learning free

LESSON 142 OF 173 · BACKEND: TESTS AND RUNNING IT

A Request ID

Practice

When many customers order at the same time, their log lines get mixed together. When one of them writes that their order went wrong, you can't tell which lines are theirs. The fix is a request ID: a random name made for each request, sent back with the answer in a header and written in every log line about that request. The customer gives you the id, and you search the log for it.

ASP.NET Core can run code around every request. A function you add with app.Use, a middleware, gets the request's context and next: its lines above await next(context); run before the route, and next runs the route. Values that belong to the request being handled go in context.Items: each request gets its own. For example, to remember when each request started:

app.Use(async (HttpContext context, RequestDelegate next) => {
    context.Items["started"] = DateTime.UtcNow;
    await next(context);
});

A route that takes an HttpContext context parameter gets the same request's context, so it can read context.Items["started"]. Headers go out before the answer's body, so set them above next. For the id itself, Guid.NewGuid().ToString("N") makes 32 random characters of 0–9 and a–f, practically never the same twice. A test can't know a random id in advance, so it checks a part: Assert.Contains(part, text) passes when part is found inside text.

The check sends four requests. The ids are random, so it shows them as <id 1>, <id 2> and so on:

POST /orders {"product_id": 1, "quantity": 2}  →  201 | X-Request-Id: <id 1>
  log: Information: [<id 1>] Order placed: 2 x Mug, total 24
POST /orders {"product_id": 3, "quantity": 1}  →  201 | X-Request-Id: <id 2>
  log: Information: [<id 2>] Order placed: 1 x Lamp, total 29
POST /orders {"product_id": 99, "quantity": 1}  →  404 | X-Request-Id: <id 3>
GET /about  →  404 | X-Request-Id: <id 4>

Your task: add a middleware that makes an id for every request, keeps it in context.Items["request_id"], sends it back in the X-Request-Id header and passes the request on. Write the id in square brackets at the start of the order's log line. Then write the test "log has request id", which checks that the header's id is in the log line. The check runs it on the shop, where it must pass, and on two broken copies, one that leaves the id out of the log and one that makes a second id for the answer, where it must fail.


Assignment
Follow the Coding Tutorial to give every request an id, put it in the answer's header and in the order's log line, and test that the two match.


Hint
Set the header above await next(context);: once the route has sent the answer, it's too late. In the test, declare HttpResponseMessage response; above the using (logs) block, so the answer is still there after the block, where logs.Output holds the lines.


STEP 1 OF 11
    Ctrl + Enter to check