Поиск  
Always will be ready notify the world about expectations as easy as possible: job change page
Apr 28, 2022

8 quick tips to improve your .NET API

Автор:
Lucas Diogo
Источник:
Просмотров:
2555

Day-to-day tips I use to develop APIs.

Every day we need to develop new APIs, whether at work or for study purposes, and some features can help us with the use of good practices in a simple way. And through this post, I want to show you some features that I use daily.

1. API Versioning

One of the challenges for those who build APIs is changing contracts that are already in use in the production environment. Clients may not want to update their applications when the API changes, so a versioning strategy becomes crucial.

A versioning strategy allows clients to continue using the existing REST API and migrate their applications to the newer API when they are ready.

In .NET, we can versioning our APIs through the addApiVersioning extension.

This API versioning can be parameterized with some options, including the default version or even how the versioning will be done, whether by URL, header, or media type. For more details, you can access the official documentation.

After the configuration performed above, it is necessary to inform the API version through the attribute. If it has been configured by URL, it will be necessary to parameterize it.

And in the API specification, you will get the following result.

2. Global Exception Handler

Instead of creating lots of try-catch throughout the code to handle unexpected errors by our application, we can simply create a middleware that handles exceptions globally. 

using System.Net;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;

namespace Sample.Identity.API.Midlewares
{
    public class ExceptionMiddleware
    {
        private readonly RequestDelegate next;
        private readonly IHttpContextAccessor accessor;
        private readonly ILogger<ExceptionMiddleware> logger;

        public ExceptionMiddleware(RequestDelegate next, IHttpContextAccessor accessor, ILogger<ExceptionMiddleware> logger)
        {
            this.next = next;
            this.logger = logger;
            this.accessor = accessor;
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await next.Invoke(context);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, $"An error was ocurred during the process. Trace Identifier: {accessor.HttpContext.TraceIdentifier}.");

                await HandleExceptionMessageAsync(accessor.HttpContext).ConfigureAwait(false);
            }
        }

        private static Task HandleExceptionMessageAsync(HttpContext context)
        {
            string response = JsonSerializer.Serialize(new ValidationProblemDetails()
            {
                Title = "An error was occurred.",
                Status = (int)HttpStatusCode.InternalServerError,
                Instance = context.Request.Path,
            });

            context.Response.ContentType = "application/json";
            context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

            return context.Response.WriteAsync(response);
        }
    }
}

And finally use it.

app.UseMiddleware<ExceptionMiddleware>();

You can check out more about how middleware works in .NET here: ASP.NET Core Middleware

3. Enable JWT in Swagger

When our application uses bearer token authorization, to be able to test it in the swagger, it is necessary to perform the configuration below.

using Microsoft.OpenApi.Models;

namespace Sample.Identity.API.Configuration
{
    public static class SwaggerConfiguration
    {
        public static void AddSwaggerConfiguration(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Version = "v1",
                    Title = "Sample.Identity.API",
                    Description = "Web api to provide authentication services"
                });

                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    In = ParameterLocation.Header,
                    Description = "Please insert JWT with Bearer into field",
                    Name = "Authorization",
                    Type = SecuritySchemeType.ApiKey
                });

                c.AddSecurityRequirement(new OpenApiSecurityRequirement {
                   {
                     new OpenApiSecurityScheme{Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme, Id = "Bearer"}}, Array.Empty<string>()
                   }
                });
            });
        }

        public static void ConfigureSwagger(this IApplicationBuilder app)
        {
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Sample.Identity.API v1"));
        }
    }
}

After that, it will be possible to insert a JWT token generated for authorization in the Swagger.

4. Access HTTP information behind a proxy.

When HTTPS requests are proxied over HTTP, the original scheme (HTTPS) is lost and must be forwarded in a header. Because an app receives a request from the proxy and not its true source on the Internet or corporate network, the originating client IP address must also be forwarded in a header.

This happens even in environments like, for example, when we are trying to capture the IP address through HttpContext.Connection.RemoteIpAddress in a docker container application.

For more information, you can access the link: Configure ASP.NET Core to work with proxy servers and load balancers

To solve it, we can use ForwardedHeaders middleware.

And then use it.

app.UseForwardedHeaders();

After that, instead of getting the proxy’s IP, it will have the X-Forwarded-For header when the request is forwarded. With these settings, the application will replace by the IP forwarding in the header.

5. IHttpContextAccessor instead of HTTP context

The IHttpContextAccessor is an interface to access HTTP context in .NET, and because it uses dependency injection, it is extremely useful when we need some information in service layers.

There are some good performance practices in its use. You can see it on the official Microsoft documentation: ASP.NET Core Performance Best Practices.

First, we need to inject it.

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

Check an example, accessing HTTP context by IHttpContextAccessor.

6. Problem Details

An RFC called Problem Details (RFC7807) standardizes how an error in an API should be responded to for the client. If you use Fluent validation, you may have noticed that the response is within this pattern.


Response generates by fluent validation.

However, there is a class that also implements this pattern, you can find the documentation here: ProblemDetails Class.

As good implementation practices, it is always important to follow the patterns of some RFCs, it provides a better design.

7. HTTP Logging

HTTP Logging is a middleware that logs information about HTTP requests and responses. This middleware is extremely useful for visibility using logs, but it’s extremely important to keep two things in mind.

Evaluate its use for sensitive data and that this middleware can reduce application performance, especially when logging the request and response bodies, so it is important to be aware of its configuration.

You can find more about it in the documentation: HTTP Logging in ASP.NET Core

app.UseHttpLogging();

8. Health checks

Health checks are exposed by an app as HTTP endpoints and are typically used with an external monitoring service or container orchestrator to check the status of an app. Before adding health checks to an app, decide on which monitoring system to use. The monitoring system dictates what types of health checks to create and how to configure their endpoints.

You can add the following code to the pipeline:

builder.Services.AddHealthChecks();

Here is an example implementation in the official Microsoft documentation:

In addition to exporting a health check, you can also use a UI to monitor all of your endpoints and even database connections.

The following example demonstrates the layout of the health checker UI:

Above are listed some main components and patterns that I use in my day-to-day when building APIs. NET.

 


That’s all folks!

 

Похожее
Apr 1
Author: Ravindra Devrani
Fluent validation is a third party library for validating your models in .NET. It is totally free. Why fluent validation? If you already have used data annotation for validation, then you must be aware of validation in .NET. So you...
Feb 10, 2023
Author: Abdelmajid BACO
A Quick Guide to Transient, Scoped, and Singleton in C#. In C#, the Transient, Scoped, and Singleton scopes are options for controlling the lifetime of objects which are created by dependency injection. Transient Transient objects are created each time they...
May 14, 2023
Author: Ravi Raghav
What is Kafka? Kafka is a distributed streaming platform developed by the Apache Software Foundation. It is designed to handle high-volume, real-time data streams and is commonly used for building data pipelines, stream processing applications, and real-time analytics. At its...
Jul 29
Author: C# Programming Obinna “Anderson” Asiegbulam
Introduction Open Data Protocol (OData) is a standard protocol for building and consuming RESTful APIs. It extends traditional REST-based data access techniques by providing a uniform way to expose, structure, and manipulate data. Originally developed by Microsoft, OData is widely...
Написать сообщение
Тип
Почта
Имя
*Сообщение
RSS
Если вам понравился этот сайт и вы хотите меня поддержать, вы можете
Using a сustom PagedList class for Generic Pagination in .NET Core
Дюжина логических задач с собеседований
Почему вы никогда не должны соглашаться на собеседования с программированием
«Великое увольнение» продолжается: теперь с работы уходят даже боссы
Soft skills: 18 самых важных навыков, которыми должен владеть каждый работник
5 приемов увеличения продуктивности разработчика
Зарплата по результатам собеседования — лучший способ сократить отклики на вакансию, а тестовые задания — избыточны
9 тяжёлых уроков, которые я усвоил за 18 лет разработки
8 вещей, которых не должен бояться разработчик
Рассуждение на тему, какую базу данных выбирать
LinkedIn: Sergey Drozdov
Boosty
Donate to support the project
GitHub account
GitHub profile