-
Notifications
You must be signed in to change notification settings - Fork 467
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
Feature Proposal: Centralized Swagger UI for OpenAPI Specification Files #3608
Comments
Cool idea, related to #2980 |
If we do this we should also support it in Visual Studio. |
Just some (half-baked) general thoughts to help spur discussion
var builder = DistributedApplication.CreateBuilder(args);
var swagger = builder.AddSwaggerHost("swagger");
builder.AddProject<Projects.MyCoolProject>("web")
.WithReference(swagger);
var swagger = builder.AddSwaggerHost("swagger")
.WithSwaggerFile("**/*.swagger.json"); // With glob to point to swagger files
var someService = builder.AddNonDotNetService("foo")
.WithSwagger(); // Search output path for swagger file. Possibly accept glob pattern again. Intended scenario is including a swagger file from a docker image or something similar.
var web = builder.AddProject<Projects.MyCoolProject>("web")
.WithReference(swagger);
// In MyCoolProject.Project.cs
var builder = WebApplication.CreateBuilder(args);
builder.AddSwagger("swagger"); // Wraps standard swagger packages to produce the swagger json file, then provides that back to the swagger host. My Questions
|
@Foxtrek64 I like the way that you've modeled this implementation as an integration in your proposal, with both a client and hosting component. In .NET 9, we added built-in support for OpenAPI document generation via the With regard to the hosting side of this, I saw it being inverted a bit: var apiService1 = builder.AddProject<>();
var apiService2 = builder.AddProject<>();
var swagger = builder.AddSwaggerUi()
.WithReference(apiService1)
.WithReference(apiService2); This way a user could navigate to a certain gateway that incorporated the OpenAPI documentation for all the API services in their application. You could potentially use the document switcher UI to keep things truly centralized. Side note: although Swagger UI is popular, I've become quite partial to Scalar over the past few months. It would be interesting to explore adding an Aspire hosting integration for Scalar that provided this functionality. @xC0dex -- what are your thoughts on prototyping an Aspire hosting integration around Scalar and seeing what it would look like?
I'm inclined to say the ergonomics should be the same across all project types, especially if the API reference document is an independent resource in-and-off itself instead of something that gets added via a One more thing, I was originally gonna close this issue in favor of centralizing all the discussion in #2980 but I think we should keep these two as independent and separate ideas.
I think the first issue (this one) is a lot more tractable given the APIs that we currently support and the prototyping that has already been done in this project. |
@captainsafia I like the inverted model. By providing the service reference to the service with the open api spec, it makes it really easy to keep the ergonomics consistent regardless of whether the service generating the open api doc is .NET or not. Also, I think the best way to handle the question of swagger vs scalar or other potential implementations could be something like var openApi = builder.AddOpenApi();
var swagger = openApi.WithSwaggerUi();
var scalar = openApi.WithScalarUi();
// others Essentially, the This also means a really nice tie-in to #2980 - the in-dashboard experience would simply be another output source, just like Swagger and Scalar. builder.AddOpenApi().WithDashboardUi(); Edit: component registration example var openApi = builder.AddOpenApi()
.WithScalarUi()
.WithReference(apiService1)
.WithReference(apiService2); |
I assume this is code that someone would write in their app host. If so, what purpose does the I think it is a comparison between: var openApi = builder.AddOpenApi()
.WithScalarUi()
.WithSwaggerUi()
.WithReference(apiService1)
.WithReference(apiService2); OR var scalar = builder.AddScalarUi();
var swagger = builder.AddSwaggerUi();
scalar
.WithReference(apiService1)
.WithReference(apiService2);
swagger
.WithReference(apiService1)
.WithReference(apiService2); With the first option being DRYer but requiring more new API. I don't think there's a technical need for an |
Hey @captainsafia, |
@xC0dex Nice! I'd recommend checking out https://github.com/davidfowl/AspireSwaggerUI as an example to start with. You'll notice if you look at this file that it uses an approach for serving the Swagger UI that is very familiar to what the Most of the Aspire-specific logic is in this file and deals with wiring up the endpoints directly to what the API service is actually listening on. Note: the repo above doesn't use the inverted model that I proposed in #3608 (comment) but it's a good start nonetheless. |
Essentially, yes. I think the primary concern here is the input logic - how we aggregate the various sources into a single resource instance that can be given to the chosen front-end. In my opinion, as someone implementing Swagger or Scalar or whatever else, I don't necessarily care where my input comes from or how it's created, I just care that I get input that is in the correct format. I also don't feel it's necessarily my responsibility to need to implement that logic myself. This would lead to a situation where there is inconsistency between builders.
I agree. Having looked at some other examples already in the ecosystem, it seems implementing our own builder type would be somewhat unusual. Take this example with Postgres, for example: var database = builder.AddPostgres("database") // IResourceBuilder<PostgresServerResource>
.WithPgAdmin(); Here, they're doing what we're trying to accomplish - some back-end service with a bolt-on GUI. I think it may be good to follow the example here - forego the With this in mind, I think the first option makes the most sense, both from a consumer standpoint and from a vendor standpoint. var openApi = builder.AddOpenApi() // IResourceBuilder<OpenApiResource>
.WithDashboardUi()
.WithResource(apiResource1)
.WithResource(apiResource2); |
I was bored over the weekend so I decided to throw together a quick partial prototype of this feature, in the current context that would be the I haven't worked with the aspire repo before so this is my first attempt at making something functional. Forked repo here Prototype showcase: |
@mikekistler FYI |
+1 - personally, I think that the .http file support is a much better experience than the web based explorers. What is (or was the last time I looked) a good experience to go from a list of APIs on an endpoint to generating a block in the http file for calling that API. For scenarios like this, I would like to improve the integration between VS and the Aspire dashboard. If an Aspire AppHost has the swagger annotations, what if that resulted in a "API Test" command in the resource view in the dashboard. Clicking it would take you to the .http file for that service, and enumerate the endpoints/APIs available. |
To make sure I'm understanding your idea - if we take my example above, you're proposing that we take the I'd be on board with that approach, provided that we get a way to extract that OpenAPI information in case someone wants to expose Swagger or Scalar or some alternative UI, which could be good for production purposes where the Aspire Dashboard may be less appropriate. |
I've been thinking about this and I probably like this design the most because it leaves a room for easy configuration. Let's say I would want to configure the path to the OpenApi document. I think something like Further more I think it would be nice to also have the ability to define specific paths for selected resources, so something like So putting it all together it would look something like this: var openApi = builder.AddOpenApi(["/path/to/document.json"]) // IResourceBuilder<OpenApiResource>
.WithDashboardUi()
.WithResource(apiResource1) // This has one document path.
.WithResource(apiResource2, ["/path/to/extra/document.json"]); // This has two document paths. |
Hey @captainsafia, I’ve put together an MVP for the Scalar integration, based on the AspireSwaggerUI project. Currently, it uses the CDN version of the Scalar API Reference and isn’t configurable yet. From my understanding, the plan for how the UI will be added isn’t fully settled yet, so I didn't spend much time there. Even though it’s still in a very early stage, I was wondering: should the UI/integration be fully configurable? And would it make sense to use the During the development, I thought it would enhance the developer experience if the OpenAPI documents from all services could be fetched automagically. I’m considering an endpoint that could provide all the necessary information needed for the integration. |
I really like this configuration approach. A // Just include paths
builder.AddOpenApi(["**/*.document.json", "**/*.swagger.json"]);
// More complicated example. This is NOT intended to be equivalent to the
// preceding example.
Matcher matcher = new();
matcher.AddInclude("**/*.document.json");
matcher.AddExclude("**/*.swagger.json");
builder.AddOpenApi(matcher); This would of course also apply to |
Ooh, I wasn't aware of that class. I like it. This then gives me an idea of having two // First parameter are include paths, second parameter are exclude paths.
builder.AddOpenApi(["**/*.document.json"], ["**/*.swagger.json"]);
// This complicated example below now matches the preceding example.
Matcher matcher = new();
matcher.AddInclude("**/*.document.json");
matcher.AddExclude("**/*.swagger.json");
builder.AddOpenApi(matcher);
// Writing just exclude paths would be like this
builder.AddOpenApi([], ["**/*.swagger.json"]); |
Feature Proposal
Summary
In the context of the .NET Aspire project, I propose to add a new feature aimed at consolidating all OpenAPI specification files across the project into a unified Swagger UI interface. This would greatly enhance the developer experience by providing a single, centralized location to view and interact with the API documentation generated from OpenAPI specifications.
Problem Statement
Currently, OpenAPI specification files are scattered throughout various parts of our project, making it challenging to locate, view, and test different APIs efficiently. Developers and API consumers have to navigate through multiple Swagger UI instances or look into different directories to find the relevant API documentation. This fragmentation hinders productivity and can lead to inconsistencies in how APIs are understood and used.
Proposed Solution
Implement a mechanism within the .NET Aspire project that automatically scans the project directories for OpenAPI specification files (*.json or *.yaml). Once identified, these files will be aggregated into a single Swagger UI instance. This unified Swagger UI will be automatically updated to reflect changes in the OpenAPI specifications, ensuring that the documentation is always current.
Benefits
Implementation Considerations
Request for Comments
I invite the community to provide feedback on this proposal. Any insights on potential challenges, additional benefits, or alternative approaches to achieving this goal would be greatly appreciated.
The text was updated successfully, but these errors were encountered: