Files
vigilcare-clinical/docs/guides/20-openapi-swagger-documentation.md

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)