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

Add `IDocumentProvider` service and its implementation #1678

Merged
merged 30 commits into from Oct 26, 2018

Conversation

Projects
None yet
3 participants
@RSuter
Owner

RSuter commented Oct 23, 2018

Based on PR #1658

  • Add IDocumentProvider as done in this PR: #1658
  • Renamed DocumentRegistry to SwaggerDocumentRegistry
  • Rename DocumentProvider to SwaggerDocumentProvider
  • Add ISwaggerGenerator to NSwag.SwaggerGeneration (OpenApiDocumentSettings no longer used, less code)
    • AspNetCoreToSwaggerGenerator implements ISwaggerGenerator and thus can be added to the SwaggerDocumentRegistry
  • Split UseSwaggerUiWithApiExplorer() into two methods UseSwagger() and UseSwaggerUi()
    • We have to break the API anyway so this is to make it more SRP
  • Make AddDocument extension methods and use ISwaggerDocumentBuilder (avoid direct access to SwaggerDocumentRegistry)
  • Prepare everything so that the WebApiToSwaggerGenerator dependency can eventually be removed

Question:

  • Do the the documents be in DI or can't we just add them to the registry which is in DI?

Breaking changes:

  • UseSwaggerUiWithApiExplorer, UseSwaggerUi3WithApiExplorer, UseSwaggerReDocWithApiExplorer no longer supported => added exception with instruction how to fix it
    • The UI methods no longer implicitly call UseSwagger() that's why these methods have been removed
  • Documents are no longer configured in Configure() but now in ConfigureServices (AddSwagger())
  • PostProcess in the generator settings has been removed (use document processors instead)
    • PostProcess in the middleware now also provides the request (use this method only for http context specific transformation, otherwise use document processors)

Simple config:

    public void ConfigureServices(IServiceCollection services)
    {
        ...

        // Add NSwag OpenAPI/Swagger DI services and configure documents
        services.AddSwagger(); // add default document
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        ...
        // Add middlewares to service the OpenAPI/Swagger document and the web UI
        app.UseSwagger();
        app.UseSwaggerUi3();
    }

Advanced config:

    public void ConfigureServices(IServiceCollection services)
    {
        …

        // Add OpenAPI and Swagger DI services and configure documents

        // Adds the NSwag services
        services.AddSwagger(options => options
            // Register a Swagger 2.0 document generator
            .AddDocument("swagger", settings =>
            {
                // Add custom document processors, etc.
                settings.DocumentProcessors.Add(new SecurityDefinitionAppender("TEST_HEADER", new SwaggerSecurityScheme
                {
                    Type = SwaggerSecuritySchemeType.ApiKey,
                    Name = "TEST_HEADER",
                    In = SwaggerSecurityApiKeyLocation.Header,
                    Description = "TEST_HEADER"
                }));
            })
            // Register an OpenAPI 3.0 document generator
            .AddDocument("openapi", settings => settings.SchemaType = SchemaType.OpenApi3));
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        ...

        //// Add OpenAPI and Swagger middlewares to serve documents and web UIs

        // Add Swagger 2.0 document serving middleware
        app.UseSwagger(options =>
        {
            options.DocumentName = "swagger";
            options.Path = "/swagger/v1/swagger.json";
        });

        // Add web UIs to interact with the document
        app.UseSwaggerUi3(options =>
        {
            // Define OpenAPI/Swagger document route (defined with UseSwaggerWithApiExplorer)
            options.SwaggerRoute = "/swagger/v1/swagger.json";

            // Define web UI route
            options.SwaggerUiRoute = "/swagger_ui";
        });
        app.UseReDoc(options =>
        {
            options.SwaggerRoute = "/swagger/v1/swagger.json";
            options.SwaggerUiRoute = "/swagger_redoc";
        });

        //// Add OpenAPI 3.0 document serving middleware
        app.UseSwagger(options =>
        {
            options.DocumentName = "swagger";
            options.Path = "/openapi/v1/openapi.json";
        });

        // Add web UIs to interact with the document
        app.UseSwaggerUi3(options =>
        {
            options.SwaggerRoute = "/openapi/v1/openapi.json";
            options.SwaggerUiRoute = "/openapi_ui";
        });
        app.UseReDoc(options =>
        {
            options.SwaggerRoute = "/openapi/v1/openapi.json";
            options.SwaggerUiRoute = "/openapi_redoc";
        });

        // Add Swagger UI with multiple documents
        app.UseSwaggerUi3(options =>
        {
            // Add multiple OpenAPI/Swagger documents to the Swagger UI 3 web frontend
            options.SwaggerRoutes.Add(new SwaggerUi3Route("Swagger", "/swagger/v1/swagger.json"));
            options.SwaggerRoutes.Add(new SwaggerUi3Route("Openapi", "/openapi/v1/openapi.json"));
            options.SwaggerRoutes.Add(new SwaggerUi3Route("Petstore", "http://petstore.swagger.io/v2/swagger.json"));

            // Define web UI route
            options.SwaggerUiRoute = "/swagger_all";
        });
    }

rynowak and others added some commits Oct 6, 2018

Add `IDocumentProvider` service and its implementation
- #1626
- does not "provide an api to generate multiple / all documents"; could be layered on this work
  - otherwise, meets requirements listed in #1626
- assumes the following answers to open questions in #1626 (generally means everything is opt-in)
  - without an `AddSwagger()` call, `IDocumentProvider` service will not exist
  - registered document name / identifier is new `SwaggerSettings<>.DocumentName` property
    - document is not registered unless `DocumentName` is non-`null` i.e. `IDocumentProvider` won't know about it
    - `SwaggerSettings<>.MiddlewareBasePath` and `SwaggerRoute` are independent of `DocumentName`
  - middleware does not depend on the `IDocumentProvider` or registrar services; duplicating some code
- many thanks to @rynowak for writing this proposal
Revert changes to support `WebApiToSwaggerGeneratorSettings` in `IDoc…
…umentProvider`

- remove some code from files added in 5b7e0a3b34
- revert changes made in 5b7e0a3b34 to existing files
Revert "Make `IDocumentPovider` `public`"
- `internal` again
- commit 4057107.
WIP: Add ability to register documents from `Startup.ConfigureService…
…s(...)`

- add NSwag.Sample.OpenApi project
- rework bd9c7fc; revert part of that commit e.g. undo `SwaggerExtensions` changes

nit:
- correct doc comment for `AspNetCoreToSwaggerGeneratorSettings`

WIP:
- some doc comments are currently empty
- names are tentative

@RSuter RSuter referenced this pull request Oct 23, 2018

Closed

[WIP] Improve middleware api #1

@RSuter

This comment has been minimized.

Owner

RSuter commented Oct 23, 2018

@dougbu and @rynowak this is my proposal.

Currently missing is support for global IOptions support.

Can you please provide me a sample of the advanced config with your better solution?

@dougbu

This comment has been minimized.

Contributor

dougbu commented Oct 23, 2018

Do the the documents be in DI or can't we just add them to the registry which is in DI?

Either works fine now that you're hiding the registry behind the builder interface. And, the AddDocument(...) calls work 🆗 either hanging off the AddSwagger() return type or as nested configuration methods. I'll only note that nested configurations (and lambdas) get confusing.

Can you please provide me a sample of the advanced config with your better solution?

From #1658 discussions
For example, ConfigureServices(...) might contain

services.AddSwagger();
services.Configure<SwaggerMiddlewareOptions>(o => o.SwaggerRoute = "/openApi/{documentName}/swagger.json");
services.Configure<SwaggerUi3Options>(o => o.SwaggerUiRoute = "/myUi");

and
In Configure(...):

var options = new SwaggerUi3Options
{
    SwaggerUiRoute = "alternativeUi",
   TryItOut = false,
};
app
    .UseSwaggerUi3()
    .UseSwaggerUi3(options);
@dougbu

This comment has been minimized.

Contributor

dougbu commented Oct 23, 2018

Can you please provide me a sample of the advanced config with your better solution?

Separately, I'll build on #1658 to use IOptions<T> without returning to the PR on top of PR road we were going down in dougbu#1. Will take me a bit as I step away from our IM conversation here in GitHub 😸

@RSuter

This comment has been minimized.

Owner

RSuter commented Oct 26, 2018

  • Add support for documentName placeholder
  • Moved stuff to the Microsoft.* namespaces
  • Avoid duplicating stuff, avoid *Options classes (which makes stuff even more confusing)
  • Avoid copying settings (hard to maintain as property copies might be forgotten)
  • IOptions support prepared but will be added in v12 (when settings classes are cleaned up => only possible when the WebAPI generator feature is removed)
  • Multiple documents are added in nested lambda => advanced scenario and makes more sense for me as it is all in the scope of AddSwagger()

@RSuter RSuter changed the title from Add `IDocumentProvider` service and its implementation (2) to Add `IDocumentProvider` service and its implementation Oct 26, 2018

@RSuter RSuter merged commit 914e36b into master Oct 26, 2018

1 check passed

continuous-integration/appveyor/branch AppVeyor build succeeded
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment