February 20, 2023
When a team builds an API, it’s usually important to agree on a common set of style, formatting and behaviour conventions to improve consistency across the API endpoints. As well as promoting readability and understanding across the team, standard conventions can also improve API security.
Once you have chosen some rules, it’s a good idea to enforce them - and to automate that process as much as possible. While there are many code style tools available such as StyleCop and SonarQube, creating custom rules under these tools can be complicated.
This blog post explores simple tests you can write to check your ASP .NET Core API’s conventions using the ApiExplorer namespace.
If you’re writing a .NET Core Api with generated OpenApi / Swagger documentation, then you’re using ApiExplorer already! It’s included by default with many of the ASP.NET Core templates and you can find the nuget package here: https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.ApiExplorer/
ApiExplorer provides reflection logic for your API endpoints including “metadata such as the list of controllers and actions, and their URLs and allowed HTTP methods“.
OpenAPI Generators such as Swashbuckle use ApiExplorer to determine the endpoints in your app and generate OpenAPI specification. We can use this same namespace ourselves to query details about our API and write unit tests to confirm our APIs follows our team’s conventions.
First, register ApiExplorer dependencies in the Dependency Injection configuration for your API
This config alone is enough to start using ApiExplorer from inside your API requests as per this blog post: https://andrewlock.net/introduction-to-the-apiexplorer-in-asp-net-core/
But to leverage this explorer from a Unit test, we need to do a little more. API Explorer will find and document APIs in the current API assembly but when we’re running a unit test, we startup from the testing assembly. When I tried accessing the Api Explorer under a unit test context, it would return no found API Endpoints.
The solution I found was to use WebApplicationFactory.
WebApplicationFactory is designed for ASP.NET Core integration testing. For this use case, it will bootstrap enough of the ASP.NET Core framework under a testing context to allow the API explorer to correctly scan the API Assembly and report back on found endpoints.
You can find an introduction to WebApplicationFactory usage here: https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-7.0
We can obtain an instance of IApiDescriptionGroupCollectionProvider from WebApplicationFactory via Services.GetService<IApiDescriptionGroupCollectionProvider>
This rule relates to two items on the OWASP API Security Top 10:
If your app is an ASP.NET API that uses Entity Framework for database access, a remediation for the above is to avoid binding your persisted entity classes directly to the API endpoints using view models or DTOs to limit the API-exposed schema.
Using ApiExplorer, we can get a list of classes that have been bound to the API and compare it to the list of classes bound to Entity Framework.
This isn’t the only rule you can write! The ability to query detailed information about your API’s public interface can become a powerful tool when checking expected API behaviours across your projects.