Skip to content

Commit d312084

Browse files
Add demo API for integration tests
1 parent b702cb6 commit d312084

95 files changed

Lines changed: 2393 additions & 1538 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/launch.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
{
22
"version": "0.2.0",
33
"configurations": [
4+
{
5+
"name": ".NET Core Launch (console)",
6+
"type": "coreclr",
7+
"request": "launch",
8+
"preLaunchTask": "build",
9+
"program": "${workspaceFolder}/ReQuesty/bin/Debug/net10.0/requesty.dll",
10+
"args": [
11+
"generate",
12+
"--openapi", "${workspaceFolder}/Demo/ReQuesty.Demo.Api/ReQuesty.Demo.Api_main.json",
13+
"--output", "${workspaceFolder}/Demo/ReQuesty.Demo.IntegrationTest/ApiClient",
14+
"--class-name", "DemoApiClient",
15+
"--namespace-name", "ReQuesty.Demo.IntegrationTests.ApiClient",
16+
"--clean-output"
17+
],
18+
"cwd": "${workspaceFolder}",
19+
"stopAtEntry": false,
20+
"console": "internalConsole"
21+
},
422
{
523
"name": "Debug ReQuesty",
624
"type": "dotnet",

.vscode/tasks.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"type": "dotnet",
6+
"task": "build",
7+
"group": "build",
8+
"problemMatcher": [],
9+
"label": "build"
10+
}
11+
]
12+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System.Net;
2+
using System.Net.Mime;
3+
using System.Text.Json.Serialization;
4+
using Microsoft.AspNetCore.Mvc;
5+
6+
namespace ReQuesty.Demo.Api.Controllers.Base;
7+
8+
/// <summary>
9+
/// Base controller for the Demo API, everything should extend from this.
10+
/// </summary>
11+
[ApiController]
12+
[Route("[controller]")]
13+
[Consumes(MediaTypeNames.Application.Json)]
14+
[Produces(MediaTypeNames.Application.Json)]
15+
[ProducesResponseType<ProblemDetails>(StatusCodes.Status500InternalServerError)]
16+
public abstract class DemoControllerBase : ControllerBase
17+
{
18+
/// <summary>
19+
/// The type of data to return
20+
/// </summary>
21+
[JsonConverter(typeof(JsonStringEnumConverter))]
22+
public enum ReturnType
23+
{
24+
/// <summary>
25+
/// Return null
26+
/// </summary>
27+
Null,
28+
29+
/// <summary>
30+
/// Return random valid data for the type
31+
/// </summary>
32+
Random,
33+
34+
/// <summary>
35+
/// Return invalid data for the type
36+
/// </summary>
37+
Invalid
38+
}
39+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using ReQuesty.Demo.Api.Controllers.Base;
3+
4+
namespace ReQuesty.Demo.Api.Controllers;
5+
6+
/// <summary>
7+
///
8+
/// </summary>
9+
public class PrimativeReturnController : DemoControllerBase
10+
{
11+
/// <summary>
12+
/// Gets a string based on the specified return type.
13+
/// </summary>
14+
/// <returns></returns>
15+
[HttpGet("string", Name = "GetString")]
16+
[ProducesResponseType<string>(StatusCodes.Status200OK)]
17+
public async ValueTask<ActionResult<string>> GetStringAsync([FromQuery] ReturnType returnType)
18+
{
19+
return Ok(returnType switch
20+
{
21+
ReturnType.Null => null,
22+
ReturnType.Random => Guid.NewGuid().ToString(),
23+
ReturnType.Invalid => 123,
24+
_ => throw new()
25+
});
26+
}
27+
28+
/// <summary>
29+
/// Gets a nullable string based on the specified return type.
30+
/// </summary>
31+
/// <returns></returns>
32+
[HttpGet("nullable-string", Name = "GetNullableString")]
33+
[ProducesResponseType<string>(StatusCodes.Status200OK)] // <string?> isn't valid here
34+
public async ValueTask<ActionResult<string?>> GetNullableStringAsync([FromQuery] ReturnType returnType)
35+
{
36+
return Ok(returnType switch
37+
{
38+
ReturnType.Null => null,
39+
ReturnType.Random => Guid.NewGuid().ToString(),
40+
ReturnType.Invalid => 123,
41+
_ => throw new()
42+
});
43+
}
44+
45+
/// <summary>
46+
/// Gets an int based on the specified return type.
47+
/// </summary>
48+
/// <returns></returns>
49+
[HttpGet("int", Name = "GetInt")]
50+
[ProducesResponseType<int>(StatusCodes.Status200OK)]
51+
public async ValueTask<ActionResult<int>> GetIntAsync([FromQuery] ReturnType returnType)
52+
{
53+
return Ok(returnType switch
54+
{
55+
ReturnType.Null => null,
56+
ReturnType.Random => Random.Shared.Next(),
57+
ReturnType.Invalid => "not an int",
58+
_ => throw new()
59+
});
60+
}
61+
62+
/// <summary>
63+
/// Gets a nullable int based on the specified return type.
64+
/// </summary>
65+
/// <returns></returns>
66+
[HttpGet("nullable-int", Name = "GetNullableInt")]
67+
[ProducesResponseType<int?>(StatusCodes.Status200OK)]
68+
public async ValueTask<ActionResult<int?>> GetNullableIntAsync([FromQuery] ReturnType returnType)
69+
{
70+
return Ok(returnType switch
71+
{
72+
ReturnType.Null => null,
73+
ReturnType.Random => Random.Shared.Next(),
74+
ReturnType.Invalid => "not an int",
75+
_ => throw new()
76+
});
77+
}
78+
79+
/// <summary>
80+
/// Gets an Guid based on the specified return type.
81+
/// </summary>
82+
/// <returns></returns>
83+
[HttpGet("guid", Name = "GetGuid")]
84+
[ProducesResponseType<Guid>(StatusCodes.Status200OK)]
85+
public async ValueTask<ActionResult<Guid>> GetGuidAsync([FromQuery] ReturnType returnType)
86+
{
87+
return Ok(returnType switch
88+
{
89+
ReturnType.Null => null,
90+
ReturnType.Random => Guid.NewGuid(),
91+
ReturnType.Invalid => "not a guid",
92+
_ => throw new()
93+
});
94+
}
95+
96+
/// <summary>
97+
/// Gets a nullable guid based on the specified return type.
98+
/// </summary>
99+
/// <returns></returns>
100+
[HttpGet("nullable-guid", Name = "GetNullableGuid")]
101+
[ProducesResponseType<Guid?>(StatusCodes.Status200OK)]
102+
public async ValueTask<ActionResult<Guid?>> GetNullableGuidAsync([FromQuery] ReturnType returnType)
103+
{
104+
return Ok(returnType switch
105+
{
106+
ReturnType.Null => null,
107+
ReturnType.Random => Guid.NewGuid(),
108+
ReturnType.Invalid => "not a guid",
109+
_ => throw new()
110+
});
111+
}
112+
}

Demo/ReQuesty.Demo.Api/Program.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System.Text.Json;
2+
using System.Reflection;
3+
using System.Text.Json.Serialization;
4+
using Microsoft.OpenApi;
5+
6+
namespace ReQuesty.Demo.Api;
7+
8+
/// <summary>
9+
///
10+
/// </summary>
11+
public static class Program
12+
{
13+
/// <summary>
14+
///
15+
/// </summary>
16+
/// <param name="args"></param>
17+
public static async Task Main(string[] args)
18+
{
19+
await WebApplication.CreateBuilder(args).BuildBonesApi().RunBonesApiAsync();
20+
}
21+
22+
private static WebApplication BuildBonesApi(this WebApplicationBuilder builder)
23+
{
24+
25+
builder.WebHost.UseKestrel().ConfigureKestrel(kestrelServerOptions =>
26+
{
27+
kestrelServerOptions.AddServerHeader = false;
28+
});
29+
30+
builder.Services.AddControllers().AddJsonOptions(configure =>
31+
{
32+
configure.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
33+
configure.JsonSerializerOptions.WriteIndented = true;
34+
configure.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
35+
configure.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
36+
configure.JsonSerializerOptions.AllowTrailingCommas = true;
37+
configure.JsonSerializerOptions.RespectNullableAnnotations = true;
38+
});
39+
40+
builder.Services.AddEndpointsApiExplorer();
41+
builder.Services.AddOpenApi("main", options =>
42+
{
43+
options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1;
44+
});
45+
46+
return builder.Build();
47+
}
48+
49+
private static async Task RunBonesApiAsync(this WebApplication app)
50+
{
51+
app.UseCors(configurePolicy =>
52+
{
53+
configurePolicy
54+
.WithOrigins("*")
55+
.AllowAnyMethod()
56+
.AllowAnyHeader();
57+
});
58+
59+
app.UseExceptionHandler(opt => { });
60+
61+
if (app.Environment.IsDevelopment())
62+
{
63+
app.MapOpenApi();
64+
app.UseReDoc(c =>
65+
{
66+
c.DocumentTitle = "Demo API Documentation";
67+
c.SpecUrl = "/openapi/main.json";
68+
});
69+
}
70+
else
71+
{
72+
app.UseHttpsRedirection();
73+
}
74+
75+
app.UseAuthentication();
76+
app.UseAuthorization();
77+
app.MapControllers();
78+
79+
await app.RunAsync();
80+
}
81+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$schema": "https://json.schemastore.org/launchsettings.json",
3+
"profiles": {
4+
"http": {
5+
"commandName": "Project",
6+
"dotnetRunMessages": true,
7+
"launchBrowser": false,
8+
"applicationUrl": "http://localhost:5016",
9+
"environmentVariables": {
10+
"ASPNETCORE_ENVIRONMENT": "Development"
11+
}
12+
},
13+
"https": {
14+
"commandName": "Project",
15+
"dotnetRunMessages": true,
16+
"launchBrowser": false,
17+
"applicationUrl": "https://localhost:7146;http://localhost:5016",
18+
"environmentVariables": {
19+
"ASPNETCORE_ENVIRONMENT": "Development"
20+
}
21+
}
22+
}
23+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
5+
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
6+
<OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.3" />
11+
<PackageReference Include="Microsoft.Extensions.ApiDescription.Server" Version="10.0.3">
12+
<PrivateAssets>all</PrivateAssets>
13+
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
14+
</PackageReference>
15+
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
16+
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="10.1.0" />
17+
</ItemGroup>
18+
</Project>

0 commit comments

Comments
 (0)