Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exchange Rate Provider - Backend Task - Fernando Álvarez Naval #676

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions jobs/Backend/Task/Currency.cs

This file was deleted.

23 changes: 0 additions & 23 deletions jobs/Backend/Task/ExchangeRate.cs

This file was deleted.

19 changes: 0 additions & 19 deletions jobs/Backend/Task/ExchangeRateProvider.cs

This file was deleted.

8 changes: 0 additions & 8 deletions jobs/Backend/Task/ExchangeRateUpdater.csproj

This file was deleted.

22 changes: 0 additions & 22 deletions jobs/Backend/Task/ExchangeRateUpdater.sln

This file was deleted.

49 changes: 49 additions & 0 deletions jobs/Backend/Task/ExchangeRateUpdater/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Archivos de sistema operativo
.DS_Store
Thumbs.db

# Configuración de Visual Studio
.vs/
*.vcxproj.user
*.suo
*.user
*.sln.docstates

# Carpetas de compilación y temporales
[Bb]in/
[Oo]bj/
[Ll]og/
[Dd]ebug*/
[Rr]elease*/
x64/
x86/
[Aa]rm/
[Aa]rm64/
*.log
*.tmp

# Archivos de paquetes y dependencias
packages/
*.nupkg
project.lock.json
project.fragment.lock.json

# Archivos de publicación
*.publishsettings
*.azurePubxml
*.azurePubxml.user

# Configuración de IDEs
.idea/
.vscode/

# Archivos de pruebas
TestResults/
*.trx
*.coverage

# Archivos sensibles
*.config
*.env
*.key
*.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ExchangeRateUpdater.Data\ExchangeRateUpdater.Data.csproj" />
<ProjectReference Include="..\ExchangeRateUpdater.Models\ExchangeRateUpdater.Models.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using ExchangeRateUpdater.Data.Responses;
using ExchangeRateUpdater.Models.Requests;

namespace ExchangeRateUpdater.Business.Interfaces;
public interface IExchangeRateService
{
Task<List<ExchangeRateResultDto>> GetExchangeRates(IEnumerable<ExchangeRateRequest> currencies, DateTime date, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using ExchangeRateUpdater.Models.Requests;
using ExchangeRateUpdater.Data.Interfaces;
using ExchangeRateUpdater.Data.Responses;
using ExchangeRateUpdater.Business.Interfaces;
using ExchangeRateUpdater.Models.Models;
using Microsoft.Extensions.Logging;

namespace ExchangeRateUpdater.Business.Services;
public class ExchangeRateService : IExchangeRateService
{
private readonly IExchangeRateRepository _exchangeRatesRepository;
private readonly ILogger<ExchangeRateService> _logger;
public ExchangeRateService(IExchangeRateRepository exchangeRatesRepository, ILogger<ExchangeRateService> logger)
{
_exchangeRatesRepository = exchangeRatesRepository;
_logger = logger;
}
public async Task<List<ExchangeRateResultDto>> GetExchangeRates(IEnumerable<ExchangeRateRequest> currencies, DateTime date, CancellationToken cancellationToken)
{
var exchangeRatesByCurrency = new List<ExchangeRate>();

//Get all the rates for a specified date
var exchangeRates = await _exchangeRatesRepository.GetExchangeRatesByDateAsync(date, cancellationToken);

//Get only the requested ones
var requestedExchangeRates = exchangeRates.Where(p => currencies
.Any(e => e.ToString() == p.ToString()))
.ToList();

_logger.LogInformation($"{requestedExchangeRates.Count}/{currencies.ToList().Count} exchange rate(s) have been obtained.");
//Map to a new object that simplifies reading the response
return requestedExchangeRates.Select(rate => MapToResult(rate)).ToList();
}

private ExchangeRateResultDto MapToResult(ExchangeRate rate)
{
return new ExchangeRateResultDto(
new Currency(rate.SourceCurrency.Code),
new Currency(rate.TargetCurrency.Code),
rate.Value,
rate.Date);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Flurl" Version="4.0.0" />
<PackageReference Include="Flurl.Http" Version="4.0.2" />
<PackageReference Include="Flurl.Http.Newtonsoft" Version="0.9.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ExchangeRateUpdater.Models\ExchangeRateUpdater.Models.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

using ExchangeRateUpdater.Data.Responses;

namespace ExchangeRateUpdater.Data.Interfaces;
public interface IExchangeRateCacheRepository
{
ExchangeRatesResponseDto GetExchangeRates(DateTime date);
void SetExchangeRates(ExchangeRatesResponseDto rates);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

using ExchangeRateUpdater.Data.Responses;

namespace ExchangeRateUpdater.Data.Interfaces;
public interface IExchangeRateRepository
{
Task<List<ExchangeRate>> GetExchangeRatesByDateAsync(DateTime date, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using ExchangeRateUpdater.Data.Interfaces;
using ExchangeRateUpdater.Data.Responses;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;


namespace ExchangeRateUpdater.Data.Repositories;
public class ExchangeRateCacheRepository : IExchangeRateCacheRepository
{
private readonly IMemoryCache _cache;
private readonly ILogger<ExchangeRateCacheRepository> _logger;

public ExchangeRateCacheRepository(IMemoryCache cache, ILogger<ExchangeRateCacheRepository> logger)
{
_cache = cache;
_logger = logger;
}

public ExchangeRatesResponseDto GetExchangeRates(DateTime date)
{
var result = new ExchangeRatesResponseDto() { Rates = new List<ExchangeRateDto>()};
var key = date.ToString("yyyy-MM-dd");

if (_cache.TryGetValue(key, out ExchangeRatesResponseDto ratesCached))
{
_logger.LogInformation($"{ratesCached.Rates.Count} retrieved from cache");
result.Rates = ratesCached.Rates.Where(t => t.ValidFor == date).ToList();
}

return result;
}

public void SetExchangeRates(ExchangeRatesResponseDto rates)
{
try
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromDays(1)); //Keep cache for 1 day max

//Since weekends there's no rates and the api always returns the las data avaiable,
//the rates in cache have the actual date and not the requested
var key = rates.Rates[0].ValidFor.ToString("yyyy-MM-dd");

if (!_cache.TryGetValue(key, out _))
{
_logger.LogInformation($"{rates.Rates.Count} have been saved on cache");
_cache.Set(key, rates, cacheEntryOptions);
}


}
catch (Exception ex)
{
_logger.LogError(ex.Message);
throw new Exception($"There was an error while saving in cache. Error: {ex.Message}");
}
}
}

Loading