182 lines
8.2 KiB
Markdown
182 lines
8.2 KiB
Markdown
# Guide 20: OpenAPI / Swagger Documentation
|
|
|
|
## What is OpenAPI and Swagger?
|
|
|
|
**OpenAPI** (formerly called Swagger Specification) is a standard format for describing REST APIs. An OpenAPI specification is a JSON or YAML file that lists every endpoint, its parameters, request/response shapes, authentication requirements, and error codes. Think of it as a machine-readable instruction manual for your API.
|
|
|
|
**Swagger** is a set of tools that work with OpenAPI specifications:
|
|
- **Swagger UI**: A web-based interactive API explorer. Developers can browse endpoints, see parameter descriptions, and make live test requests — all from the browser, without writing any code.
|
|
- **Swashbuckle**: A .NET library that automatically generates the OpenAPI specification from your controller code and XML documentation comments, and hosts Swagger UI.
|
|
|
|
**Why does this matter?** Without API documentation, frontend developers need to read the backend C# code (or ask the backend developer) to understand how to call each endpoint. With Swagger UI, they open a browser, see every endpoint, and can test them immediately. The documentation stays in sync with the code automatically because it's generated from the code.
|
|
|
|
---
|
|
|
|
## Setup in Program.cs
|
|
|
|
```csharp
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
builder.Services.AddSwaggerGen(options =>
|
|
{
|
|
// Basic API information
|
|
options.SwaggerDoc("v1", new OpenApiInfo
|
|
{
|
|
Title = "VigilCare Clinical API",
|
|
Version = "v1",
|
|
Description = "Clinical monitoring and alerting platform API"
|
|
});
|
|
|
|
// Tell Swagger UI that the API requires a JWT Bearer token
|
|
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
|
{
|
|
Name = "Authorization",
|
|
Type = SecuritySchemeType.Http,
|
|
Scheme = "bearer",
|
|
BearerFormat = "JWT",
|
|
In = ParameterLocation.Header,
|
|
Description = "Enter your JWT token"
|
|
});
|
|
|
|
// Apply the Bearer requirement to all endpoints by default
|
|
options.AddSecurityRequirement(document => new OpenApiSecurityRequirement
|
|
{
|
|
{
|
|
new OpenApiSecuritySchemeReference("Bearer", document),
|
|
new List<string>()
|
|
}
|
|
});
|
|
|
|
// Include XML documentation comments from the compiled assembly
|
|
var xmlPath = Path.Combine(AppContext.BaseDirectory,
|
|
$"{Assembly.GetExecutingAssembly().GetName().Name}.xml");
|
|
options.IncludeXmlComments(xmlPath);
|
|
});
|
|
```
|
|
|
|
**What does each part do?**
|
|
|
|
| Setting | Purpose |
|
|
|---------|---------|
|
|
| `AddEndpointsApiExplorer()` | Enables the metadata extraction that Swashbuckle needs to discover your endpoints |
|
|
| `SwaggerDoc("v1", ...)` | Names the API spec "v1" with a title and description shown at the top of Swagger UI |
|
|
| `AddSecurityDefinition("Bearer", ...)` | Adds an "Authorize" button to Swagger UI where developers can paste their JWT token |
|
|
| `AddSecurityRequirement(...)` | Shows a lock icon on every endpoint, indicating authentication is required |
|
|
| `IncludeXmlComments(xmlPath)` | Reads the `///` XML doc comments from your C# code and displays them as endpoint descriptions |
|
|
|
|
### Enabling Swagger UI
|
|
|
|
```csharp
|
|
app.UseSwagger(); // Serves the OpenAPI spec at /swagger/v1/swagger.json
|
|
app.UseSwaggerUI(options =>
|
|
{
|
|
options.SwaggerEndpoint("/swagger/v1/swagger.json", "VigilCare Clinical API v1");
|
|
});
|
|
```
|
|
|
|
Available at: `http://localhost:5270/swagger/ui`
|
|
|
|
---
|
|
|
|
## Writing Good Swagger Documentation
|
|
|
|
Swagger UI shows two things about each endpoint: information from your C# code attributes, and information from XML documentation comments.
|
|
|
|
### Controller and Action Attributes
|
|
|
|
```csharp
|
|
[ApiController]
|
|
[Route("api/v1/alert-thresholds")]
|
|
[Produces("application/json")]
|
|
[Authorize]
|
|
public class AlertThresholdsController : ControllerBase
|
|
{
|
|
[HttpPost]
|
|
[AuthorizePermission(ClinicalPermissions.ThresholdsWrite)]
|
|
[ProducesResponseType(typeof(ApiResponse<AlertThreshold>), StatusCodes.Status201Created)]
|
|
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status409Conflict)]
|
|
public async Task<IActionResult> Create([FromBody] AlertThresholdRequest req)
|
|
```
|
|
|
|
- **`[Produces("application/json")]`** tells Swagger the response format
|
|
- **`[ProducesResponseType(...)]`** documents which status codes the endpoint can return and what the response body looks like. Swagger UI shows these as expandable response examples.
|
|
- **`[FromBody]`** tells Swagger the request body schema comes from `AlertThresholdRequest`
|
|
|
|
### XML Documentation Comments
|
|
|
|
```csharp
|
|
/// <summary>
|
|
/// Creates a new alert threshold for an observation code.
|
|
/// </summary>
|
|
/// <param name="req">Threshold bounds and display metadata.</param>
|
|
/// <returns>The created threshold.</returns>
|
|
[HttpPost]
|
|
public async Task<IActionResult> Create([FromBody] AlertThresholdRequest req)
|
|
```
|
|
|
|
The `<summary>` appears as the endpoint description in Swagger UI. The `<param>` tags describe individual parameters. The `<returns>` tag describes the response.
|
|
|
|
**How does this work?** When you build a C# project with `<GenerateDocumentationFile>true</GenerateDocumentationFile>` in the `.csproj` file, the compiler creates an XML file containing all `///` comments. Swashbuckle reads this XML file at runtime and merges the comments into the OpenAPI specification.
|
|
|
|
---
|
|
|
|
## What Swagger UI Shows
|
|
|
|
When you open `http://localhost:5270/swagger/ui`, you see:
|
|
|
|
1. **API title and description** from `SwaggerDoc()`
|
|
2. **Grouped endpoints** organized by controller (Encounters, Observations, Alert Thresholds, FHIR, etc.)
|
|
3. **For each endpoint**:
|
|
- HTTP method and URL (e.g., `POST /api/v1/encounters/{encounterId}/observations`)
|
|
- Summary from `<summary>` XML comment
|
|
- Parameter descriptions from `<param>` XML comments
|
|
- Request body schema (auto-generated from the C# request class)
|
|
- Response schemas for each status code (from `[ProducesResponseType]`)
|
|
4. **"Authorize" button** — paste a JWT token to authenticate all subsequent requests
|
|
5. **"Try it out" button** — fill in parameters and execute real requests against the running API
|
|
|
|
---
|
|
|
|
## Security Scheme in Swagger UI
|
|
|
|
The security definition adds an "Authorize" button at the top of Swagger UI:
|
|
|
|
```csharp
|
|
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
|
{
|
|
Name = "Authorization",
|
|
Type = SecuritySchemeType.Http,
|
|
Scheme = "bearer",
|
|
BearerFormat = "JWT",
|
|
In = ParameterLocation.Header,
|
|
Description = "Enter your JWT token"
|
|
});
|
|
```
|
|
|
|
**How to use it:**
|
|
1. Call `POST /api/v1/auth/login` with username/password to get a token
|
|
2. Click "Authorize" in Swagger UI
|
|
3. Paste the token (without the "Bearer " prefix — Swagger adds it automatically)
|
|
4. Click "Authorize" — all subsequent requests include the `Authorization: Bearer <token>` header
|
|
|
|
---
|
|
|
|
## The Generated OpenAPI Specification
|
|
|
|
The raw specification is available at `/swagger/v1/swagger.json`. It's a standard OpenAPI 3.0 document that can be consumed by:
|
|
|
|
- **Code generators**: Generate API client libraries for TypeScript, Python, Java, etc. using tools like `openapi-generator` or `nswag`
|
|
- **Testing tools**: Import into Postman, Insomnia, or Bruno for manual testing
|
|
- **Documentation platforms**: Host on ReadMe, Stoplight, or Redocly for public documentation
|
|
- **Contract testing**: Validate that the API implementation matches the specification
|
|
|
|
---
|
|
|
|
## Key Takeaways
|
|
|
|
- **Swagger UI makes your API self-documenting** — developers can explore and test endpoints from a browser without reading C# code
|
|
- **Write `<summary>` comments on every controller action** — they become the endpoint descriptions in Swagger UI. Without them, endpoints are listed without any explanation.
|
|
- **Use `[ProducesResponseType]` for every status code** — this documents the possible responses and their shapes, making it clear what success and error responses look like
|
|
- **The security definition enables authenticated testing** — developers can paste a JWT token in the UI and test protected endpoints without using curl or Postman
|
|
- **The OpenAPI spec is a machine-readable contract** — frontend teams can generate TypeScript API clients from it, ensuring type-safe API calls without manual typing
|
|
- **Documentation stays in sync with code** — because it's generated from the actual controller code and attributes, it can never go stale (unlike a manually-written Wiki page)
|