Chapter 11: Documenting APIs with OpenAPI
This chapter introduces OpenAPI as a way to describe a minimal API and previews using that description for documentation, testing, metadata, and generated C# clients.
After this chapter you will be able to
- OpenAPI API descriptions. Explain that the OpenAPI specification describes RESTful APIs and that an ASP.NET Core minimal API can expose an OpenAPI document describing its endpoints.
- OpenAPI document purpose. Explain that OpenAPI is a language-agnostic specification whose JSON document describes a REST API's available URLs, invocation details, and returned data types. Describe how that document enables tooling such as API exploration, strongly typed client generation, and third-party API-management integration.
- Swashbuckle document generation. Describe how to add Swashbuckle.AspNetCore to a minimal API and configure it to generate and serve an OpenAPI document. State that Swashbuckle obtains endpoint information from ASP.NET Core metadata services and exposes the generated document at the Swagger JSON endpoint.
- Swagger UI purpose. Explain what Swagger UI provides for an OpenAPI application and when it can be a useful alternative to Postman for local API testing.
- Interactive API inspection. Describe the information Swagger UI displays and trace how to test an endpoint by choosing Try it out, supplying parameter values, and choosing Execute; explain that the result can expose responses missing from the API documentation.
- Minimal API endpoint metadata. Explain that endpoint metadata is information attached to a minimal API endpoint that does not change how the endpoint executes, but lets other ASP.NET Core features use information about it.
- OpenAPI tags and responses. Describe how OpenAPI metadata can add tags and explicit response descriptions to minimal API endpoints, and explain that Swagger UI uses tags to group endpoints and Produces() metadata to show their responses.
- Strongly typed client purpose. Explain what a generated strongly typed C# client provides when consuming an API from another C# project, including automatic request serialization and response deserialization.
- Client generation refresh workflow. Trace the generation workflow from downloading the OpenAPI JSON locally through reading its endpoints and schemas, generating the C# client, and regenerating it when the local description changes during builds.
- Visual Studio client generation. Describe how to generate a strongly typed client from an OpenAPI document using Visual Studio's Add Service Reference workflow. Include that the API must be running with its OpenAPI JSON accessible, and that you select OpenAPI, provide the document URL, namespace, and client class name before finishing generation.
- Global-tool client generation. Describe the workflow for generating an NSwag client with the .NET OpenAPI global tool: run an accessible API, identify its OpenAPI JSON URL, install the tool, add an OpenAPI reference from the console-project folder, and update the added packages.
- Generated client invocation. Explain how to call the API through a generated FruitClient: create it with the API base address and an HttpClient, then call its generated asynchronous endpoint methods such as FruitPOSTAsync() and FruitGETAsync().
- Endpoint names as operation IDs. Explain that adding WithName() to each minimal API endpoint supplies its OperationID in the OpenAPI description, which NSwag uses to generate clearer client method names instead of names such as FruitPOSTAsync() and FruitGETAsync().
- NSwag client customization options. Explain the three NSwag generation customizations in this section: use System.Text.Json, generate a client interface, and remove the explicit base URL constructor argument. Describe why each option can better fit an ASP.NET Core application or its tests.
- OpenApiReference options configuration. Describe how to configure these NSwag settings by adding an Options element inside the OpenApiReference element in the project file. State the relevant command-line switches and their key true/false or library values.
- NSwag regeneration troubleshooting. Explain why changing NSwag options in the csproj file may not regenerate the client: NSwag watches the local OpenAPI JSON file and regenerates when that file changes, not necessarily when options change. Describe forcing regeneration by deleting the project obj folder, or by making and then reverting a small OpenAPI-document change.
- Saved OpenAPI snapshot. Explain why the OpenAPI JSON document saved in a client project can become outdated and when it must be downloaded again. State that the saved document is a point-in-time snapshot, not an automatically updated copy of the API description.
- OpenAPI refresh workflows. Describe the supported ways to refresh a saved OpenAPI description: manually replace the JSON, use Visual Studio's Connected Services refresh action, or use the .NET OpenAPI tool with the original URL. State that the API must be running and its description document available before either tool-based refresh.
- NSwag regeneration build. Describe what to do after refreshing the saved OpenAPI description: build the application to trigger NSwag client regeneration. Explain that refreshed changes, such as operation IDs, then appear in the generated code.
- Endpoint metadata enhancements. Describe how adding descriptions and summaries to the OpenAPI document, along with other metadata on minimal API endpoints, improves the experience of developers using an API.
- OpenAPI-enabled fluent descriptions. Explain why WithSummary() and WithDescription() alone do not update the generated OpenAPI description, and describe the additional package and WithOpenApi() call required for them to do so.
- Attribute-based endpoint metadata. Describe how dedicated C# attributes can replace almost all fluent endpoint metadata extension methods, and state that the attributes are applied directly to the handler method or lambda.
- Metadata readability trade-offs. Explain that choosing fluent methods or attributes is largely a matter of taste, and justify adding only metadata worth its readability cost based on the API audience, maturity, and opportunities to extract helpers.
- XML comment OpenAPI integration. Describe how XML documentation comments on static or instance endpoint-handler methods become OpenAPI summaries and parameter descriptions through Swashbuckle. Explain that the .NET SDK writes the comments to an XML file during the build and Swashbuckle reads that file at startup.
- XML comment configuration steps. Explain the three required setup steps for XML-comment metadata: enable GenerateDocumentationFile in the project file, configure SwaggerGen to read the generated XML document, and use a static or instance method handler with XML comments.
- OpenAPI limitation awareness. Explain that although OpenAPI and Swagger support API testing and code generation, they also have limitations that can become more significant as an API grows in complexity.
- OpenAPI description boundaries. Explain that OpenAPI is intended to tell clients how to call an API, but it deliberately does not cover every possible REST API style. Describe that its limitations arise when endpoint responses or available operations cannot be known in advance.
- HATEOAS dynamic links. Describe HATEOAS as a REST design in which responses include links for actions a client can take and the paths for those actions. Explain that the server can change those links according to resource state or user, so OpenAPI cannot predefine all endpoint responses and available actions.
- Generated client trade-offs. Explain why OpenAPI client generation is beneficial only when the generated code fits the application's needs, and why extensive customization can make writing a client manually simpler.
- Cross-client Product type mismatch. Explain why Product objects generated from separate but related OpenAPI documents cannot necessarily be passed directly between their generated clients, even when their properties and JSON representation match.
- Specification and tooling lag. Explain why support for an OpenAPI feature can fail across a tool chain even when the OpenAPI specification defines it, and describe the greater risk when using newer or less popular features.
- OpenAPI adoption trade-offs. Justify when a light investment in OpenAPI is worthwhile and when heavy investment may not be worthwhile, based on simple requirements and Swagger UI testing versus complex requirements, hard-to-describe APIs, or dissatisfaction with generated code.
What it builds on
- What is an HTTP API, and when should you use one? (chapter 5) · The idea of an HTTP API and its endpoints.
- Defining minimal API endpoints (chapter 5) · Minimal API endpoints in an ASP.NET Core application.
- The .csproj project file: Declaring your dependencies (chapter 3) · Adding NuGet package dependencies to an ASP.NET Core project.
- Adding and configuring services (chapter 3) · Registering and configuring application services.
- Defining how requests are handled with middleware and endpoints (chapter 3) · Configuring middleware and endpoints in an ASP.NET Core application.
- Extracting values from the URL with routing (chapter 5) · Route parameters in endpoint URLs.
- Mapping verbs to endpoints (chapter 5) · Mapping HTTP verbs to endpoints.
- Returning status codes with Results and TypedResults (chapter 5) · API endpoints can return different HTTP status-code responses, including successful and error results.
Section by section
Introduction
This chapter introduces OpenAPI as a way to describe a minimal API and previews using that description for documentation, testing, metadata, and generated C# clients.
- OpenAPI API descriptions: Explain that the OpenAPI specification describes RESTful APIs and that an ASP.NET Core minimal API can expose an OpenAPI document describing its endpoints.
Why it matters: An API description provides a machine-readable account of what an API offers, enabling documentation and tooling. - OpenAPI tooling workflow: Describe the chapter's OpenAPI workflow: add and expose an OpenAPI document, use Swagger UI to inspect and test it, enrich endpoint metadata, and generate a C# client with NSwag.
Why it matters: The value of OpenAPI comes from the tools that consume its description for testing, documentation, and client code. - Endpoint metadata quality: Explain that OpenAPI, Swagger UI, and generated clients need rich endpoint metadata for the best functionality, including summaries and descriptions supplied through fluent methods, attributes, or XML documentation comments.
Why it matters: Richer endpoint information makes the resulting documentation and generated-client experience more useful.
Key terms: OpenAPI specification, OpenAPI document, RESTful APIs, minimal API, Swagger UI, metadata, NSwag, generated client, C# client, summaries
11.1 Adding an OpenAPI description to your app
This section introduces OpenAPI documents and shows how Swashbuckle generates and serves an OpenAPI description for a minimal API application.
- OpenAPI document purpose: Explain that OpenAPI is a language-agnostic specification whose JSON document describes a REST API's available URLs, invocation details, and returned data types. Describe how that document enables tooling such as API exploration, strongly typed client generation, and third-party API-management integration.
Why it matters: An OpenAPI document turns an API's description into something tools can read and use automatically. - Swashbuckle document generation: Describe how to add Swashbuckle.AspNetCore to a minimal API and configure it to generate and serve an OpenAPI document. State that Swashbuckle obtains endpoint information from ASP.NET Core metadata services and exposes the generated document at the Swagger JSON endpoint.
Why it matters: Registering generation and serving middleware makes the API's live endpoint metadata available as an OpenAPI document. - Document contents and configuration: Describe that a generated OpenAPI document includes general application information, such as title and version, plus endpoint-specific details such as HTTP verbs and path parameters. Explain that values such as the title and description can be configured through AddSwaggerGen(), and that Swashbuckle retains Swagger terminology in its method names even though OpenAPI is the specification.
Why it matters: Configuring useful document metadata makes generated API documentation clearer to people and downstream tools.
Key terms: OpenAPI, Swagger, OpenAPI document, RESTful APIs, JSON, Swashbuckle.AspNetCore, Swashbuckle, AddSwaggerGen(), ASP.NET Core metadata services, middleware
11.2 Testing your APIs with Swagger UI
This section introduces Swagger UI as a Swashbuckle-provided web interface for exploring and testing an app’s OpenAPI-described endpoints, while revealing why endpoint metadata may need improvement.
- Swagger UI purpose: Explain what Swagger UI provides for an OpenAPI application and when it can be a useful alternative to Postman for local API testing.
Why it matters: Swagger UI lets developers inspect and try an API from the application itself without needing a separate tool for simple local testing. - Swagger UI middleware endpoint: Describe how Swagger UI is added with Swashbuckle middleware and state that it integrates with the OpenAPI document middleware and is exposed at /swagger by default.
Why it matters: Knowing where Swagger UI comes from and where it is hosted lets you open the interactive documentation for a running application. - Interactive API inspection: Describe the information Swagger UI displays and trace how to test an endpoint by choosing Try it out, supplying parameter values, and choosing Execute; explain that the result can expose responses missing from the API documentation.
Why it matters: Interactive testing both verifies an endpoint’s behavior and highlights gaps between its documented and actual responses.
Key terms: Swagger UI, OpenAPI, Postman, Swashbuckle, Swagger UI middleware, OpenAPI document middleware, /swagger, Try it out, Execute, schema
11.3 Adding metadata to your minimal APIs
This section explains endpoint metadata in minimal APIs, focusing on optional OpenAPI metadata that improves generated documentation and Swagger UI.
- Minimal API endpoint metadata: Explain that endpoint metadata is information attached to a minimal API endpoint that does not change how the endpoint executes, but lets other ASP.NET Core features use information about it.
Why it matters: Metadata lets an endpoint communicate useful information to framework features and tools without changing its request-handling code. - Metadata category distinctions: Distinguish routing metadata, metadata for other middleware, and OpenAPI metadata, including the feature each category supports.
Why it matters: Recognizing the categories helps you understand why the same endpoint can provide information to routing, middleware, and documentation tools. - OpenAPI tags and responses: Describe how OpenAPI metadata can add tags and explicit response descriptions to minimal API endpoints, and explain that Swagger UI uses tags to group endpoints and Produces() metadata to show their responses.
Why it matters: Accurate tags and response metadata make generated API documentation easier for API consumers to navigate and understand. - Optional metadata investment: Justify when adding extensive OpenAPI metadata is worthwhile: it is optional for simple Swagger UI testing, but valuable when exposing an OpenAPI document for others to consume and for making API tooling easier to use.
Why it matters: This helps you spend documentation effort where it benefits external consumers and generated tooling most.
Key terms: metadata, minimal API endpoints, WithName(), LinkGenerator, routing metadata, middleware metadata, authorization, hostname filtering, output caching, OpenAPI metadata
11.4 Generating strongly typed clients with NSwag
This section introduces using NSwag, through Visual Studio or a .NET tool, to generate and keep updated a strongly typed C# client from an API’s OpenAPI description.
- Strongly typed client purpose: Explain what a generated strongly typed C# client provides when consuming an API from another C# project, including automatic request serialization and response deserialization.
Why it matters: A generated client makes calling an API from C# easier and less error-prone than manually crafting HTTP requests. - NSwag generation options: Describe NSwag's role as the client generator used here, and distinguish the two supported ways to invoke it: Visual Studio or the Microsoft .NET OpenAPI global tool.
Why it matters: Knowing that both routes produce the same client lets you choose the workflow you prefer. - Client generation refresh workflow: Trace the generation workflow from downloading the OpenAPI JSON locally through reading its endpoints and schemas, generating the C# client, and regenerating it when the local description changes during builds.
Why it matters: The build-integrated refresh process keeps generated client code aligned with the API description.
Key terms: strongly typed client, serialization, deserialization, OpenAPI description, NSwag, Visual Studio, Microsoft .NET OpenAPI global tool, Swashbuckle, OpenAPI description JSON file, endpoints
11.4.1 Generating a client using Visual Studio
This section shows how to use Visual Studio to generate an NSwag-based strongly typed API client from an accessible OpenAPI document and update its required packages.
- Visual Studio client generation: Describe how to generate a strongly typed client from an OpenAPI document using Visual Studio's Add Service Reference workflow. Include that the API must be running with its OpenAPI JSON accessible, and that you select OpenAPI, provide the document URL, namespace, and client class name before finishing generation.
Why it matters: This lets a .NET application obtain a client for an API from its published contract rather than requiring the API source code. - Generated project configuration: Explain the project changes Visual Studio makes for OpenAPI client generation and why package versions may need updating. State that it adds NuGet references and an OpenApiReference element, but the generated packages can be out of date, so NSwag.ApiDescription.Client and Microsoft.Extensions.ApiDescription.Client should be updated before building.
Why it matters: Updating these dependencies resolves the Visual Studio-generated setup so the project can build and produce the client.
Key terms: Add Service Reference, OpenAPI service reference, OpenAPI document, OpenAPI description, generated client, FruitClient, OpenApiReference, NSwag.ApiDescription.Client, Microsoft.Extensions.ApiDescription.Client, NuGet
11.4.2 Generating a client using the .NET Global tool
This section shows how to use the .NET OpenAPI global tool to add an OpenAPI reference to a console project and generate an NSwag client without Visual Studio.
- Global-tool client generation: Describe the workflow for generating an NSwag client with the .NET OpenAPI global tool: run an accessible API, identify its OpenAPI JSON URL, install the tool, add an OpenAPI reference from the console-project folder, and update the added packages.
Why it matters: This lets you generate an API client from the command line rather than relying on Visual Studio. - Generated OpenAPI project configuration: Explain that the tool downloads the OpenAPI description into the project, such as OpenAPIs\fruit.json, and adds an OpenApiReference entry to the project file; describe adding ClassName and Namespace attributes when the default generated client name and namespace need to be made explicit.
Why it matters: Knowing what the tool changes makes the generated client configuration visible and editable in any development environment.
Key terms: .NET OpenAPI tool, OpenAPI reference, OpenAPI description, NSwag, OpenApiReference, OpenAPIs\fruit.json, ClassName, Namespace, csproj
11.4.3 Using a generated client to call your API
This section shows how an NSwag-generated C# client is produced from an OpenAPI description, used to call API endpoints, and improved through endpoint names.
- Generated client creation: Describe how the NSwag.ApiDescription.Client and Microsoft.Extensions.ApiDescription.Client packages use the project's OpenAPI description to generate a C# client class and the types needed for request and response serialization.
Why it matters: Understanding where the client comes from makes the generated API-calling code less mysterious. - Generated client invocation: Explain how to call the API through a generated FruitClient: create it with the API base address and an HttpClient, then call its generated asynchronous endpoint methods such as FruitPOSTAsync() and FruitGETAsync().
Why it matters: The generated client lets application code call an HTTP API through C# methods instead of manually constructing every request. - Generated client boilerplate: Explain that generated client methods handle API-call boilerplate, including URL path construction, request-body serialization, response deserialization, and checking error status codes.
Why it matters: This explains why a generated client is preferable to repeating low-level HTTP request code for every endpoint. - Endpoint names as operation IDs: Explain that adding WithName() to each minimal API endpoint supplies its OperationID in the OpenAPI description, which NSwag uses to generate clearer client method names instead of names such as FruitPOSTAsync() and FruitGETAsync().
Why it matters: Meaningful endpoint metadata produces a clearer, more usable client for API consumers.
Key terms: NSwag.ApiDescription.Client, Microsoft.Extensions.ApiDescription.Client, OpenAPI description, OpenApiReference, namespace, FruitClient, HttpClient, base address, FruitPOSTAsync(), FruitGETAsync()
11.4.4 Customizing the generated code
This section shows how to configure NSwag-generated clients for System.Text.Json, interfaces, and HttpClient-based addresses, and how to force regeneration when those options do not take effect.
- NSwag client customization options: Explain the three NSwag generation customizations in this section: use System.Text.Json, generate a client interface, and remove the explicit base URL constructor argument. Describe why each option can better fit an ASP.NET Core application or its tests.
Why it matters: These options make generated clients align with your app’s JSON stack, testing strategy, and dependency-injection setup. - OpenApiReference options configuration: Describe how to configure these NSwag settings by adding an Options element inside the OpenApiReference element in the project file. State the relevant command-line switches and their key true/false or library values.
Why it matters: Putting the switches in the project file controls the shape and dependencies of the client code NSwag generates. - Generated client extensibility hooks: Describe how NSwag marks generated client classes as partial so you can add a separate partial class with useful methods. Explain that its partial methods provide hooks before requests are sent or received and disappear at compile time when no implementation is supplied.
Why it matters: Partial classes and hooks let you extend generated code without editing code that NSwag can overwrite. - NSwag regeneration troubleshooting: Explain why changing NSwag options in the csproj file may not regenerate the client: NSwag watches the local OpenAPI JSON file and regenerates when that file changes, not necessarily when options change. Describe forcing regeneration by deleting the project obj folder, or by making and then reverting a small OpenAPI-document change.
Why it matters: Without forcing regeneration, your source code can continue using an old client even after you change its generator settings.
Key terms: System.Text.Json, Newtonsoft.Json, GenerateClientInterfaces, UseBaseUrl, BaseAddress, HttpClient, OpenApiReference, Options, /UseBaseUrl:false, /GenerateClientInterfaces:true
11.4.5 Refreshing the OpenAPI description
This section explains how to refresh a saved OpenAPI document so NSwag regenerates a client that reflects the current API description.
- Saved OpenAPI snapshot: Explain why the OpenAPI JSON document saved in a client project can become outdated and when it must be downloaded again. State that the saved document is a point-in-time snapshot, not an automatically updated copy of the API description.
Why it matters: An outdated description causes generated client code to omit or misrepresent recent API metadata changes. - OpenAPI refresh workflows: Describe the supported ways to refresh a saved OpenAPI description: manually replace the JSON, use Visual Studio's Connected Services refresh action, or use the .NET OpenAPI tool with the original URL. State that the API must be running and its description document available before either tool-based refresh.
Why it matters: Refreshing the local description provides the current contract from which client code can be generated. - Refresh tool compatibility: Distinguish the refresh tool from the tool originally used to add the OpenAPI reference. Explain that a reference added with Visual Studio must be refreshed with Visual Studio, whereas one added with the .NET OpenAPI tool must be refreshed with that tool, because they use different project attributes.
Why it matters: Using the matching tool avoids a failed or unsupported refresh workflow for the existing reference. - NSwag regeneration build: Describe what to do after refreshing the saved OpenAPI description: build the application to trigger NSwag client regeneration. Explain that refreshed changes, such as operation IDs, then appear in the generated code.
Why it matters: Refreshing the document alone does not update the client code until the build triggers NSwag generation.
Key terms: OpenAPI description, point-in-time snapshot, NSwag, generated client, metadata, Connected Services, OpenAPI reference, Refresh, .NET OpenAPI tool, OpenAPI description document
11.5 Adding descriptions and summaries to your endpoints
This section introduces adding descriptions, summaries, and other metadata to minimal API endpoints so OpenAPI-based tools provide a better developer experience.
- Endpoint metadata enhancements: Describe how adding descriptions and summaries to the OpenAPI document, along with other metadata on minimal API endpoints, improves the experience of developers using an API.
Why it matters: Clear endpoint metadata helps tools communicate how an API should be used.
Key terms: OpenAPI description document, descriptions, summaries, metadata, minimal API endpoints, Swagger UI
11.5.1 Using fluent methods to add descriptions
This section shows how fluent metadata methods and WithOpenApi() add endpoint and parameter documentation to a minimal API’s generated OpenAPI document.
- OpenAPI-enabled fluent descriptions: Explain why WithSummary() and WithDescription() alone do not update the generated OpenAPI description, and describe the additional package and WithOpenApi() call required for them to do so.
Why it matters: Without WithOpenApi() and the supporting package, descriptive endpoint metadata will not appear in the OpenAPI document or Swagger UI. - Parameter description customization: Describe how to use the lambda overload of WithOpenApi() to set OpenAPI metadata directly, including a description for an endpoint parameter such as id.
Why it matters: Parameter documentation helps API consumers understand what values an endpoint expects. - OpenAPI metadata consumers: Explain that the added summary and description metadata appears in Swagger UI, and that NSwag uses an endpoint summary as a documentation comment in generated client code.
Why it matters: The same OpenAPI metadata improves both interactive API documentation and the readability of generated clients.
Key terms: WithSummary(), WithDescription(), WithOpenApi(), Microsoft.AspNetCore.OpenApi, OpenAPI description, Swashbuckle, lambda method, OpenAPI metadata, parameter description, id parameter
11.5.2 Using attributes to add metadata
This section shows how to replace most fluent endpoint metadata calls with attributes, while weighing the readability cost of API metadata.
- Attribute-based endpoint metadata: Describe how dedicated C# attributes can replace almost all fluent endpoint metadata extension methods, and state that the attributes are applied directly to the handler method or lambda.
Why it matters: Attributes can make endpoint metadata less noisy than long chains of fluent extension methods. - WithOpenApi requirement: State that WithOpenApi() is the one fluent call that cannot be replaced by an attribute in this example, because it must remain for Swashbuckle to read the OpenAPI metadata correctly.
Why it matters: Leaving this call in place ensures the metadata added with attributes is correctly used for the OpenAPI description. - Metadata readability trade-offs: Explain that choosing fluent methods or attributes is largely a matter of taste, and justify adding only metadata worth its readability cost based on the API audience, maturity, and opportunities to extract helpers.
Why it matters: Useful API documentation should clarify an endpoint without burying its intent beneath unnecessary metadata.
Key terms: attributes, endpoint metadata, extension methods, handler method, lambda function, WithOpenApi(), Swashbuckle, OpenAPI metadata, fluent interfaces, metadata
11.5.3 Using XML documentation comments to add metadata
This section shows how to use C# XML documentation comments as OpenAPI summaries and parameter descriptions, and when that level of metadata is worthwhile.
- XML comment OpenAPI integration: Describe how XML documentation comments on static or instance endpoint-handler methods become OpenAPI summaries and parameter descriptions through Swashbuckle. Explain that the .NET SDK writes the comments to an XML file during the build and Swashbuckle reads that file at startup.
Why it matters: This lets you keep familiar C# documentation close to an endpoint handler while reusing it in the generated API description. - XML comment configuration steps: Explain the three required setup steps for XML-comment metadata: enable GenerateDocumentationFile in the project file, configure SwaggerGen to read the generated XML document, and use a static or instance method handler with XML comments.
Why it matters: All three pieces are needed before endpoint documentation comments can affect the generated OpenAPI description. - Handler support limitations: State that, in the described .NET 7 support, XML documentation comments work for static and instance method endpoint handlers but not for lambda methods or local functions. Distinguish this partial support from complete OpenAPI endpoint documentation.
Why it matters: Knowing the handler limitation prevents expecting XML comments on a minimal API lambda to appear in OpenAPI. - Metadata investment choices: Justify choosing the amount of OpenAPI metadata based on its use: minimal metadata can be appropriate for local Swagger UI testing, whereas generated C# clients or a public API benefit from richer descriptions. Describe conditionally adding Swagger services and middleware only in development when OpenAPI is solely for local testing.
Why it matters: The right documentation effort depends on whether OpenAPI is only a local testing aid or a contract consumed by clients and external users.
Key terms: XML documentation comments, Swashbuckle, OpenAPI description, GenerateDocumentationFile, SwaggerGen, csproj, PropertyGroup, static method handler, .NET 7, static method endpoint handlers
11.6 Knowing the limitations of OpenAPI
This section introduces the caveat that OpenAPI and Swagger have limitations, especially for increasingly complex APIs, before examining those challenges.
- OpenAPI limitation awareness: Explain that although OpenAPI and Swagger support API testing and code generation, they also have limitations that can become more significant as an API grows in complexity.
Why it matters: Recognizing these limits helps you use generated API descriptions and tools with appropriate expectations.
Key terms: OpenAPI, Swagger, Swagger UI, code generation
11.6.1 Not all APIs can be described by OpenAPI
This section explains why OpenAPI cannot fully describe certain dynamic, aggregated, or unusually secured APIs.
- OpenAPI description boundaries: Explain that OpenAPI is intended to tell clients how to call an API, but it deliberately does not cover every possible REST API style. Describe that its limitations arise when endpoint responses or available operations cannot be known in advance.
Why it matters: Knowing OpenAPI's boundaries helps you avoid treating a generated specification as a complete model of every API design. - HATEOAS dynamic links: Describe HATEOAS as a REST design in which responses include links for actions a client can take and the paths for those actions. Explain that the server can change those links according to resource state or user, so OpenAPI cannot predefine all endpoint responses and available actions.
Why it matters: HATEOAS illustrates the key mismatch between an API that advertises actions dynamically and a specification that expects them to be known beforehand. - API gateway specification aggregation: Describe the API-gateway scenario in which multiple backend APIs each have their own OpenAPI specification but clients use one unified gateway API. State that there is no easy way to combine those backend specifications into one unified document for the gateway that clients can test against or use for code generation.
Why it matters: A gateway can simplify access for clients while making it harder to offer one accurate OpenAPI contract for the combined API. - Authentication workflow support: Explain that OpenAPI can describe authentication requirements and Swagger UI supports them, but extensions to common authentication protocols or advanced authentication features may not be supported by Swagger UI. State that an unsupported workflow can make Swagger UI unusable for that API.
Why it matters: Documenting an authentication scheme does not guarantee that an interactive documentation tool can execute the real authentication flow.
Key terms: OpenAPI specification, REST APIs, Hypertext As the Engine of Application State, HATEOAS, links, resource state, backend APIs, API gateway, unified API, code generation
11.6.2 Generated code is opinionated
This section explains that generated API clients reflect their generator's design choices, so customization costs, exception behavior, and incompatible generated types can sometimes outweigh their benefits.
- Generated client trade-offs: Explain why OpenAPI client generation is beneficial only when the generated code fits the application's needs, and why extensive customization can make writing a client manually simpler.
Why it matters: Generated code can save substantial effort, but only if its conventions and maintenance cost work for your application. - Exception-oriented generated clients: Describe the complaint that some generated clients use exceptions for ordinary process flow when an API returns an error or unexpected status code, and state the resulting costs for callers.
Why it matters: A client's error-handling design affects both runtime cost and how much handling code every API call requires. - Cross-client Product type mismatch: Explain why Product objects generated from separate but related OpenAPI documents cannot necessarily be passed directly between their generated clients, even when their properties and JSON representation match.
Why it matters: Separate generated clients can create distinct C# types that require explicit conversion at integration boundaries.
Key terms: code generation, OpenAPI documents, generated client, NSwag, exceptions, process flow, error status code, unexpected status code, ProductsClient, CartClient
11.6.3 Tooling often lags the specification
This section explains why independently evolving OpenAPI tools can limit a documentation and client-generation workflow, and when OpenAPI is worth adopting despite those limits.
- OpenAPI tooling chain: Describe the roles of the OpenAPI specification, ASP.NET Core metadata tooling, Swashbuckle, NSwag, and Swagger UI in producing an OpenAPI document, generated clients, and an API-testing interface.
Why it matters: Knowing which tool performs each step helps you locate the source of a documentation or client-generation limitation. - Specification and tooling lag: Explain why support for an OpenAPI feature can fail across a tool chain even when the OpenAPI specification defines it, and describe the greater risk when using newer or less popular features.
Why it matters: A standard feature is useful only when the generators and consumers in your chosen tool chain support it. - OpenAPI adoption trade-offs: Justify when a light investment in OpenAPI is worthwhile and when heavy investment may not be worthwhile, based on simple requirements and Swagger UI testing versus complex requirements, hard-to-describe APIs, or dissatisfaction with generated code.
Why it matters: Choosing the scope of OpenAPI adoption prevents spending heavily on tooling that does not fit the API or development style. - gRPC code-generation alternative: State that gRPC is an alternative worth considering for developers who like code generation but prefer an RPC programming style, and note its robust multi-language code-generation support and .NET support.
Why it matters: gRPC may better fit a code-generation workflow when an RPC-style API is preferred over the OpenAPI approach.
Key terms: OpenAPI specification, OpenAPI Initiative, ASP.NET Core metadata, Swashbuckle, NSwag, Swagger UI, tool chain, OpenAPI-compatible document, OpenAPI documents, code generation
11.7 Summary
This summary recaps how to generate, expose, enrich, consume, and recognize the limits of OpenAPI descriptions for ASP.NET Core APIs.
Where this is used later
- Describing your authentication requirements to OpenAPI (chapter 25) · Authentication requirements are described to OpenAPI using endpoint metadata.
- Applying authorization policies to minimal API endpoints (chapter 25) · Authorization policies are applied to minimal API endpoints using metadata.
- Using typed clients to encapsulate HTTP calls (chapter 33) · Typed HttpClient clients benefit from generated clients that take their base address from HttpClient rather than a primitive constructor argument.
- Creating your first web API project (chapter 20) · The section notes that OpenAPI descriptions can include controller endpoints as well as minimal API endpoints.
- (chapter intro) (chapter 20) · The idea that API tooling and representations have limitations.
Concepts explained in this chapter
- OpenAPI specificationAn OpenAPI document is a structured document that describes an HTTP API's available URLs, operations, parameters, and data types according to the OpenAPI standard.
- generated clientClient code generation is the automatic production of source code for calling an API from an API description.
- NSwagNSwag is a .NET library and toolset for generating OpenAPI documents and generating clients from API descriptions.
- code generationCode generation is the automated production of source code or related artifacts from a higher-level description or specification.
- SwashbuckleSwashbuckle is a .NET library that generates OpenAPI documents and provides middleware for serving and visualizing them in ASP.NET Core applications.
- OpenApiReferenceOpenApiReference is a .NET project configuration element that specifies an OpenAPI service reference for client code generation.
- doc commentAn XML documentation comment is a structured C# source-code comment whose XML content documents program elements for tooling and generated documentation.
- Swagger UISwagger UI is a web-based interface that visualizes an API description and enables interactive API requests.
- .NET toolA .NET global tool is a .NET CLI tool installed for use across projects and invoked from the command line.
- operation idAn operation ID is a unique identifier for an API operation in an OpenAPI description that can be used by tooling when naming generated client methods.
- NSwag.ApiDescription.ClientNSwag.ApiDescription.Client is a .NET package that generates client code from API descriptions, including OpenAPI descriptions.
- System.Text.JsonSystem.Text.Json is the .NET library for reading and writing JSON data.
- partial methodA partial method is a C# method declaration that may be implemented in another part of the same partial type and omitted at compile time when unimplemented.
- metadataMetadata is descriptive information attached to an endpoint that can be inspected or used by framework components.
- NuGetA NuGet package is a distributable package containing a .NET library or other reusable assets together with metadata and dependency information.
- Visual StudioVisual Studio is Microsoft's integrated development environment for building, debugging, and managing software projects.
- projectA project is a .NET unit of deployment containing the source files and configuration needed to build an application or library.
- WithNameWithName is an ASP.NET Core endpoint-mapping method that assigns a name to an endpoint as metadata.
- HTTP 404 errorThe HTTP 404 status code indicates that the server cannot find the resource or endpoint identified by the request path.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
