Skip to content

Commit

Permalink
Add a better exception message (#51)
Browse files Browse the repository at this point in the history
* Fixes #50.

* Fixed typos and normalized capitalization.
  • Loading branch information
mwadams authored Jul 9, 2020
1 parent dacecfe commit b402639
Show file tree
Hide file tree
Showing 5 changed files with 493 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,78 +4,137 @@

namespace Menes.Internal
{
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.OpenApi.Exceptions;
using Microsoft.OpenApi.Models;

/// <inheritdoc/>
public class OutputBuilderNotFoundException : OpenApiException
public class OutputBuilderNotFoundException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="OutputBuilderNotFoundException"/> class.
/// </summary>
/// <param name="result">The result being processed.</param>
/// <param name="operation">The operation being executed.</param>
public OutputBuilderNotFoundException(object result, OpenApiOperation operation)
: base(BuildMessage(result, operation))
{
this.RawResult = result;
this.OpenApiResult = result as OpenApiResult;
this.Operation = operation;
}

/// <summary>
/// Gets the OpenApiResult.
/// </summary>
public OpenApiResult? OpenApiResult { get; }

/// <summary>
/// Gets the Operation.
/// </summary>
public OpenApiOperation Operation { get; }

/// <summary>
/// Gets the raw Result.
/// </summary>
public object RawResult { get; }

private static string BuildMessage(object result, OpenApiOperation operation)
{
var sb = new StringBuilder();
bool firstTime = true;
sb.Append("Expecting a Response with a Status Code in the range of ");
bool appendComma = false;
sb.Append("Expecting a response with a status code of: ");

foreach (KeyValuePair<string, OpenApiResponse> response in operation.Responses)
{
if (!firstTime)
if (appendComma)
{
sb.Append(", ");
}

sb.Append(" ");
sb.Append(response.Key);
sb.Append(" - ");
sb.Append(response.Value.Description);
sb.Append(" ");
if (!string.IsNullOrWhiteSpace(response.Value.Description))
{
sb.Append(" - ");
sb.Append(response.Value.Description);
}

firstTime = false;
appendComma = true;
}

sb.Append(". Recieved a Response with Status Code of ");
sb.Append(".");

if (this.RawResult is OpenApiResult oaiResult)
if (result is OpenApiResult oaiResult)
{
this.OpenApiResult = oaiResult;

sb.AppendLine();
sb.Append("Received a response with a status code of: ");
sb.Append(oaiResult.StatusCode);
}
else
{
sb.Append(this.RawResult.GetType());
}
sb.Append(".");

sb.Append(". Check that your Operation implementation return value matches the OpenAPI operation response definition.");
sb.AppendLine();

this.Message = sb.ToString();
}
if (oaiResult.Results.Count == 0)
{
sb.Append("There were no content result media types provided.");
}
else
{
sb.Append("The following content result media types were provided: ");
appendComma = false;
foreach (string item in oaiResult.Results.Keys)
{
if (appendComma)
{
sb.Append(", ");
}

/// <inheritdoc cref="Message"/>
public new string Message { get; }
appendComma = true;
sb.Append(item);
}
}

/// <summary>
/// Gets the OpenApiResult.
/// </summary>
public OpenApiResult? OpenApiResult { get; }
sb.AppendLine();

/// <summary>
/// Gets the Operation.
/// </summary>
public OpenApiOperation Operation { get; }
sb.Append("One of the following content result media types was expected: ");
sb.AppendLine();
foreach (KeyValuePair<string, OpenApiResponse> item in operation.Responses)
{
sb.Append(item.Key);
sb.Append(": ");

/// <summary>
/// Gets the raw Result.
/// </summary>
public object RawResult { get; }
if (item.Value.Content.Count == 0)
{
sb.Append("No content.");
continue;
}

appendComma = false;

foreach (string mediaType in item.Value.Content.Keys)
{
if (appendComma)
{
sb.Append(", ");
}

sb.Append(mediaType);
appendComma = true;
}

sb.AppendLine();
}
}
else
{
sb.AppendLine();
sb.Append("Received a response with a type of ");
sb.Append(result.GetType());
}

sb.AppendLine();
sb.Append("Check that your service implementation return value matches the OpenAPI OperationResponse definition.");
return sb.ToString();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@perScenarioContainer

Feature: HttpResultBuilderErrorDetection
In order to discover that I've made a mistake
As an OpenApi service developer
I want to be told when my service is not providing an expected response

Scenario: Operation returns an OpenApiResult with no matching status code
Given I have an OpenApiOperation
And I have an OpenApiResult with a 201 response
When I pass the OpenApiOperation and OpenApiResult to HttpRequestResultBuilder.BuildResult
Then it should throw an OutputBuilderNotFoundException

Scenario: Operation returns an OpenApiResult with no matching media type
Given I have an OpenApiOperation
And I have an OpenApiResult with a 200 response
When I pass the OpenApiOperation and OpenApiResult to HttpRequestResultBuilder.BuildResult
Then it should throw an OutputBuilderNotFoundException

Scenario: Operation returns an OpenApiResult with matching media type and status code
Given I have an OpenApiOperation
And I have an OpenApiResult with a 200 response and an "application/hal+json" body
When I pass the OpenApiOperation and OpenApiResult to HttpRequestResultBuilder.BuildResult
Then it should not throw an OutputBuilderNotFoundException

Scenario: Operation returns an OpenApiResult with a mismatched media type
Given I have an OpenApiOperation
And I have an OpenApiResult with a 200 response and an "application/json" body
When I pass the OpenApiOperation and OpenApiResult to HttpRequestResultBuilder.BuildResult
Then it should throw an OutputBuilderNotFoundException
Loading

0 comments on commit b402639

Please sign in to comment.