dotnet / dotnet/aspnetcore

OpenAPI document generation tool feedback

Open
#57,044 17 comments 4 reactions 0 assignees View on GitHub
area-commandlinetools feature-openapi
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

Playing around with the OpenAPI document CLI generation from [_Lint generated OpenAPI documents with Spectral_](https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis/aspnetcore-openapi?view=aspnetcore-9.0#lint-generated-openapi-documents-with-spectral) I found a few issues and rough edges. Rather than create lots of small issues I figured I'd list them all here, and they can be spun off into dedicated issues based on feedback/triage.

#### OpenApiDocumentsDirectory is not resolved to a full path

If `OpenApiDocumentsDirectory` is specified as a relative path (e.g. `dotnet build ./src/API /p:OpenApiGenerateDocuments=true /p:OpenApiDocumentsDirectory="./artifacts/openapi"`), the path is not resolved to a full path, and then ends up as a path relative to the tool invocation, rather than relative to the current working directory of the command, so the document ends up in the `bin\Debug` etc. folder rather than the folder the user expected.

Seems like resolving the full path here in the MSBuild targets before invoking the tool would resolve that: https://github.com/dotnet/aspnetcore/blob/06155c05af89c957de20d2c53cee0e37171b9a09/src/Tools/Extensions.ApiDescription.Server/src/build/Microsoft.Extensions.ApiDescription.Server.targets#L56

#### "Invalid OpenAPI spec version" warning

If the target is run without explicitly an OpenAPI document version to generate, a warning is output:

```console
Generating document named 'api'.
Using discovered `GenerateAsync` overload with version parameter.
Invalid OpenAPI spec version '' provided. Falling back to default: v3.0.
Writing document named 'api' to './artifacts/openapi\API_api.json'.
```

This comes from here:

https://github.com/dotnet/aspnetcore/blob/06155c05af89c957de20d2c53cee0e37171b9a09/src/Tools/GetDocumentInsider/src/Commands/GetDocumentCommandWorker.cs#L329

If this `Enum.TryParse()` call fails to parse anything:

https://github.com/dotnet/aspnetcore/blob/06155c05af89c957de20d2c53cee0e37171b9a09/src/Tools/GetDocumentInsider/src/Commands/GetDocumentCommandWorker.cs#L323

It looks like there's a few ways to resolve this:

1. Assign a default value for `GetDocumentCommandContext.OpenApiVersion` if no value is provided: https://github.com/dotnet/aspnetcore/blob/06155c05af89c957de20d2c53cee0e37171b9a09/src/Tools/GetDocumentInsider/src/Commands/GetDocumentCommand.cs#L141
2. Don't emit the warning if `GetDocumentCommandContext.OpenApiVersion` is null/empty (rather than a value that doesn't parse)
3. Explicitly pass a value for `--openapi-version` through from the MSBuild target: https://github.com/dotnet/aspnetcore/blob/06155c05af89c957de20d2c53cee0e37171b9a09/src/Tools/GetDocumentInsider/src/Commands/GetDocumentCommand.cs#L33

#### No MSBuild property for specifying the OpenAPI version

It's possible to add extra options to work around the above using `OpenApiGenerateDocumentsOptions` (e.g. `/p:OpenApiGenerateDocumentsOptions="--openapi-version OpenApi3_0"`), but there isn't a specific MSBuild property for this.

To make usage easier a property could be defined that the user can specify to set the version without needing to explicitly set command line parameters that the MSBuild target could transform and pass through to the tool (e.g. `/p:OpenApiGenerateDocumentVersion=3.0` into `--openapi-version OpenApi3_0`).

#### MSBuild properties not affecting "up-to-date-ness"

I noticed when the path wasn't being fully evaluated, if I re-ran the build with a different input property the document wouldn't be regenerated.

For example:

```pwsh
❯ dotnet build ./src/API /p:OpenApiGenerateDocuments=true /p:OpenApiDocumentsDirectory="${OutputDirectory}"
Restore complete (1.9s)
You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy
API succeeded (16.5s) → artifacts\bin\API\debug\API.dll

Build succeeded in 21.8s

api on  dotnet-nightly [$] via .NET v9.0.100-preview.7.24375.12 took 22s
❯ dotnet build ./src/API /p:OpenApiGenerateDocuments=true /p:OpenApiDocumentsDirectory="${OutputDirectory}2"
Restore complete (0.5s)
You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy
API succeeded (1.0s) → artifacts\bin\API\debug\API.dll

Build succeeded in 4.4s

api on  dotnet-nightly [$] via .NET v9.0.100-preview.7.24375.12 took 4s
```

The first command creates the API document at `${OutputDirectory}` in ~20 seconds.

The second command with the output path set to `${OutputDirectory}2` doesn't emit anything and takes ~4 seconds.

It seems like the properties being passed through aren't affecting MSBuild up-to-date checks and causing the document not to be re-generated.

#### Output directory value isn't checked for

I made a mistake during playing with the tool and accidentally un-defined the variable for the output path. This then causes an `ArgumentException` to be thrown inside the tool (`--output ""`). Should something check a value is specified first?

```console
❯ dotnet build ./src/API /p:OpenApiGenerateDocuments=true /p:OpenApiDocumentsDirectory="${OutputDirectory}" /p:OpenApiGenerateDocumentsOptions="--openapi-version OpenApi3_0"
Restore complete (0.6s)
You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy
API failed with 6 error(s) (12.4s) → artifacts\bin\API\debug\API.dll
C:\Users\Martin.Costello\.nuget\packages\microsoft.extensions.apidescription.server\9.0.0-preview.7.24375.8\build\Microsoft.Extensions.ApiDescription.Server.targets(66,5): error : System.ArgumentException: The value cannot be an empty string. (Parameter 'path')
C:\Users\Martin.Costello\.nuget\packages\microsoft.extensions.apidescription.server\9.0.0-preview.7.24375.8\build\Microsoft.Extensions.ApiDescription.Server.targets(66,5): error : at System.ArgumentException.ThrowNullOrEmptyException(String argument, String paramName)
C:\Users\Martin.Costello\.nuget\packages\microsoft.extensions.apidescription.server\9.0.0-preview.7.24375.8\build\Microsoft.Extensions.ApiDescription.Server.targets(66,5): error : at System.IO.Directory.CreateDirectory(String path)
C:\Users\Martin.Costello\.nuget\packages\microsoft.extensions.apidescription.server\9.0.0-preview.7.24375.8\build\Microsoft.Extensions.ApiDescription.Server.targets(66,5): error : at Microsoft.Extensions.ApiDescription.Tool.Commands.GetDocumentCommandWorker.GetDocuments(IServiceProvider services)
C:\Users\Martin.Costello\.nuget\packages\microsoft.extensions.apidescription.server\9.0.0-preview.7.24375.8\build\Microsoft.Extensions.ApiDescription.Server.targets(66,5): error : at Microsoft.Extensions.ApiDescription.Tool.Commands.GetDocumentCommandWorker.Process()
C:\Users\Martin.Costello\.nuget\packages\microsoft.extensions.apidescription.server\9.0.0-preview.7.24375.8\build\Microsoft.Extensions.ApiDescription.Server.targets(66,5): error MSB3073: The command "dotnet "C:\Users\Martin.Costello\.nuget\packages\microsoft.extensions.apidescription.server\9.0.0-preview.7.24375.8\build\../tools/dotnet-getdocument.dll" --assembly "C:\Coding\martincostello\api\artifacts\bin\API\debug\API.dll" --file-list "C:\Coding\martincostello\api\artifacts\obj\API\API.OpenApiFiles.cache" --framework ".NETCoreApp,Version=v9.0" --output "" --project "API" --assets-file "C:\Coding\martincostello\api\artifacts\obj\API\project.assets.json" --platform "AnyCPU" --openapi-version OpenApi3_0" exited with code 11.
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.