Add NSwag for automatic TypeScript API client generation

- Replace Swashbuckle with NSwag.AspNetCore + NSwag.MSBuild
- Configure OpenAPI document in Program.cs via AddOpenApiDocument
- Add nswag.json: aspNetCoreToOpenApi → Axios TypeScript client
- Post-build target uses NSwagExe_Net80 to run on correct runtime
- Client generated to frontend/src/api/apiClient.ts (gitignored)
- Add axios to frontend dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Martin Švrčina 2026-03-17 00:36:30 +01:00
parent 6b58dfa4e4
commit 982b6d5fa6
6 changed files with 3012 additions and 14 deletions

5
.gitignore vendored
View File

@ -19,6 +19,11 @@ appsettings.Local.json
publish/
out/
# ========================
# Generated API client (regenerated on each backend build)
# ========================
frontend/src/api/
# ========================
# Vue / Node
# ========================

View File

@ -7,13 +7,21 @@
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ClaudeTest.Application\ClaudeTest.Application.csproj" />
<ProjectReference Include="..\ClaudeTest.Infrastructure\ClaudeTest.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NSwag.AspNetCore" Version="14.*" />
<PackageReference Include="NSwag.MSBuild" Version="14.*">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<Target Name="NSwag" AfterTargets="Build">
<Exec Command="$(NSwagExe_Net80) run nswag.json /variables:Configuration=$(Configuration)" WorkingDirectory="$(ProjectDir)" />
</Target>
</Project>

View File

@ -1,25 +1,22 @@
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddOpenApiDocument(config =>
{
config.Title = "ClaudeTest API";
config.Version = "v1";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
app.UseOpenApi();
app.UseSwaggerUi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,85 @@
{
"runtime": "Net80",
"defaultVariables": null,
"documentGenerator": {
"aspNetCoreToOpenApi": {
"project": "ClaudeTest.API.csproj",
"documentName": "v1",
"msBuildProjectExtensionsPath": null,
"configuration": null,
"runtime": null,
"targetFramework": null,
"noBuild": true,
"msBuildOutputPath": null,
"verbose": false,
"workingDirectory": null,
"aspNetCoreEnvironment": null,
"output": null,
"newLineBehavior": "Auto"
}
},
"codeGenerators": {
"openApiToTypeScriptClient": {
"className": "{controller}Client",
"moduleName": "",
"namespace": "",
"typeScriptVersion": 4.3,
"template": "Axios",
"promiseType": "Promise",
"httpClass": "HttpClient",
"withCredentials": false,
"useSingletonProvider": false,
"injectionTokenType": "OpaqueToken",
"rxJsVersion": 6.0,
"dateTimeType": "Date",
"nullValue": "Undefined",
"generateClientClasses": true,
"generateClientInterfaces": true,
"generateOptionalParameters": true,
"exportTypes": true,
"wrapDtoExceptions": false,
"exceptionClass": "ApiException",
"clientBaseClass": null,
"wrapResponses": false,
"wrapResponseMethods": [],
"generateResponseClasses": true,
"responseClass": "SwaggerResponse",
"protectedMethods": [],
"configurationClass": null,
"useTransformOptionsMethod": false,
"useTransformResultMethod": false,
"generateDtoTypes": true,
"operationGenerationMode": "MultipleClientsFromOperationId",
"includedOperationIds": [],
"excludedOperationIds": [],
"markOptionalProperties": true,
"generateCloneMethod": false,
"typeStyle": "Class",
"enumStyle": "Enum",
"useLeafType": false,
"classTypes": [],
"extendedClasses": [],
"extensionCode": null,
"generateDefaultValues": true,
"excludedTypeNames": [],
"excludedParameterNames": [],
"handleReferences": false,
"generateTypeCheckFunctions": false,
"generateConstructorInterface": true,
"convertConstructorInterfaceData": false,
"importRequiredTypes": true,
"useGetBaseUrlMethod": false,
"baseUrlTokenName": "API_BASE_URL",
"queryNullValue": "",
"useAbortSignal": false,
"inlineNamedDictionaries": false,
"inlineNamedAny": false,
"includeHttpContext": false,
"templateDirectory": null,
"serviceHost": null,
"serviceSchemes": null,
"output": "../../frontend/src/api/apiClient.ts",
"newLineBehavior": "Auto"
}
}
}

2902
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@
"dependencies": {
"@fontsource/roboto": "^5.2.10",
"@mdi/font": "7.4.47",
"axios": "^1.13.6",
"vue": "^3.5.30",
"vuetify": "^4.0.2"
},