I'm working on documentation for an API server implemented using ServiceStack. I have a few questions. If it makes more sense, I can move these to separate posts.
IgnoreDataMember is mentioned in multiple places as the way to hide DTO properties from metadata, but that's not an option if you publish the message to queue since that works via serialization and it skips those fields...
The Exclude attribute [Exclude(Feature.Metadata)] is supposed to hide DTO's from the meatadata page. While it works at top-level classes, it doesn't filter out properties of a base class. In other words if MyBaseDto is marked to exlude, but MyEndpointDto inherits from MyBaseDto, properties from both classes are shown. Is this a bug?
Removing services from metadata works really well, but I don't see how to remove them from Swagger/OpenAPI. I can implement the OperationFilter callback, but there's no obvious way there to actually remove anything. If I use the ResourceFilterPattern regex property, it works by DTO, not route. I'd love to remove any route that starts with /internal for instance.
The LogoUrl property of the OpenApiFeature and SwaggerFeature doesn't seem to actually affect the page anywhere. Is there another step to take?
On the Swagger UI page, why does every route include the text " XX is not defined!" I'm not sure what's it's supposed to be pull from.
I need help understanding how OpenAPI and Swagger fit together. Why are they two separate features? If I just add the OpenAPI feature, I can still bring up the Swagger UI. What does the Swagger feature bring to the table?
The difference between ServiceStack's Swagger Feature and Open API is that Swagger Feature implements the older Swagger 1.2 spec where as Open API implements the newer Swagger 2.0 spec which has been renamed from Swagger. If you're unsure which to use, use the newer Open API.
Swagger UI is just the UI and ServiceStack bundles a version of the Swagger UI which works with both the older Swagger 1.2 spec as well as the newer Open API 2.0 spec.
[Exclude(Feature.Metadata)] or [ExcludeMetadata] works as intended, annotate it on DTOs you wish to exclude from ServiceStack's metadata services which also removes them being included in the returned Swagger/Open API spec + UI.
You can use the ApiDeclarationFilter to modify the entire OpenApiDeclaration before it's returned, you can remove routes by removing them from the Paths Dictionary and Types definitions from being included by removing them from Definitions Dictionary. You can submit other feature requests for missing features you want implemented.
The LogoUrl has been fixed for Open API and we've also added LogoHref so you can change the url that the logo goes to which by default refreshes the Swagger UI page. This change is available from v4.5.13 that's now available on MyGet.
Open API is the spec Swagger UI is the UI
The purpose of both Open API and Swagger plugins is to implement the Swagger specification which is a generic and machine readable json format to describe Service APIs. Only one of the benefits is to provide a dynamic UI which ServiceStack provides by bundling the Swagger UI that works with their respective API versions. Other purposes of implementing the Open API spec include enabling automated tooling like generating a Azure AutoRest client or importing your Service into Azure's Management API.
Related
I'm upgrading an ASP.NET Core API project from v5 to v6.
Service config in v5:
services.AddSwaggerGen();
Service config in v6:
builder.Services.AddEndpointsApiExplorer(); // what is this?
builder.Services.AddSwaggerGen();
What is AddEndpointsApiExplorer? Everything works as expected whether I add it or not.
I use the "ASP.NET API Versioning" library. Are they related? If so, must I use both, just the library, or is the library unnecessary now?
AddEndpointsApiExplorer is for Minimal APIs whereas AddApiExplorer requires, at least, MVC Core. For API projects, AddControllers calls AddApiExplorer on your behalf.
But Why Does Everything Still Work With AddEndpointsApiExplorer?
With the introduction of Endpoint Routing, everything in the routing system boils down to an Endpoint. ASP.NET Core uses the Application Model, namely ApplicationModel, ControllerModel, and ActionModel, to create Endpoint instances and register them with the routing system. Minimal APIs, however, use a builder to directly create and register individual Endpoint instances.
The default API Explorer implementation provides a IApiDescriptionProvider that builds ApiDescription instances from the Application Model. Minimal APIs do not have an Application Model so there is nothing to build ApiDescription instances from. The API Explorer provides these descriptions, which are commonly used by tools such as OpenAPI generators. Without any descriptions, there would be no support for Minimal APIs and OpenAPI; that would be bad (or, at least, certainly not accepted by developers). To address that, the ASP.NET Core team created a second IApiDescriptionProvider that only considers Endpoint.
If Everything is an Endpoint, Why Not Merge Implementations?
There's two parts to this answer. First, changing the original IApiDescriptionProvider implementation would introduce a public, breaking change. At a minimum, new constructor arguments would be required. Since it was a major version bump, this approach wasn't off the table, but it turns out to be irrelevant. The bigger issue is that the original IApiDescriptionProvider implementation and AddApiExplorer live in and depend on MVC Core. Minimal APIs only require the routing abstractions. There is no way to merge the two without adding unnecessary coupling. To address this problem, AddEndpointsApiExplorer was added which adds an implementation that only requires an IApiDescriptionProvider implementation based on bare bones Endpoint definitions from the routing system.
If AddEndpointsApiExplorer exists and I call it, do I even need AddApiExplorer anymore? Maybe. The metadata exposed and available on Minimal API Endpoint instances is much lighter than the Application Model; after all, they are minimal. Behind the scenes, a IApiDescriptionGroupCollectionProvider implementation takes a sequence of IApiDescriptionProvider instances. If AddEndpointsApiExplorer and AddApiExplorer are called, then both providers will execute. If only AddEndpointsApiExplorer is called, it will work with regular 'ol controllers, but the descriptions' information fidelity might be less than what you are accustomed to. If you are only authoring Minimal APIs, then AddEndpointsApiExplorer is required if you want API Explorer support.
The fidelity between the two methods is improving even more in .NET 7.0. In some future release, it's possible we might see these approaches coalesce into one.
TLDR; .AddEndpointsApiExplorer() was created to support Minimal Api's.
Searching the doc's via google shows a number of pages that include a call to .AddEndpointsApiExplorer(). But no mention of why you need it, or if it is required when migrating from a v5 project. The documentation is definitely lacking.
Working backwards from the source code & git blame, I found the related project. So the answer appears to be related to support for Minimal Api's.
I believe some new services were created to extract return type information from these new minimal api's, in a way that might apply in a more general way when using Endpoint Routing without MVC.
If you are using MVC, perhaps via .AddControllers(), .AddApiExplorer() would be called for you. Providing the services that swagger depends on for describing controller actions. If that's all you need, then this new api call doesn't seem to be required.
While the documentation for using swagger with minimal api's includes a call to .AddEndpointsApiExplorer(). Even that doesn't explain exactly why it is required.
Why does .AddEndpointsApiExplorer() exist at all? Why were the new features excluded from .AddApiExplorer()? Why was this method rename left out of other documentation for v6?
Perhaps we should create an issue on https://github.com/dotnet/aspnetcore/ or https://github.com/dotnet/AspNetCore.Docs/ to ask for clarification so that others don't have to ask these questions.
TL;DR
Only use AddEndpointsApiExplorer if you use v6's "minimal APIs", which look like this:
app.MapGet("/", () => "Hello World!");
EDIT: I'm aware of what attributes in general do, the question is for this specific attribute alone. Sorry for the confusion!
I've read the following question, along with this one, which point to how the attribute is used to ignore the generated swagger/swashbuckle documentation for specific methods or whole controllers. (documentation is the swagger page with all the api's listed I believe?)
But other than swagger/swashbuckle (which is a NuGet package), what other function does this attribute possess in ASP.NET?
When applied to a public method on a controller, it prevents that method from appearing in the swagger ui.
First of all, to clarify, an attribute in C# does not trigger anything by itself. External code searches for classes, methods or properties marked with a specific attribute, and act accordingly.
Of course, there are many building blocks in ASP.NET MVC, it can be confusing sometimes.
This attribute is used by Swagger to hide the endpoint.
Also usedd (in .NET core at least) by the given implementations of IApiDescriptionProvider and other related interfaces, but that would be effective only if you actually use them (by configuring them up in Startup.cs)
(for some more details and example, see https://andrewlock.net/introduction-to-the-apiexplorer-in-asp-net-core/)
This attribute helps to control the visibility. We can use this on the controller class or an action method when we want to hide that specific controller or action from showing in the swagger UI.
I am using Swashbuckle to embed Swagger documentation for our API into our .NET Web API 2.2 application (.NET 4.5). Up until now all the controllers have lived in the main Web API dll but as we start building out the API we are moving different version APIs to separate dlls.
When specifying a custom asset in Swashbuckle it is possible to specify 1 assembly for a resource path e.g. "v1" -> V1Assembly. However, I want to support the ability for the user to be able to view all API endpoints across all versions and assemblies. How do I make sure that this functionality is feasible with Swashbuckle? Essentially, I want a "all" or "index" endpoint on the help system to show all potential API Resources across all versioned assemblies.
My thought was a new feature that extends the SwaggerUiConfig to allow CustomAsset to accept an array of assemblies instead of just one so that we could interrogate multiple assemblies to generated the documentation instead of just the single one.
Any thoughts on how to accomplish this in the SwaggerConfig or otherwise?
If I understand correctly when you started versioning you ended up with multiple Web API.
You should consider refactoring your code using aspnet-api-versioning
All you will need to do in the controllers is identify them using something like:
[ApiVersion( "AreaOne" )]
https://github.com/Microsoft/aspnet-api-versioning/wiki/How-to-Version-Your-Service
For that Swashbuckle has full support.
I've got a Web API REST web service that is returning objects. I have installed Swagger.NET as well as Swagger UI. I'd like Swagger UI to list the fields inside of the objects being returned from the Web API REST methods. Is this possible?
From the Swagger documentation, Swagger.NET uses ApiExplorer to gather information about the Web API endpoints I have (classes that extend ApiController). Also, Swagger.NET looks at .NET doc comments (using '///'). I'm not sure how to describe the internals of these objects though.
Any ideas?
Thanks.
This is not supported currently out of the box. Following issue is related to it. You can vote up this:
http://aspnetwebstack.codeplex.com/workitem/877
I'm looking at developing an application in ASP.NET MVC 3 and would like to provide a public API at the same time.
From looking around, there seems to be 2 ways to go about it. Either create an API area and have controllers that return json / xml. Or use action filters and a single front end set of controllers, and have those return json / xml / html depending on the request headers.
I'd like to do the later, but I was wondering how you could go about versioning your api if you went this route?
If you go the first route, you could easily just create a v1 / v2 controller, but if you do the later, how could you version it?
Versioning is a rather complex issue to begin with. Here are ways I looked at before:
URL. In this case https://api.example.com/v1/projects is assumed to be a different resource than http://api.example.com/v2/projects, even though its not the case. Basecamp seems to do this. Following this approach, assume you'll always have to support old APIs.
Headers. The URLs remains the same, however, the client pass an additional HTTP header, say X-MYAPI-VERSION with each request with a value identifying the version of the API to use. The Google Documents List API do this. A potential problem with this approach is that HTTP headers may be stripped by intermediaries between the client and server.
Parameters. To circumvent the problem with option 2, you can pass the API version to use as a parameter (such as https://api.example.com/projects?v=3).
Media types. Here your URLs stay the same, however, users are required to specify the representation of the resources using the accept and content type headers. For example, a "project" can be presented using "application/vnd.mycompany.resource[-version][+format]" giving your representations of "application/vnd.mycompany.project-v1+json" for v1 json or "application/vnd.mycompany.project-v1+xml" for v1 xml. When you need a new version of a project comes along the mime type may look as follows "application/vnd.mycompany.project-v2+xml". Github seems to support that.
Part of payload. In this case the payload of the request contains the version number to use. For example, when XML is passed, you can look at the namespace to determine which version of the API is being used. For JSON, you can use a "$version" or "_version" property to specify the version.
Client Key. When the application is registered, it specifies which version of the API it wants to use. When you authenticate the client, you ensure that you emulate the version it wants to use.
No explicit versioning There is always the option not to version your API and try to handle changes transparently by making all fields optional and handle them appropriately when they are missing. Chances are you will be doing this anyways to make future versions of your API compatible with the version you are developing today.
Many recommend option 4, although its not always practical. Most of these options require additional work to get working with ASP.NET MVC.
You can go one of two routes - you can include the API in the route (instead of http://app.lication/category/1 you would have something like http://app.lication/api/v1/category/1) or you could include a custom HTTP header.
Either will allow you to discriminate which version's being called.