aboutsummaryrefslogtreecommitdiff
path: root/src/Costasdev.Busurbano.Backend/GetStopEstimates.cs
diff options
context:
space:
mode:
authorAriel Costas Guerrero <ariel@costas.dev>2025-08-05 23:36:20 +0200
committerAriel Costas Guerrero <ariel@costas.dev>2025-08-05 23:36:20 +0200
commitb04fd7d33d07f9eddea2eb53e1389d5ca5453413 (patch)
treefec6f44639514ee4af70031f09a39fb1c808623f /src/Costasdev.Busurbano.Backend/GetStopEstimates.cs
parentc18063cc107c3126a9b62caa857e37062ab86c9c (diff)
Add timetable feature with caching and localization support
Diffstat (limited to 'src/Costasdev.Busurbano.Backend/GetStopEstimates.cs')
-rw-r--r--src/Costasdev.Busurbano.Backend/GetStopEstimates.cs86
1 files changed, 85 insertions, 1 deletions
diff --git a/src/Costasdev.Busurbano.Backend/GetStopEstimates.cs b/src/Costasdev.Busurbano.Backend/GetStopEstimates.cs
index 7d4a5e8..50d8c98 100644
--- a/src/Costasdev.Busurbano.Backend/GetStopEstimates.cs
+++ b/src/Costasdev.Busurbano.Backend/GetStopEstimates.cs
@@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Caching.Memory;
using Costasdev.VigoTransitApi;
+using System.Text.Json;
namespace Costasdev.Busurbano.Backend;
@@ -8,10 +10,14 @@ namespace Costasdev.Busurbano.Backend;
public class ApiController : ControllerBase
{
private readonly VigoTransitApiClient _api;
+ private readonly IMemoryCache _cache;
+ private readonly HttpClient _httpClient;
- public ApiController(HttpClient http)
+ public ApiController(HttpClient http, IMemoryCache cache)
{
_api = new VigoTransitApiClient(http);
+ _cache = cache;
+ _httpClient = http;
}
[HttpGet("GetStopEstimates")]
@@ -39,5 +45,83 @@ public class ApiController : ControllerBase
return new BadRequestObjectResult("Stop not found");
}
}
+
+ [HttpGet("GetStopTimetable")]
+ public async Task<IActionResult> GetStopTimetable()
+ {
+ // Get date parameter (default to today if not provided)
+ var dateString = Request.Query.TryGetValue("date", out var requestedDate)
+ ? requestedDate.ToString()
+ : DateTime.Today.ToString("yyyy-MM-dd");
+
+ // Validate date format
+ if (!DateTime.TryParseExact(dateString, "yyyy-MM-dd", null, System.Globalization.DateTimeStyles.None, out var parsedDate))
+ {
+ return BadRequest("Invalid date format. Please use yyyy-MM-dd format.");
+ }
+
+ // Get stopId parameter
+ if (!Request.Query.TryGetValue("stopId", out var requestedStopIdString))
+ {
+ return BadRequest("Please provide a stop id as a query parameter with the name 'stopId'.");
+ }
+
+ if (!int.TryParse(requestedStopIdString, out var requestedStopId))
+ {
+ return BadRequest("The provided stop id is not a valid number.");
+ }
+
+ // Create cache key
+ var cacheKey = $"timetable_{dateString}_{requestedStopId}";
+
+ // Try to get from cache first
+ if (_cache.TryGetValue(cacheKey, out var cachedData))
+ {
+ return new OkObjectResult(cachedData);
+ }
+
+ try
+ {
+ // Fetch data from external API
+ var url = $"https://costas.dev/static-storage/vitrasa_svc/stops/{dateString}/{requestedStopId}.json";
+ var response = await _httpClient.GetAsync(url);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
+ {
+ return NotFound($"Timetable data not found for stop {requestedStopId} on {dateString}");
+ }
+ return StatusCode((int)response.StatusCode, "Error fetching timetable data");
+ }
+
+ var jsonContent = await response.Content.ReadAsStringAsync();
+ var timetableData = JsonSerializer.Deserialize<JsonElement>(jsonContent);
+
+ // Cache the data for 12 hours
+ var cacheOptions = new MemoryCacheEntryOptions
+ {
+ AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12),
+ SlidingExpiration = TimeSpan.FromHours(6), // Refresh cache if accessed within 6 hours of expiry
+ Priority = CacheItemPriority.Normal
+ };
+
+ _cache.Set(cacheKey, timetableData, cacheOptions);
+
+ return new OkObjectResult(timetableData);
+ }
+ catch (HttpRequestException ex)
+ {
+ return StatusCode(500, $"Error fetching timetable data: {ex.Message}");
+ }
+ catch (JsonException ex)
+ {
+ return StatusCode(500, $"Error parsing timetable data: {ex.Message}");
+ }
+ catch (Exception ex)
+ {
+ return StatusCode(500, $"Unexpected error: {ex.Message}");
+ }
+ }
}