---
sidebar_position: 3
title: Effectuer des requêtes HTTP
---

## Format des données

Deux fonctionnement existent afin de récupérer des données d'une API, la première et de récupérer les données brut au format JSON, la deuxième est d'utiliser la sérialisation / désérialisation.

Dans notre cas, la librairie utilisée implémente par défaut la sérialisation / désérialisation.

Afin de pouvoir manipuler nos données nous allons utiliser notre classe de composant `Item` en local, les données reçues elles proviennent de la sérialisation de la classe `Item` du serveur.

```csharp title="Models/Item.cs"
public class Item
{
    public int Id { get; set; }
    public string DisplayName { get; set; }
    public string Name { get; set; }
    public int StackSize { get; set; }
    public int MaxDurability { get; set; }
    public List<string> EnchantCategories { get; set; }
    public List<string> RepairWith { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime? UpdatedDate { get; set; }
	public string ImageBase64 { get; set; }
}
```

:::info
Ajouter ou supprimer des champs dans notre modèle ne génére pas d'erreur lors de la récupération des données.
:::

## Utilisation de l'IOC

Grâçe à notre IOC nous allons donc appeler notre API dans un service spécifique implémentant l'interface `IDataService`.

Créer la classe `DataApiService`:

```csharp title="Services/DataApiService.cs"
public class DataApiService : IDataService
{
    private readonly HttpClient _http;

    public DataApiService(
        HttpClient http)
    {
        _http = http;
    }

    public async Task Add(ItemModel model)
    {
        // Get the item
		var item = ItemFactory.Create(model);
		
        // Save the data
		await _http.PostAsJsonAsync("https://localhost:7234/api/Crafting/", item);
    }

    public async Task<int> Count()
    {
		return await _http.GetFromJsonAsync<int>("https://localhost:7234/api/Crafting/count");
    }

    public async Task<List<Item>> List(int currentPage, int pageSize)
    {
		return await _http.GetFromJsonAsync<List<Item>>($"https://localhost:7234/api/Crafting/?currentPage={currentPage}&pageSize={pageSize}");
    }
	
	public async Task<Item> GetById(int id)
	{
		return await _http.GetFromJsonAsync<Item>($"https://localhost:7234/api/Crafting/{id}");
	}

	public async Task Update(int id, ItemModel model)
	{
        // Get the item
		var item = ItemFactory.Create(model);
		
		await _http.PutAsJsonAsync($"https://localhost:7234/api/Crafting/{id}", item);
	}

	public async Task Delete(int id)
	{
		await _http.DeleteAsync($"https://localhost:7234/api/Crafting/{id}");
	}

	public async Task<List<CraftingRecipe>> GetRecipes()
	{
		return await _http.GetFromJsonAsync<List<CraftingRecipe>>("https://localhost:7234/api/Crafting/recipe");
	}
}
```

Nous avons désormais une classe permettant de passer l'ensemble de nos appels par une API.

## Enregistrez le service de données

Ouvrez le fichier "Program.cs" et modifiez la ligne suivante :

```csharp title="Program.cs"
...

builder.Services.AddScoped<IDataService, DataApiService>();

...
```

## Ajouter l'exemple d'API à votre projet

Téléchargez ce [projet](/Minecraft.Crafting.Api.zip).

:::caution
Si vous avez une erreur 404 avec le téléchargement, supprimez le dernier `/` à la fin de l'url. Exemple : `.zip/` => `.zip`
:::

Décompressez le fichier dans le répertoire de votre projet, au même endroit que le répertoire du projet Blazor.

Exemple:

![Sample Api Location](/img/api/sample-api-location.png)

Sur Visual Studio, cliquez droit sur la solution et choisissez `Add => Existing Project...`

![Add Existing Project](/img/api/add-existing-project.png)

Sélectionnez le fichier `Minecraft.Crafting.Api.csproj` dans le répertoire `Minecraft.Crafting.Api`.

Votre solution contient maintenant deux projets, votre client et l'exemple d'API.

## Comment démarrer deux projets en même temps dans Visual Studio

Pour tester votre client avec l'API, vous devez démarrer les deux projets en même temps.

Pour cela, sur Visual Studio, cliquez droit sur la solution et choisissez `Properties`

![Solution Properties](/img/api/solution-properties.png)

Sur le nouvel écran, sélectionnez "Multiple startup projects" et sélectionnez "Start" pour les deux projets.

![Multiple startup projects](/img/api/multiple-startup-projects.png)

Lorsque vous démarrez le mode débogage, les deux projets sont démarrés.

## Notion : IHttpClientFactory 

Une `IHttpClientFactory` peut être inscrite et utilisée pour configurer et créer des instances de HttpClient dans une application. 
`IHttpClientFactory` offre les avantages suivants :

* Fournit un emplacement central pour le nommage et la configuration d’instance de `HttpClient` logiques. Par exemple, un client nommé github peut être inscrit et configuré pour accéder à GitHub. Un client par défaut peut être inscrit pour un accès général.
* Codifie le concept de middleware sortant par le biais de la délégation de gestionnaires dans `HttpClient`. Fournit des extensions pour le middleware basé sur Polly pour tirer parti de la délégation de gestionnaires dans `HttpClient`.
* Gère le regroupement et la durée de vie des instances sous-jacentes `HttpClientMessageHandler`. La gestion automatique évite les problèmes DNS courants (Domain Name System) qui se produisent lors de la gestion `HttpClient` manuelle des durées de vie.
* Ajoute une expérience de journalisation configurable (via `ILogger`) pour toutes les requêtes envoyées via des clients créés par la fabrique.

### Modèles de consommation

Vous pouvez utiliser IHttpClientFactory dans une application de plusieurs façons :
* Utilisation de base
* Clients nommés
* Clients typés
* Clients générés

La meilleure approche dépend des exigences de l’application.


#### Utilisation de base

Inscrivez `IHttpClientFactory` dans `Program.cs` en appelant `AddHttpClient` :

```csharp
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// highlight-next-line
builder.Services.AddHttpClient();
```

Une `IHttpClientFactory` demande peut être demandée à l’aide de l’injection de dépendances (DI). Le code suivant utilise `IHttpClientFactory` pour créer une instance `HttpClient` :

```csharp
public class BasicModel : PageModel
{
    private readonly IHttpClientFactory _httpClientFactory;

// highlight-next-line
    public BasicModel(IHttpClientFactory httpClientFactory) => _httpClientFactory = httpClientFactory;

    public IEnumerable<GitHubBranch>? GitHubBranches { get; set; }

    public async Task OnGet()
    {
        var httpRequestMessage = new HttpRequestMessage(
            HttpMethod.Get,
            "https://api.github.com/repos/dotnet/AspNetCore.Docs/branches")
        {
            Headers =
            {
                { HeaderNames.Accept, "application/vnd.github.v3+json" },
                { HeaderNames.UserAgent, "HttpRequestsSample" }
            }
        };

// highlight-next-line
        var httpClient = _httpClientFactory.CreateClient();
        var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);

        if (httpResponseMessage.IsSuccessStatusCode)
        {
            using var contentStream =
                await httpResponseMessage.Content.ReadAsStreamAsync();
            
            GitHubBranches = await JsonSerializer.DeserializeAsync
                <IEnumerable<GitHubBranch>>(contentStream);
        }
    }
}
```

L’utilisation de `IHttpClientFactory` comme dans l’exemple précédent est un bon moyen de refactoriser une application existante. Il n’a aucun impact sur l’utilisation `HttpClient`. 
Dans les endroits où des instances `HttpClient` sont créées dans une application existante, remplacez ces occurrences par des appels à `CreateClient`.

#### Clients nommés

Les clients nommés sont un bon choix quand :
* L’application nécessite de nombreuses utilisations distinctes de `HttpClient`.
* Beaucoup de `HttpClient` entre eux ont une configuration différente.

Spécifiez la configuration d’un nom `HttpClient` lors de son inscription dans `Program.cs`:

```csharp
builder.Services.AddHttpClient("GitHub", httpClient =>
{
    httpClient.BaseAddress = new Uri("https://api.github.com/");

    // using Microsoft.Net.Http.Headers;
    // The GitHub API requires two headers.
    httpClient.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/vnd.github.v3+json");
    httpClient.DefaultRequestHeaders.Add(HeaderNames.UserAgent, "HttpRequestsSample");
});
```

Dans le code précédent, le client est configuré avec :
* Adresse de base `https://api.github.com/de`.
* Deux en-têtes requis pour travailler avec l’API GitHub.

##### CreateClient

Chaque fois que `CreateClient` est appelée :
* Une nouvelle instance est `HttpClient` créée.
* L’action de configuration est appelée.

Pour créer un client nommé, passez son nom à `CreateClient` :

```csharp
public class NamedClientModel : PageModel
{
    private readonly IHttpClientFactory _httpClientFactory;

    public NamedClientModel(IHttpClientFactory httpClientFactory) =>
        _httpClientFactory = httpClientFactory;

    public IEnumerable<GitHubBranch>? GitHubBranches { get; set; }

    public async Task OnGet()
    {
// highlight-next-line
        var httpClient = _httpClientFactory.CreateClient("GitHub");
        var httpResponseMessage = await httpClient.GetAsync(
            "repos/dotnet/AspNetCore.Docs/branches");

        if (httpResponseMessage.IsSuccessStatusCode)
        {
            using var contentStream =
                await httpResponseMessage.Content.ReadAsStreamAsync();
            
            GitHubBranches = await JsonSerializer.DeserializeAsync
                <IEnumerable<GitHubBranch>>(contentStream);
        }
    }
}
```

Dans le code précédent, la requête n’a pas besoin de spécifier un nom d’hôte. Le code peut passer uniquement le chemin d’accès, car l’adresse de base configurée pour le client est utilisée.

#### Clients typés

Clients typés :
* Fournissent les mêmes fonctionnalités que les clients nommés, sans qu’il soit nécessaire d’utiliser des chaînes comme clés.
* Bénéficie de l’aide d’IntelliSense et du compilateur lors de l’utilisation des clients.
* Fournissent un emplacement unique pour configurer et interagir avec un `HttpClient` particulier. Par exemple, un client typé unique peut être utilisé :
	* Pour un point de terminaison principal unique.
	* Pour encapsuler toute logique traitant du point de terminaison.
* Collaborez avec la di et pouvez être injecté si nécessaire dans l’application.

Un client typé accepte un `HttpClient` paramètre dans son constructeur :

```csharp
public class GitHubService
{
    private readonly HttpClient _httpClient;

// highlight-next-line
    public GitHubService(HttpClient httpClient)
    {
        _httpClient = httpClient;

        _httpClient.BaseAddress = new Uri("https://api.github.com/");

        // using Microsoft.Net.Http.Headers;
        // The GitHub API requires two headers.
        _httpClient.DefaultRequestHeaders.Add(
            HeaderNames.Accept, "application/vnd.github.v3+json");
        _httpClient.DefaultRequestHeaders.Add(
            HeaderNames.UserAgent, "HttpRequestsSample");
    }

    public async Task<IEnumerable<GitHubBranch>?> GetAspNetCoreDocsBranchesAsync() =>
        await _httpClient.GetFromJsonAsync<IEnumerable<GitHubBranch>>(
            "repos/dotnet/AspNetCore.Docs/branches");
}
```

Dans le code précédent :
* La configuration est déplacée dans le client typé.
* L’instance fournie `HttpClient` est stockée en tant que champ privé.

Les méthodes spécifiques à l’API peuvent être créées qui exposent `HttpClient` des fonctionnalités. 
Par exemple, la méthode encapsule du `GetAspNetCoreDocsBranches` code pour récupérer les branches GitHub de docs.

Le code suivant appelle `AddHttpClient` dans `Program.cs` pour inscrire la `GitHubService` classe cliente typée :

```csharp
builder.Services.AddHttpClient<GitHubService>();
```

Le client typé est inscrit comme étant transitoire avec injection de dépendances. Dans le code précédent, `AddHttpClient` s’inscrit `GitHubService` en tant que service temporaire. Cette inscription utilise une méthode de fabrique pour :
* Créez une instance de `HttpClient`.
* Créez une instance de `GitHubService`, en passant l’instance de `HttpClient` son constructeur.

Le client typé peut être injecté et utilisé directement :

```csharp
public class TypedClientModel : PageModel
{
    private readonly GitHubService _gitHubService;

// highlight-next-line
    public TypedClientModel(GitHubService gitHubService) => _gitHubService = gitHubService;

    public IEnumerable<GitHubBranch>? GitHubBranches { get; set; }

    public async Task OnGet()
    {
        try
        {
// highlight-next-line
            GitHubBranches = await _gitHubService.GetAspNetCoreDocsBranchesAsync();
        }
        catch (HttpRequestException)
        {
            // ...
        }
    }
}
```

La configuration d’un client typé peut également être spécifiée lors de son inscription `Program.cs`, plutôt que dans le constructeur du client typé :

```csharp
builder.Services.AddHttpClient<GitHubService>(httpClient =>
{
    httpClient.BaseAddress = new Uri("https://api.github.com/");

    // ...
});
```

#### Clients générés

`IHttpClientFactory` peut être utilisé en combinaison avec des bibliothèques tierces telles que Refit. 
Refit est une REST bibliothèque pour .NET. 
Il convertit les REST API en interfaces actives. Appel `AddRefitClient` pour générer une implémentation dynamique d’une interface, qui utilise `HttpClient` pour effectuer les appels HTTP externes.

Une interface personnalisée représente l’API externe :

```csharp
public interface IGitHubClient
{
    [Get("/repos/dotnet/AspNetCore.Docs/branches")]
    Task<IEnumerable<GitHubBranch>> GetAspNetCoreDocsBranchesAsync();
}
```

Appel `AddRefitClient` pour générer l’implémentation dynamique, puis appeler `ConfigureHttpClient` pour configurer le sous-jacent `HttpClient` :

```csharp
// highlight-next-line
builder.Services.AddRefitClient<IGitHubClient>()
// highlight-next-line
    .ConfigureHttpClient(httpClient =>
    {
        httpClient.BaseAddress = new Uri("https://api.github.com/");

        // using Microsoft.Net.Http.Headers;
        // The GitHub API requires two headers.
        httpClient.DefaultRequestHeaders.Add(
            HeaderNames.Accept, "application/vnd.github.v3+json");
        httpClient.DefaultRequestHeaders.Add(
            HeaderNames.UserAgent, "HttpRequestsSample");
    });
```

Utilisez DI pour accéder à l’implémentation dynamique de `IGitHubClient`:

```csharp
public class RefitModel : PageModel
{
    private readonly IGitHubClient _gitHubClient;

// highlight-next-line
    public RefitModel(IGitHubClient gitHubClient) => _gitHubClient = gitHubClient;

    public IEnumerable<GitHubBranch>? GitHubBranches { get; set; }

    public async Task OnGet()
    {
        try
        {
// highlight-next-line
            GitHubBranches = await _gitHubClient.GetAspNetCoreDocsBranchesAsync();
        }
        catch (ApiException)
        {
            // ...
        }
    }
}
```

### Type de requête d'HttpClient

HttpClient prend en charge d’autres verbes HTTP :

| Propriétés | Verbe |
| ---- | ---- |
| Delete | Représente une méthode de protocole HTTP DELETE. |
| Get | Représente une méthode de protocole HTTP GET. |
| Head | Représente une méthode de protocole HTTP HEAD. La méthode HEAD est identique à GET, mais le serveur retourne uniquement des en-têtes de message dans la réponse, sans corps du message. |
| Method | Méthode &HTTP. |
| Options | Représente une méthode de protocole HTTP OPTIONS. |
| Patch | Obtient la méthode de protocole HTTP PATCH. |
| Post | Représente une méthode de protocole HTTP POST utilisée pour publier une nouvelle entité en plus d'un URI. |
| Put | Représente une méthode de protocole HTTP PUT utilisée pour remplacer une entité identifiée par un URI. |
| Trace | Représente une méthode de protocole HTTP TRACE. |
