├── LICENSE └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Muhammad Azeez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Awesome ASP.NET Core API 2 | 3 | > This repo was originally [a blog post](https://mazeez.dev/posts/asp-net-core-api-checklist). 4 | 5 | Building modern APIs require a lot of things to make them reliable, observable, and scalable. In no particular order, here are some of them that help you build better APIs: 6 | 7 | ## 1. Healthchecks 8 | Healthchecks are important in making sure that we know when anything happens to our APIs. We can setup dashboards to monitor them and setup alerting to let us know when one of the APIs is unhealthy. They are also important when deploying your apps to kubernetes. Kubernetes can monitor healthchecks of your APIs and automatically try to kill the unhealthy instances and create new instances to take their place. 9 | 10 | There are two kinds of healthchecks: 11 | 12 | - **Liveliness:** indicates if your API has crashed and must be restarted. 13 | 14 | - **Readiness:** indicates if your API has been intialized and is ready for processing requests. When launching a new instance of an API, it might need some time to intialize dependencies and load data to be ready. 15 | 16 | ### More Information: 17 | - [MS Docs - Health checks in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks) 18 | - [IAmTimCorey - Intro to Health Checks in .NET Core](https://www.youtube.com/watch?v=Kbfto6Y2xdw) 19 | 20 | ## 2. Logging 21 | Logging provides valuable information when trying to debug unexpected behavior. But too much logging can significantly slow down our APIs. For that reason we can set the logging level to `Warning` in production and only lower it when we need to. 22 | 23 | By default ASP.NET Core provides an abstraction layer for logging that supports [Structured Logging](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0#log-message-template). 24 | 25 | A very popular logging library that many people use with ASP.NET Core is [Serilog](https://serilog.net/). Serilog has more [Sinks](https://github.com/serilog/serilog/wiki/Provided-Sinks) than the default ASP.NET Core loggging abstraction and can easily be integrated with ASP.NET Core. 26 | 27 | ### More information: 28 | - [MS Docs - Logging in .NET Core and ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging) 29 | - [IAmTimCorey - C# Logging with Serilog and Seq - Structured Logging Made Easy](https://www.youtube.com/watch?v=_iryZxv8Rxw) 30 | 31 | ## 3. Observability 32 | 33 | This includes a few things: 34 | 35 | 2. Performance monitoring (P99, P95, P50) 36 | 3. Metrics: Specific counters you or your business cares about 37 | 4. Tracing: Being able to see the entire lifecycle of each request from frontend to API to data source. 38 | 39 | [OpenTelemetry](https://opentelemetry.io/) is an open standard for doing all of the above and [ASP.NET Core supports it](https://devblogs.microsoft.com/aspnet/observability-asp-net-core-apps/). The good news is, if you use OpenTelemetry, there is a rich ecosystem of tools and services that you can integrate with. 40 | 41 | All of the major cloud providers have services that you can use to view the captured data. 42 | 43 | ## 4. Error reporting 44 | There are tools specifically for capturing, storing and showing exceptions that have been raised in your APIs. They the exceptions by their type and location and show how many times they have occurred. Some tools include: 45 | 46 | - [Sentry](https://sentry.io) 47 | - [Rollbar](https://rollbar.com/) 48 | - [Raygun](https://raygun.com/) 49 | 50 | ## 5. Status Endpoint 51 | 52 | It's also good to have a status endpoint in your API that shows the name of the API, version of the API and when was it started. This can be used to create a dashboard showing all of the different services and their versions. Something like this: 53 | 54 | ```csharp 55 | using Microsoft.AspNetCore.Mvc; 56 | 57 | using System; 58 | using System.Diagnostics; 59 | 60 | namespace MyCoolApi.Controllers 61 | { 62 | public class StatusResponse 63 | { 64 | public string Name { get; set; } 65 | public string Version { get; set; } 66 | public DateTime StartTime { get; set; } 67 | public string Host { get; set; } 68 | } 69 | 70 | [ApiController] 71 | [Route("status")] 72 | public class StatusController 73 | { 74 | [HttpGet] 75 | public StatusResponse Get() 76 | { 77 | var version = typeof(Startup).Assembly.GetName().Version; 78 | 79 | return new StatusResponse 80 | { 81 | Name = "my-cool-api", 82 | Version = $"{version.Major}.{version.Minor}.{version.Build}", 83 | StartTime = Process.GetCurrentProcess().StartTime, 84 | Host = Environment.MachineName 85 | }; 86 | } 87 | } 88 | } 89 | ``` 90 | 91 | ## 6. Http Resiliency 92 | 93 | Although it's generally preferred for your APIs to communicate with other APIs using asynchronous messaging, sometimes you need to call other APIs using HTTP calls. 94 | 95 | We need to bake in some level of resiliency by automatically retrying transient failures. This can easily be done by using something like [Polly](https://github.com/App-vNext/Polly). 96 | 97 | ### More information: 98 | 99 | - [Implement HTTP call retries with exponential backoff with IHttpClientFactory and Polly policies](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly) 100 | - [Bryan Hogan - Fault Tolerant Web Service Requests with Polly](https://app.pluralsight.com/library/courses/polly-fault-tolerant-web-service-requests) 101 | 102 | ## 7. Statelessness and Containerization 103 | 104 | Containers are a great way to make sure your APIs can be easily scaled out and deployed to multiple environments in a repeatable manner. However to make sure you can get the most out of containerization you should try to make sure your APIs are stateless. 105 | 106 | Being stateless means that they don't hold any critical data in memory. For caching you can use a centralized caching technology like [Redis](https://redis.io/) instead. This way you can start as many instances as you need without worrying about having stale cached data or data duplication. 107 | 108 | You must also be careful about background jobs. You must make sure the different instances don't process background jobs multiple times. And for message queues, you have to implement the [Competing Consumers](https://docs.microsoft.com/en-us/azure/architecture/patterns/competing-consumers) pattern which some message buses support natively. 109 | 110 | ### More information: 111 | 112 | - [MS Docs - Tutorial: Containerize a .NET Core app](https://docs.microsoft.com/en-us/dotnet/core/docker/build-container) 113 | - [Hangfire](https://www.hangfire.io/) 114 | - [Quartz.NET](https://www.quartz-scheduler.net/) 115 | - [MS Docs - Competing Consumers](https://docs.microsoft.com/en-us/azure/architecture/patterns/competing-consumers) 116 | 117 | ## 9. OpenAPI Spec / Swagger 118 | 119 | Documenting your APIs is very important. Swagger integrates with ASP.NET Core and automatically finds all of the routes (Controller actions) and shows them in a beautiful dashboard that you can customize. 120 | 121 | ### More information: 122 | - [MS Docs - ASP.NET Core web API documentation with Swagger / OpenAPI]((https://docs.microsoft.com/en-us/aspnet/core/tutorials/web-api-help-pages-using-swagger?view=aspnetcore-5.0)) 123 | - [Kevin Dockx - Documenting an ASP.NET Core API with OpenAPI / Swagger](https://www.pluralsight.com/courses/aspdotnet-core-api-openapi-swagger) 124 | 125 | ## 10. Configuration and Options 126 | 127 | ASP.NET Core has an extensible configuration mechanism. It can pull configurations from json files, environment variables and command line arguments. You can also provide custom sources for configuration. It also provide ways to easily fetch the configurations in a type-safe manner. it also provides an easy mechanism to [validate the configuration sections](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-5.0#options-validation). 128 | 129 | ### More information: 130 | 131 | - [MS Docs - Options Pattern in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options) 132 | - [Steve Gordon - Using Configuration and Options in .NET Core and ASP.NET Core Apps](https://www.pluralsight.com/courses/dotnet-core-aspnet-core-configuration-options/) 133 | - 134 | ## 11. Integration and Unit Tests 135 | 136 | ASP.NET Core has made it easy to write Unit tests by making the whole framework DI friendly. It has also made Integration tests easy by [`WebApplicationFactory`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.testing.webapplicationfactory-1) Having automated tests saves a lot of time and makes your APIs more robust. And when writing integration tests, try to use the same database technology that you use for production. If you're using Postgres in production, don't use Sqlite or In-Memory DB Providers for integration tests. 137 | 138 | ### More information: 139 | 140 | - [MS Docs - Integration tests in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests) 141 | - [Steve Gordon - Integration Testing ASP.NET Core Applications: Best Practices](https://www.pluralsight.com/courses/integration-testing-asp-dot-net-core-applications-best-practices) 142 | 143 | ## 12. Build beautiful REST APIs 144 | 145 | If you're building REST APIs, there are some conventions that make your APIs more pleasant and intuitive to use. 146 | 147 | ### More information: 148 | 149 | - [Stackoverflow Blog - Best practices for REST API design](https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/) 150 | - [Martin Fowler - Richardson Maturity Model](https://martinfowler.com/articles/richardsonMaturityModel.html) 151 | 152 | ## 13. Authentication and Authorization 153 | 154 | Authentication is the process of identifying a user and authorization is knowing and enforcing what each user can and can't do. The most popular standards for authentication is OpenIDConnect which is an authentication layer on top of OAuth 2. 155 | 156 | There are some popular Identity Providers that you can easily integrate with your API: 157 | 158 | - [Auth0](https://auth0.com/) 159 | - [Okta](https://www.okta.com/) 160 | - [FusionAuth](https://fusionauth.io/) 161 | 162 | And there are some open source Identity and Access Management servers that you can run on-prem: 163 | 164 | - [Keycloak](https://www.keycloak.org/) 165 | - [Gluu](https://gluu.org/) 166 | 167 | And there are some libraries that you can use to build your own OIDC server: 168 | 169 | - [IdentityServer](https://duendesoftware.com/) 170 | - [OpenIddict](https://github.com/openiddict/openiddict-core) 171 | 172 | ### More information 173 | 174 | - [Kevin Dockx - Securing ASP.NET Core 3 with OAuth2 and OpenID Connect](https://app.pluralsight.com/library/courses/securing-aspnet-core-3-oauth2-openid-connect) 175 | - [Kevin Dockx - Securing Microservices in ASP.NET Core](https://app.pluralsight.com/library/courses/securing-microservices-asp-dot-net-core) 176 | 177 | ## 14. Security 178 | 179 | ### 14.1 CORS 180 | 181 | Cross-Origin Resource Sharing allows frontends to call your API even if they are not on the same domain as the API. By default in ASP.NET Core CORS is disabled. 182 | 183 | #### More information 184 | 185 | - [MS Docs - Enable Cross-Origin Requests (CORS) in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/security/cors) 186 | 187 | ### 14.2 HTTPS Enforcing 188 | 189 | For this there are two scenarios: 190 | 191 | - You're using Kestrel on edge: Then you have to make sure it's only listening to and respond over HTTPS. 192 | - You've put ASP.NET Core behind a reverse proxy: Then you generally terminate HTTPS on the proxy and it's the proxy's job to enforce HTTPS. 193 | 194 | #### More Information 195 | 196 | - [MS Docs - Enforce HTTPS in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl) 197 | 198 | ### 14.3 Cross-Site Scripting (XSS) 199 | 200 | Cross-Site Scripting (XSS) is a security vulnerability which enables an attacker to place client side scripts (usually JavaScript) into web pages. You can prevent it by sanitizing inputs from the user. 201 | 202 | #### More Information 203 | 204 | - [Prevent Cross-Site Scripting (XSS) in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/security/cross-site-scripting) 205 | 206 | ## 15. API Versioning 207 | 208 | Versioning your APIs allow you to maintain backward compatibility when making breaking changes. You can maintaing multiple versions at the same time and then deprecate versions over time. 209 | 210 | ### More Information 211 | 212 | - [Overview of API Versioning in ASP.NET Core 3.0+](https://exceptionnotfound.net/overview-of-api-versioning-in-asp-net-core-3-0/) 213 | 214 | --------------------------------------------------------------------------------