Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support response headers #49

Merged
merged 4 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ await api.addPet(new Pet() {

// fetch the pet
var result = await api.getPetById(1);
Console.WriteLine(result.name);
Console.WriteLine(result.Data.name);
```

Run from the terminal as follows:
Expand Down
2 changes: 1 addition & 1 deletion helpers/createReturnStatement.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const createReturnStatement = (responseSchema) => {
returnStatement = `JsonSerializer.Deserialize<${responseType}>(responseBody)`;
}

return new Handlebars.SafeString(`return ${returnStatement};`);
return new Handlebars.SafeString(returnStatement);
};

module.exports = createReturnStatement;
16 changes: 13 additions & 3 deletions template/ApiClient.cs.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ using System.Web;
{{#each _sortedParameters}}
/// <param name="{{name}}">{{description}}</param>
{{/each}}
public async Task{{#if _response.schema}}<{{safeTypeConvert _response.schema}}>{{/if}} {{operationId}}(
public async Task<HttpResponse<{{#if _response.schema}}{{safeTypeConvert _response.schema}}{{else}}object{{/if}}>> {{operationId}}(
{{~#each _sortedParameters ~}}
{{~nullableTypeConvert schema _optional}} {{toParamName name ~}}
{{~#if (hasDefault schema.default)}} = {{{quoteIfString schema.default}}}{{/if ~}}
Expand All @@ -72,11 +72,21 @@ using System.Web;
response.EnsureSuccessStatusCode();
{{#if _response.schema}}
var responseBody = await response.Content.ReadAsStringAsync();
{{createReturnStatement _response.schema}}
return new HttpResponse<{{safeTypeConvert _response.schema}}>(
{{createReturnStatement _response.schema}},
response.StatusCode,
response.Headers
);
{{else}}
return new HttpResponse<object>(
null,
response.StatusCode,
response.Headers
);
{{/if}}
}
{{else}}
public Task{{#if _response.schema}}<{{safeTypeConvert _response.schema}}>{{/if}} {{operationId}}({{#each _sortedParameters}}{{nullableTypeConvert schema _optional}} {{name}}{{#if schema.default}} = {{{quoteIfString schema.default}}}{{/if}}{{#unless @last}}, {{/unless}}{{/each}})
public Task{{#if _response.schema}}<HttpResponse<{{safeTypeConvert _response.schema}}>>{{/if}} {{operationId}}({{#each _sortedParameters}}{{nullableTypeConvert schema _optional}} {{name}}{{#if schema.default}} = {{{quoteIfString schema.default}}}{{/if}}{{#unless @last}}, {{/unless}}{{/each}})
{
throw new NotImplementedException("Operation '{{operationId}}' most likely does not support json encoded requests which are not supported by openapi forge.");
}
Expand Down
30 changes: 30 additions & 0 deletions template/HttpResponse.cs.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Net;
using System.Net.Http.Headers;

{{>namespace}} {
/// <summary>
/// Represents an HTTP response.
/// </summary>
public class HttpResponse<T> {
public HttpResponse(T data, HttpStatusCode statusCode, HttpResponseHeaders headers) {
Data = data;
StatusCode = statusCode;
Headers = headers;
}

/// <summary>
/// Gets the typed response.
/// </summary>
public T Data { get; private set; }

/// <summary>
/// Gets the HTTP status code.
/// </summary>
public HttpStatusCode StatusCode { get; private set; }

/// <summary>
/// Gets the returned HTTP headers.
/// </summary>
public HttpResponseHeaders Headers { get; private set; }
}
}
2 changes: 1 addition & 1 deletion template/IApiClient.cs.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ using System.Threading.Tasks;
{{#each _sortedParameters}}
/// <param name="{{name}}">{{description}}</param>
{{/each}}
public Task{{#if _response.schema}}<{{safeTypeConvert _response.schema}}>{{/if}} {{operationId}}(
public Task<HttpResponse<{{#if _response.schema}}{{safeTypeConvert _response.schema}}{{else}}object{{/if}}>> {{operationId}}(
{{~#each _sortedParameters ~}}
{{~nullableTypeConvert schema _optional}} {{toParamName name ~}}
{{~#if (hasDefault schema.default)}} = {{{quoteIfString schema.default}}}{{/if ~}}
Expand Down
20 changes: 0 additions & 20 deletions tests/FeaturesTests/Components.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,6 @@ public Components(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
{
}

[When(@"calling the method (\w+) and the server responds with")]
public async Task CallWithResponse(string methodName, DocString response)
{
await CallMethod(methodName, null, response.Content);
}

[Then(@"the response should be of type (\w+)")]
public void CheckResponseType(string type)
{
Assert.EndsWith(type, _actual.GetType().Name);
}

[And(@"the response should have a property (id|value) with value (.+)")]
public void CheckResponseIdProperty(string propName, string propValue)
{
var propInfo = _actual.GetType().GetProperty(propName);
Assert.NotNull(propInfo);
Assert.Equal(propValue, propInfo.GetValue(_actual).ToString());
}

[When(@"calling the method (\w+) with (?:object|array|parameters) ""(.+)""")]
public async Task CallMethodWithParameters(string methodName, string rawParameters)
{
Expand Down
13 changes: 0 additions & 13 deletions tests/FeaturesTests/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,9 @@ namespace Features
[FeatureFile(nameof(Configuration) + Constants.FeatureFileExtension)]
public sealed class Configuration : FeatureBase
{
private int? _serverIndex;

public Configuration(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
{
}

[When(@"calling the method (\w+) without params")]
public async Task CallWithoutParameters(string methodName)
{
await CallMethod(methodName, null, null, _serverIndex);
}

[When(@"selecting the server at index (\d)")]
public void SelectedServerIndexIsOne(string serverIndex)
{
_serverIndex = new Nullable<int>(int.Parse(serverIndex));
}
}
}
13 changes: 0 additions & 13 deletions tests/FeaturesTests/CookieParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,6 @@ public CookieParams(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
{
}

[When(@"calling the method (\w+) with (object|array|parameters) ""(.+)""")]
public async Task CallMethodWithStringParameters(string methodName, string paramType, string parametersString)
{
var parameters = paramType switch
{
"object" => new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) },
"array" => new object[] { parametersString.Split(",") },
_ => parametersString.Split(",")
};

await CallMethod(methodName, parameters);
}

[Then(@"the request header should have a cookie property with value (.+)")]
public void CheckCookiePropertyAsync(string headerProperty)
{
Expand Down
102 changes: 0 additions & 102 deletions tests/FeaturesTests/Deserialisation.cs

This file was deleted.

82 changes: 80 additions & 2 deletions tests/FeaturesTests/FeatureBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ public abstract class FeatureBase : Xunit.Gherkin.Quick.Feature
{
protected readonly ITestOutputHelper _testOutputHelper;

private int? _serverIndex;

private readonly Dictionary<string, string> _responses = new Dictionary<string, string>();

protected readonly TestHelper _testHelper;

protected readonly MockHttpMessageHandler _mockHttp;

protected readonly string _testId;

protected object _actual;
protected dynamic _actual;

protected string _docStringContent;

Expand All @@ -33,6 +37,80 @@ public FeatureBase(ITestOutputHelper testOutputHelper)
_mockHttp = new MockHttpMessageHandler();
}

[When(@"calling the method (\w+) and the server responds with")]
public async Task CallWithResponse(string methodName, DocString response)
{
_responses[methodName.Replace("Response", string.Empty)] = response.Content;

_mockHttp.When("*").Respond((HttpRequestMessage request) =>
{
return Task.FromResult<HttpResponseMessage>(
new HttpResponseMessage
{
StatusCode = System.Net.HttpStatusCode.OK,
Content = new StringContent(_responses[request.RequestUri.LocalPath.Split("/").Last()])
});
});

var request = _mockHttp.When("*").Respond("application/json", response.Content);
var apiClient = _testHelper.CreateApiClient(_mockHttp.ToHttpClient());

var methodInfo = apiClient.GetType().GetMethod(methodName);

dynamic awaitable = methodInfo.Invoke(apiClient, null);
await awaitable;
_actual = awaitable.GetAwaiter().GetResult();
}

[Then(@"the response should be of type (\w+)")]
public void CheckResponseType(string type)
{
Assert.EndsWith(type, _actual.Data.GetType().Name);
}

[When(@"calling the method (\w+) without params")]
public async Task CallWithoutParameters(string methodName)
{
await CallMethod(methodName, null, null, _serverIndex);
}

[When(@"calling the method (\w+) with object (.+)")]
public async Task CallMethodWithStringObject(string methodName, string parametersString)
{
var parameters = new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) };

await CallMethod(methodName, parameters);
}

[When(@"calling the method (\w+) with (object|array|parameters) ""(.+)""")]
public async Task CallMethodWithStringParameters(string methodName, string paramType, string parametersString)
{
var parameters = paramType switch
{
"object" => new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) },
"array" => new object[] { parametersString.Split(",") },
_ => parametersString.Split(",")
};

await CallMethod(methodName, parameters);
}

[When(@"selecting the server at index (\d)")]
public void SelectedServerIndexIsOne(string serverIndex)
{
_serverIndex = new Nullable<int>(int.Parse(serverIndex));
}


[Then(@"the response should have a property (.+) with value (.+)")]
[And(@"the response should have a property (.+) with value (.+)")]
public void CheckResponseIdProperty(string propName, string propValue)
{
var propInfo = _actual.Data.GetType().GetProperty(propName);
Assert.NotNull(propInfo);
Assert.Equal(propValue, propInfo.GetValue(_actual.Data).ToString());
}

[Given(@"an API with the following specification")]
public virtual void Generate(DocString schema)
{
Expand All @@ -46,7 +124,7 @@ public virtual void Generate(DocString schema)
public void CheckRequestUri(string url)
{
var expected = new Uri(url);
var actual = new Uri(_actual.ToString());
var actual = new Uri(_actual.Data.ToString());
Assert.Equal(expected.Host, actual.Host);
Assert.Equal(expected.AbsolutePath, actual.AbsolutePath);
var separators = new[] { '?', '&' };
Expand Down
13 changes: 0 additions & 13 deletions tests/FeaturesTests/HeaderParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,6 @@ public HeaderParams(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
{
}

[When(@"calling the method (\w+) with (object|array|parameters) ""(.+)""")]
public async Task CallMethodWithStringParameters(string methodName, string paramType, string parametersString)
{
var parameters = paramType switch
{
"object" => new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) },
"array" => new object[] { parametersString.Split(",") },
_ => parametersString.Split(",")
};

await CallMethod(methodName, parameters);
}

[Then(@"the request should have a header property with value (.+)")]
public void CheckHeaderPropertyAsync(string headerProperty)
{
Expand Down
Loading