From b04fd7d33d07f9eddea2eb53e1389d5ca5453413 Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Tue, 5 Aug 2025 23:36:20 +0200 Subject: Add timetable feature with caching and localization support --- .../GetStopEstimates.cs | 86 +++++++++++++++++++++- src/Costasdev.Busurbano.Backend/Program.cs | 1 + 2 files changed, 86 insertions(+), 1 deletion(-) (limited to 'src/Costasdev.Busurbano.Backend') 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 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(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}"); + } + } } diff --git a/src/Costasdev.Busurbano.Backend/Program.cs b/src/Costasdev.Busurbano.Backend/Program.cs index a394282..68f84fb 100644 --- a/src/Costasdev.Busurbano.Backend/Program.cs +++ b/src/Costasdev.Busurbano.Backend/Program.cs @@ -2,6 +2,7 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddHttpClient(); +builder.Services.AddMemoryCache(); var app = builder.Build(); -- cgit v1.3