Skip to main content

Swagger / OpenAPI

Swagger generates a Web interface that lists controller actions and allows testing HTTP APIs. Lagoon exposes this wiring through the ASP.NET Core server and Swashbuckle.

Wiring available in Lagoon​

ElementRole
RegisterSwaggerService(services)Registers OpenAPI generation and configures Swagger UI.
options.AddSwaggerAccess()Adds an authentication client for Swagger UI.
app.UseSwagger()Enables the OpenAPI documents.
app.UseSwaggerUI()Enables the Swagger interface.
AuthorizeCheckOperationFilterAdds the 401 / 403 responses and oauth2 security to protected operations.

The Demo server project does not declare any specific Swagger wiring; the wiring verified here is the one provided by the Lagoon server framework.

Server-side registration​

Authentication​

In OnConfigureAuthentification, add Swagger access when the application needs to expose Swagger UI. The former documentation restricted this to DEBUG mode.

Main.cs
protected override void OnConfigureAuthentification(AuthenticationOptions options)
{
base.OnConfigureAuthentification(options);

#if DEBUG
// Autorise Swagger UI à demander un jeton pour l'utilisateur connecté.
options.AddSwaggerAccess();
#endif
}

By default, AddSwaggerAccess() uses the SwaggerUI client and the /swagger/oauth2-redirect.html redirect.

Services​

In OnConfigureServices, call RegisterSwaggerService(services).

Main.cs
protected override void OnConfigureServices(IServiceCollection services)
{
#if DEBUG
// Enregistre les documents OpenAPI et la configuration Swagger UI.
RegisterSwaggerService(services);
#endif

Services.Registry.RegisterServices(services);
}

Enabling Swagger routes​

In OnConfigure, enable Swagger and Swagger UI in the ASP.NET Core pipeline.

Main.cs
protected override void OnConfigure(IApplicationBuilder app)
{
#if DEBUG
// Expose les documents OpenAPI et l'interface Swagger.
app.UseSwagger();
app.UseSwaggerUI();
#endif

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapLagoonFallback();
});
}

Exposed OpenAPI documents​

RegisterSwaggerService(services) configures the following documents:

DocumentURLContent
External/openapi/external.jsonVersioned public APIs.
Internal/openapi/internal.jsonInternal APIs, only in the development environment.

A route is considered external when its relative path starts with api/v followed by a version number, for example api/v1/countries.

External methods

Version the routes intended for use by other applications, for example /api/v1/countries. Non-versioned routes remain in the internal document.

Swagger UI interface​

The interface is available at the URL /swagger or /swagger/index.html on the application's hosting root.

If the user is already logged in, Swagger UI can retrieve a token via the Authorize button. The client used by default is SwaggerUI. The interface uses the OAuth2 flow configured by the framework.

XML documentation​

RegisterSwaggerService(services) includes the XML comments of the server project if the XML file matching the assembly exists. Enable XML documentation generation in the server project's properties if action descriptions must appear in Swagger UI.

Declaring a versioned external API​

CountriesController.cs
[ApiController]
[Route("api/[controller]")]
public class CountriesController : LgControllerBase
{
private readonly ApplicationDbContext _db;

public CountriesController(ApplicationDbContext db)
{
_db = db;
}

/// <summary>
/// Gets all country names for external applications.
/// </summary>
/// <returns>The country names.</returns>
[AllowAnonymous]
[HttpGet("/api/v1/countries")]
public IQueryable<VmCountry> GetNamesV1()
{
// Route absolue et versionnée : cette action apparaît dans le document externe.
return _db.Countries
.GroupBy(c => c.Name)
.Select(c => new VmCountry()
{
Id = c.First().Id,
Name = c.First().Name
})
.OrderBy(c => c.Name);
}

/// <summary>
/// Gets all country names for the application.
/// </summary>
/// <returns>The country names.</returns>
[Queryable]
[HttpGet("names")]
public IQueryable<VmCountry> GetNames()
{
// Route relative au contrôleur : cette action reste interne.
return _db.Countries
.GroupBy(c => c.Name)
.Select(c => new VmCountry()
{
Id = c.First().Id,
Name = c.First().Name
})
.OrderBy(c => c.Name);
}
}
Points of attention
  • For an external API, start the route with / to avoid a route relative to the controller.
  • When an external method undergoes a business change, create a new route version instead of changing the behavior of the existing version.
  • A bug fix does not necessarily require a new version.