Bonnes pratiques
Recommandations pour une intégration optimale avec MCM.ApiProxy.
Architecture
Créer une couche de service
Ne pas injecter les clients MCM directement dans les contrôleurs. Créez une couche de service :
// BON - Couche de service
public class EmployeService
{
private readonly IEmployesClient _employesClient;
public EmployeService(IEmployesClient employesClient)
{
_employesClient = employesClient;
}
public async Task<EmployeDto?> GetEmployeAsync(string id)
{
var result = await _employesClient.GetEmployeById(id);
return result.IsError ? null : MapToDto(result.Value);
}
}
// Contrôleur utilise le service
public class EmployesController : ControllerBase
{
private readonly EmployeService _employeService;
// ...
}
Utiliser l'injection de dépendances
Toujours injecter les clients via le constructeur :
// BON
public class MonService
{
private readonly IEmployesClient _employesClient;
public MonService(IEmployesClient employesClient)
{
_employesClient = employesClient;
}
}
// MAUVAIS - Service locator
public class MonService
{
public void DoSomething(IServiceProvider services)
{
var client = services.GetService<IEmployesClient>();
}
}
Performance
Éviter les appels en boucle
// MAUVAIS - N appels API
foreach (var id in employeIds)
{
var result = await _employesClient.GetEmployeById(id);
// ...
}
// BON - Un seul appel
var allEmployes = await _employesClient.GetAllEmployes();
var filtered = allEmployes.Value.Where(e => employeIds.Contains(e.IdExterne));
Utiliser la synchronisation pour les lots
// BON - Un seul appel pour plusieurs opérations
await _syncClient.Sync(
employes,
employeurs,
objetsConsentement);
Mettre en cache quand approprié
public class CachedFormulaireService
{
private readonly IFormulaireClient _formulaireClient;
private readonly IMemoryCache _cache;
public async Task<List<B2BFormulaireItem>> GetFormulairesAsync()
{
return await _cache.GetOrCreateAsync("formulaires", async entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
var result = await _formulaireClient.GetAllFormulaires();
return result.IsError ? new List<B2BFormulaireItem>() : result.Value.ToList();
});
}
}
Gestion des erreurs
Logger systématiquement
public async Task<bool> CreateEmployeAsync(B2BUpdateEmployeDto employe)
{
using var _ = _logger.BeginScope(new { EmployeId = employe.IdExterne });
var result = await _employesClient.AddEmploye(employe);
if (result.IsError)
{
_logger.LogError(
"Échec création employé - Code: {ErrorCode}, Description: {ErrorDescription}",
result.FirstError.Code,
result.FirstError.Description);
return false;
}
_logger.LogInformation("Employé créé avec succès");
return true;
}
Ne pas ignorer les erreurs
// MAUVAIS - Erreur silencieuse
var result = await _employesClient.GetEmployeById(id);
return result.Value; // Exception si erreur!
// BON - Gestion explicite
var result = await _employesClient.GetEmployeById(id);
if (result.IsError)
{
throw new EmployeNotFoundException(id);
}
return result.Value;
Données
Valider avant d'envoyer
public async Task<ErrorOr<Success>> CreateEmployeAsync(CreateEmployeRequest request)
{
// Validation locale d'abord
if (string.IsNullOrWhiteSpace(request.IdExterne))
{
return Error.Validation("IdExterne.Required", "IdExterne est obligatoire");
}
if (!IsValidEmail(request.Courriel))
{
return Error.Validation("Courriel.Invalid", "Format de courriel invalide");
}
// Puis appel API
var dto = MapToDto(request);
return await _employesClient.AddEmploye(dto);
}
Utiliser des identifiants stables
// BON - Identifiant stable basé sur votre système
var employe = new B2BUpdateEmployeDto
{
IdExterne = $"HRIS-{employee.HrisId}", // Basé sur votre système RH
// ...
};
// MAUVAIS - Identifiant qui peut changer
var employe = new B2BUpdateEmployeDto
{
IdExterne = employee.Email, // L'email peut changer!
// ...
};
Tests
Mocker les clients dans les tests
public class EmployeServiceTests
{
[Fact]
public async Task GetEmploye_ReturnsEmploye_WhenFound()
{
// Arrange
var mockClient = new Mock<IEmployesClient>();
mockClient
.Setup(c => c.GetEmployeById("EMP-123"))
.ReturnsAsync(new B2BEmployeItem { IdExterne = "EMP-123", Nom = "Test" });
var service = new EmployeService(mockClient.Object);
// Act
var result = await service.GetEmployeAsync("EMP-123");
// Assert
Assert.NotNull(result);
Assert.Equal("Test", result.Nom);
}
}
Sécurité
Protéger la clé API
- Utilisez les secrets utilisateur en développement
- Utilisez Azure Key Vault ou équivalent en production
- Ne loggez jamais la clé API
- Faites la rotation régulièrement
Valider les entrées utilisateur
// Avant d'utiliser un ID fourni par l'utilisateur
public async Task<IActionResult> GetEmploye(string id)
{
if (string.IsNullOrWhiteSpace(id) || id.Length > 100)
{
return BadRequest("ID invalide");
}
// Seulement après validation
var result = await _employeService.GetEmployeAsync(id);
// ...
}