2

I am developing a sort of middleware API, which is meant to connect to various systems. I am using the Flurl library to make requests to the individual systems.

One of these systems sometimes returns a custom header containing an error message, rather than just returning it in the response body (for reasons unbeknownst to me).

To return the correct error message, I am using Flurl's OnError event handler. I defined behaviour which checks the response for this custom header and, if found, extracts the decoded message and sets it as the response message of the request:

/// <summary>
/// Asynchronously checks responses from Thinkwise Indicium for TSFMessage headers and, if found,
/// decodes them and sets them as the actual error message of the response.
/// </summary>
/// <param name="request">The request of which the response must be checked for a Thinkwise message header.</param>
/// <returns>A Task.</returns>
public static async Task HandleThinkwiseErrorAsync(FlurlCall request)
{
  if (request.Response.Headers.TryGetFirst("TSFMessages", out var message))
  {
    var decodedMessage = JsonSerializer.Deserialize<ThinkwiseSoftwareFactoryMessage>(
                       Encoding.UTF8.GetString(Convert.FromBase64String(message)));

    var response = new HttpResponseMessage
    {
      StatusCode = HttpStatusCode.BadRequest,
      RequestMessage = new HttpRequestMessage(request.Request.Verb, request.Request.Url),
      Content = new StringContent(
        decodedMessage?.RawMessage.Split("\"")[1]
        ?? await request.Response.ResponseMessage.Content.ReadAsStringAsync(default))
      };

    request.HttpResponseMessage = response;
    request.ExceptionHandled = false;
  }
}

While I do have prior experience making HTTP requests using Flurl, configuring it like this is a first for me. I have configured Flurl as such in the DI container:

FlurlHttp.Configure(settings =>
{
  settings.OnErrorAsync = IndiciumFlurlHelper.HandleThinkwiseErrorAsync;
  settings.OnError = IndiciumFlurlHelper.HandleThinkwiseError; // Same as async method
});

I am having difficulty finding other articles, issues or SO questions which are trying to do similar things. I am probably making a rookie mistake somewhere, or just misunderstanding how the FlurlCall object is constructed and what the properties mean.

The problem I am running into is that, when I make a request I know should return an error message using this header, my middleware API returns a 204 response when it should return a 400 response with the error message in the body.

What am I doing wrong? The requests seem to work as expected, so I am pretty sure I am doing something wrong handling this response header this way.

Thanks in advance! Please do leave a comment, should you have further questions.

thebugsdontwork
  • 401
  • 3
  • 17

1 Answers1

0

This isn't going to work because 204 isn't an error status, so Flurl won't raise the OnError event and your handler won't get hit. Although you can configure which statuses Flurl should treat as errors, there's no way to specify that any status in the 2xx range should be considered an error.

You could handle the AfterCall event instead, although at that point it's too late to change the response. I'm not sure that's a great idea anyway, it's like pretending the server returned something that it didn't. Probably better to just take the actual response and handle it accordingly.

Of course another option is to skip event-handling entirely and just handle this condition inline. The event handlers are good for cross-cutting concerns like logging, but dealing with error conditions is often just part of your normal application flow. The introduction of FlurlResponse in the 3.0 should make this flow easier as well.

Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • The system I'm calling is not returning the 204, my middleware API returns the 204 if the request to the system is successful. However, if I send a request to the system I know for certain should return a 500 response, my middleware API still returns a 204 even though I configured it to return a 403 if the header is found. My apologies for not clearly stating that in the question. – thebugsdontwork Jul 10 '21 at 16:18
  • In that case I think you might need to post your middleware code. Have you tried stepping through it with the debugger to make sure the event handler gets hit and your middleware sees that response you're setting up? – Todd Menier Jul 11 '21 at 19:17
  • The posted code is the middleware code. It looks for a header and, if found, changes the response to a Bad Request instead of the Internal Server Error thrown by the system and sets the decoded message as the response body (or, that's what I try to do). I have not yet had the time to step through using the debugger, will do that and post an answer here if I find the fault. – thebugsdontwork Jul 12 '21 at 09:25