Simplifier l’intégration de l’API avec Refit

La simplification de l’intégration avec les API réduit le code passe-partout et rend l’application plus modulaire, réduisant ainsi le couplage et aboutissant à un code plus propre et plus concis. Découvrez comment utiliser Refit dans ce processus et les meilleures ressources pour gérer les requêtes entre les API.
Les applications modernes utilisent des interfaces de programmation d’applications (API) pour recevoir et envoyer des données ou des commandes. Cependant, créer des clients HTTP pour utiliser ces API peut être épuisant et sujet aux erreurs. Heureusement, certains outils rendent ce processus plus simple et plus efficace. L’un de ces outils est Refit, une bibliothèque puissante qui facilite l’intégration des API dans les applications ASP.NET Core.
Cet article vous apprendra comment configurer et utiliser Refit dans une application ASP.NET Core. Nous couvrirons tout, de la configuration initiale à la création de clients API et aux appels HTTP. De plus, nous verrons comment implémenter un système d’authentification simple utilisant JWT et comment configurer Refit pour recevoir le jeton d’authentification. À la fin de l’article, vous verrez comment Refit peut simplifier considérablement l’interaction avec les API, rendant votre code plus propre et plus facile à maintenir.
Comment les requêtes entre les API sont-elles effectuées ?
Dans les applications web, pour demander une API externe, il est courant d’implémenter un client API. Un client API dans le développement logiciel fait référence à un composant ou à une couche de l’application chargé d’effectuer des requêtes et des interactions avec des API externes.
Le client API encapsule la logique nécessaire pour envoyer des requêtes HTTP aux points de terminaison de l’API, traiter les réponses reçues et sérialiser/désérialiser les données entre des formats tels que JSON.
Par défaut, ASP.NET Core a le HttpClient
classe dans le System.Net.Http
espace de noms qui est utilisé pour envoyer une requête HTTP et recevoir la demande-réponse.
Bien que HttpClient soit une classe puissante pour effectuer des requêtes HTTP dans les applications ASP.NET Core, certains inconvénients doivent être pris en compte. Par exemple, la nécessité d’une configuration et d’une gestion manuelles des instances HttpClient. De plus, il peut être nécessaire de gérer les délais d’attente, les en-têtes et les gestionnaires, ce qui entraîne une plus grande complexité et peut entraîner des erreurs s’il n’est pas géré correctement.
Un autre facteur moins favorable de HttpClient est qu’il a moins d’abstraction et une plus grande complexité par rapport à d’autres ressources telles que les bibliothèques tierces, qui peuvent fournir une abstraction de haut niveau via des interfaces typées, tandis que HttpClient nécessite plus de code passe-partout pour configurer et envoyer des requêtes.
Dans les scénarios où les applications effectuent de nombreux appels à des API externes, une utilisation excessive de HttpClient peut entraîner un code plus détaillé et moins lisible.
Refit : une bonne alternative à HttpClient
Dans les scénarios qui nécessitent plusieurs appels à des API externes, une bonne alternative à HttpClient est Remonter. Refit est une bibliothèque pour ASP.NET Core qui offre une approche plus simplifiée, élégante et productive de l’intégration avec les API HTTP.
Refit vous permet de définir des interfaces C# simples et fortement typées pour décrire les points de terminaison de l’API, éliminant ainsi le besoin d’écrire manuellement du code passe-partout pour construire des URL, configurer des en-têtes, sérialiser/désérialiser des objets JSON et d’autres détails de bas niveau. Refit encapsule tous ces paramètres standard, permettant une personnalisation si nécessaire.
De plus, Refit utilise des attributs pour configurer les détails de la requête HTTP, tels que l’authentification et la mise en cache. Cela fournit une configuration des requêtes plus déclarative et simplifiée, rendant le code plus intuitif. Un autre avantage de Refit est qu’il simplifie la gestion des erreurs basée sur les codes d’état HTTP renvoyés par les API.
Pratique avec Refit
Dans cet article, nous allons créer les configurations de base de Refit, et après avoir ajouté une couche d’authentification à l’API externe, pour cela, nous créerons deux API. Le premier (CustomerAPI) demandera le second (CustomerAdditionalInfoApi). Cette demande se fera via Refit, où nous explorerons quelques détails et verrons comment il est possible de faciliter l’intégration avec des API externes.
Le code complet du projet est accessible dans ce référentiel sur GitHub : Code source du gestionnaire de clientèle.
Création des applications
L’exemple de l’article utilise .NET version 8, vous pouvez créer l’exemple d’application dans des versions plus anciennes, mais des problèmes peuvent survenir et ne sont pas abordés dans l’article.
Pour créer la solution et les deux projets API, vous pouvez utiliser les commandes suivantes :
dotnet new sln -n CustomerManagement
dotnet new web -n CustomerApi
dotnet new web -n CustomerAdditionalInfoApi
dotnet sln add CustomerApi/CustomerApi.csproj
dotnet sln add CustomerAdditionalInfoApi/CustomerAdditionalInfoApi.csproj
Ensuite, vous pouvez ouvrir le projet de solution avec votre IDE préféré. Cet article utilise Visual Studio.
La première API sur laquelle nous allons travailler est CustomerApi. Ouvrez un terminal dans le projet et exécutez les commandes ci-dessous pour y installer les packages NuGet nécessaires :
dotnet add package Refit
dotnet add package Refit.HttpClientFactory
Ensuite, dans le projet, créez un nouveau dossier appelé « Modèles » et à l’intérieur, créez la classe ci-dessous :
namespace CustomerApi.Models;
public class Customer
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
L’étape suivante consiste à créer un objet de transfert de données (DTO) pour renvoyer les données de la demande API d’informations supplémentaires. Créez un nouveau dossier appelé « Dtos » et ajoutez-y la classe ci-dessous :
- ClientInformations supplémentairesDto
namespace CustomerApi.Dtos;
public class CustomerAdditionalInfoDto
{
public string Id { get; set; }
public string CustomerId { get; set; }
public string Address { get; set; }
public string PhoneNumber { get; set; }
}
Créons maintenant l’interface qui sera utilisée par Refit pour implémenter le point de terminaison de l’API externe. Ainsi, dans le projet CustomerAPI, créez un nouveau dossier appelé « Référentiels ». Dans celui-ci, créez un autre dossier appelé « Interfaces » et ajoutez-y l’interface ci-dessous :
using CustomerApi.Dtos;
using Refit;
namespace CustomerApi.Repositories.Interfaces;
public interface ICustomerAdditionalInfoApi
{
[Get("/customerAdditionalInfos/{customerId}")]
Task<CustomerAdditionalInfoDto> GetCustomerAdditionalInfo(string customerId);
}
Notez que dans cette interface, une méthode est déclarée pour récupérer des données supplémentaires auprès d’un client en utilisant l’identifiant comme paramètre. De plus, le [Get("/customerAdditionalInfos/{customerId}")]
L’attribut de Refit est utilisé, qui déclare que la méthode HTTP est un GET et la route à laquelle accéder est également déclarée : "/customerAdditionalInfos/{customerId}"
.
Configurons maintenant Refit dans la classe Program du projet. Pour cela, ajoutez simplement le code suivant juste en dessous de l’endroit où la variable builder est créée :
builder.Services
.AddRefitClient<ICustomerAdditionalInfoApi>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri("http://localhost:5080"));
Nous informons ici Refit de l’interface qu’il doit utiliser pour créer l’abstraction permettant d’accéder aux API externes. De plus, nous transmettons l’Uniform Resource Identifier (Uri) comme «http://localhost:5080 » qui est l’adresse http et le port qui exécuteront l’API externe.
Pour simplifier les choses, dans cet exemple, nous configurons l’Uri directement dans le ConfigureHttpClient()
méthode, mais dans des scénarios réels, ces informations doivent être stockées dans des emplacements sécurisés tels que des hôtes de stockage cloud protégés par cryptage.
Ajoutons maintenant le point de terminaison qui communiquera avec l’API d’informations supplémentaires :
app.MapGet("/customers/{id}/additionalInfo", async (string id, ICustomerAdditionalInfoApi additionalInfoApi) =>
{
try
{
var info = await additionalInfoApi.GetCustomerAdditionalInfo(id);
return Results.Ok(info);
}
catch (ApiException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
return Results.NotFound($"Additional information not found for the customer id: {id}");
}
});
Dans ce point de terminaison, nous utilisons l’interface qui implémente Refit pour accéder à l’API externe et récupérer des informations supplémentaires auprès du client. Si les données sont trouvées, elles sont renvoyées ; sinon, si le retour est un statut 404 NotFound, une erreur est renvoyée indiquant qu’aucune information supplémentaire n’a été trouvée pour ce client.
Notez à quel point il est simple de demander une API via Refit, vous permettant d’ajouter autant d’API et de points de terminaison que nécessaire. Et il est possible de gérer le retour de l’API via les codes d’état HTTP.
La première API est prête, implémentons maintenant la deuxième API, à laquelle la première accédera via Refit. À l’intérieur du projet CustomerAdditionalInfoApi
créez un nouveau dossier appelé « Modèles » et à l’intérieur, créez la classe ci-dessous :
public string Id { get; set; }
public string CustomerId { get; set; }
public string Address { get; set; }
public string PhoneNumber { get; set; }
Et dans la classe Program, ajoutez le code ci-dessous :
app.MapGet("/customerAdditionalInfos/{customerId}", async (string customerId) =>
{
var customerAdditionalInfo = GetCustomerAdditionalInfos().FirstOrDefault(a => a.CustomerId == customerId);
return customerAdditionalInfo is CustomerAdditionalInfo info ? Results.Ok(info) : Results.NotFound();
});
List<CustomerAdditionalInfo> GetCustomerAdditionalInfos()
{
return new List<CustomerAdditionalInfo>
{
new CustomerAdditionalInfo
{
Id = "6FE892BB",
CustomerId = "35A51B05",
Address = "200 John Wesley Blvd, Bossier City, Louisiana, USA",
PhoneNumber = "555-1234"
},
new CustomerAdditionalInfo
{
Id = "189DF59F",
CustomerId = "4D8AD7B2",
Address = "103100 Overseas Hwy, Key Florida, USA",
PhoneNumber = "555-5678"
},
new CustomerAdditionalInfo
{
Id = "A9374B16",
CustomerId = "23D4FCC2",
Address = "6175 Brandt Pike, Huber Heights, Ohio, USA",
PhoneNumber = "555-8765"
}
};
}
Notez qu’ici, nous n’utilisons pas de base de données : nous créons simplement une API simple pour renvoyer des exemples de données via un point de terminaison.
Une autre configuration nécessaire consiste à définir le port configuré dans l’autre API. Ainsi, dans le dossier Propriétés, dans le launchSettings.json
fichier dans le profiles
le schéma change le applicationUrl
port de clé vers 5080
. Ceci afin que l’application démarre sur ce port, qui a été configuré dans l’API du client.
Lançons maintenant les deux applications et vérifions si Refit fonctionne. Dans Visual Studio, cliquez avec le bouton droit sur la solution et choisissez l’option properties
option. Dans la fenêtre ouverte, sélectionnez Multiple startup projects
et le Start
option pour les deux.
Ensuite, exécutez les applications.
Cet article utilise Progress Telerik Un violoniste partout à demander. Donc, dans Fiddler, exécutez une requête au point final http://localhost:PORT/customers/additionalInfo/4D8AD7B2
. Ici, nous faisons une demande à l’API client en transmettant l’ID client dans l’URL, qui envoie la demande à la deuxième API (CustomerAdditionalInfoAPI) et renvoie les données client.
Maintenant, exécutez à nouveau la requête mais avec un ID inexistant, par exemple : 1A2AD1B2
-et la réponse sera un statut HTTP introuvable :
Notez qu’en utilisant Refit, nous avons pu prédire la réponse à la requête et la traiter si nécessaire. Dans ce cas, lors du retour du statut HTTP 404, une exception a été exécutée et un message d’erreur personnalisé a été renvoyé.
Ajout de l’authentification JWT à Refit
JSON Web Token (JWT) est une norme utilisée pour l’authentification/autorisation dans les API Web qui utilise des jetons signés à l’aide d’un secret privé ou d’une clé publique/privée.
Dans l’exemple précédent, nous avons accédé à l’API externe, mais elle n’avait aucune règle d’authentification/autorisation. Nous vérifierons ensuite comment implémenter cela lors de l’accès à l’API externe à l’aide de Refit.
Tout d’abord, configurons CustomerAPI pour envoyer le jeton à CustomerAdditionalInfoApi. Ainsi, dans le dossier Interfaces ajoutez l’interface suivante :
namespace CustomerApi.Repositories.Interfaces;
public interface IAuthTokenProvider
{
string GetToken();
}
Puis dans le dossier Repositories ajoutez la classe suivante :
using CustomerApi.Repositories.Interfaces;
namespace CustomerApi.Repositories;
public class AuthTokenProvider : IAuthTokenProvider
{
public string GetToken()
{
return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.pg-7kh_cZ0m4yDULVjR7rKPZFh7nBprKGFVYzS7Y7y0";
}
}
Notez que nous définissons ici une interface avec une méthode pour récupérer le jeton. Ensuite, nous créons une classe qui implémente le GetToken()
et renvoie un JWT. Ce token a été généré sur le site JWT et est corrigé dans le code.
N’oubliez pas qu’il ne s’agit que d’un exemple : dans les applications du monde réel, ce jeton doit être obtenu via un point de terminaison sécurisé pour générer le jeton. Pour plus d’informations sur le sujet, vous pouvez consulter cet article qui approfondit l’authentification et l’autorisation avec JWT : Authentification et autorisation avec JWT.
Ensuite, dans la classe Program, ajoutez le code suivant juste en dessous de la variable builder :
builder.Services.AddSingleton<IAuthTokenProvider, AuthTokenProvider>();
Et remplacez le code :
builder.Services
.AddRefitClient<ICustomerAdditionalInfoApi>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri("http://localhost:5080"));
avec ce qui suit :
builder.Services
.AddRefitClient<ICustomerAdditionalInfoApi>()
.ConfigureHttpClient((serviceProvider, c) =>
{
var tokenProvider = serviceProvider.GetRequiredService<IAuthTokenProvider>();
var token = tokenProvider.GetToken();
c.BaseAddress = new Uri("http://localhost:5080");
c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
});
Notez qu’ici nous obtenons le token et le transmettons à Refit via l’en-tête de requête, qui sera de type « Bearer ».
Ensuite, sous l’extrait :
catch (ApiException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized)
{
return Results.Unauthorized();
}
ajoutez ce qui suit :
catch (ApiException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized)
{
return Results.Unauthorized();
}
Il s’agit ici du retour de l’API externe, qui aura désormais la possibilité de renvoyer un statut HTTP non autorisé.
L’implémentation de JWT dans la première API est prête, faisons maintenant la configuration dans l’API CustomerAdditionalInfoApi. Alors, commencez par ouvrir un terminal dans l’API CustomerAdditionalInfoApi et exécutez la commande ci-dessous pour installer la dépendance du package JWT NuGet :
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Ensuite, dans la classe Program, ajoutez le code suivant ci-dessous où la variable « builder » est créée :
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MIICWwIBAAKBgHZO8IQouqjDyY47ZDGdw9j"))
};
});
builder.Services.AddAuthorization();
Ici, nous configurons les exigences JWT. Notez que la plupart des exigences sont marquées comme fausses car, comme indiqué précédemment, il ne s’agit que d’un exemple didactique. Dans les applications du monde réel, il faut faire attention à ces informations. De plus, nous configurons directement la clé secrète (MIICWwIBAAKBgHZO8IQouqjDyY47ZDGdw9j). Cette clé a été utilisée pour créer le jeton JWT configuré dans l’API client.
Toujours dans la classe programme, en dessous du app
variable, ajoutez ce qui suit :
app.UseAuthentication();
app.UseAuthorization();
Ces méthodes sont utilisées pour indiquer au compilateur d’utiliser l’authentification et l’autorisation.
Enfin, pour que le point final prenne en compte les règles d’autorisation JWT, il est nécessaire d’ajouter le RequireAuthorization()
méthode d’extension. Le point final complet ressemblera alors à ceci :
app.MapGet("/customerAdditionalInfos/{customerId}", async (string customerId) =>
{
var customerAdditionalInfo = GetCustomerAdditionalInfos().FirstOrDefault(a => a.CustomerId == customerId);
return customerAdditionalInfo is CustomerAdditionalInfo info ? Results.Ok(info) : Results.NotFound();
});
}).RequireAuthorization();
Test de l’accès au point de terminaison authentifié via Refit
Maintenant que toutes les configurations d’authentification et d’autorisation sont prêtes, nous pouvons exécuter l’application et vérifier si le point de terminaison continue de fonctionner. Démarrez ensuite les deux API et exécutez à nouveau la requête via Fiddler.
Notez que là encore, les données ont été renvoyées avec succès, car l’API a été authentifiée. Pour tester l’erreur d’autorisation, modifiez la clé secrète (MIICWwIBAAKBgHZO8IQouqjDyY47ZDGdw9j) dans la classe Program de l’API CustomerAdditionalInfoApi et refaites la requête.
Cette fois, l’API d’informations supplémentaires n’a pas reconnu la clé secrète envoyée dans la requête et a renvoyé le code d’état HTTP 401 (Non autorisé).
Conclusion
Dans cet article, nous avons examiné certains des inconvénients de la classe native HttpClient d’ASP.NET Core, qui, bien qu’elle réponde aux principaux besoins de communication entre les API, peut devenir un problème lors de la gestion de nombreuses requêtes vers des API externes.
En revanche, nous avons exploré la fonctionnalité de Refit, qui constitue une bonne alternative à HttpClient, permettant au développeur de créer moins de code passe-partout et de simplifier le processus de requête entre les API. De plus, nous avons vérifié comment mettre en œuvre un système d’authentification simple et envoyer le jeton à l’API externe via Refit.
Refit est un excellent outil pour travailler avec des API Web. Ainsi, chaque fois que vous en ressentez le besoin, envisagez d’utiliser Refit pour gérer les appels externes et assurer le succès de votre application.
Source link