Merge pull request #14 from JoshHeaps/feature/blog

add cache invalidation
This commit is contained in:
Josh Heaps
2026-03-06 17:06:51 -07:00
committed by GitHub
3 changed files with 29 additions and 1 deletions
+24 -1
View File
@@ -6,7 +6,7 @@ namespace Media.JoshHeaps.Net.Api;
[ApiController] [ApiController]
[Route("api/blog")] [Route("api/blog")]
public class BlogApi(BlogService blogService, DbExecutor dbExecutor) : ControllerBase public class BlogApi(BlogService blogService, DbExecutor dbExecutor, IHttpClientFactory httpClientFactory, IConfiguration configuration, ILogger<BlogApi> logger) : ControllerBase
{ {
[HttpGet("posts")] [HttpGet("posts")]
public async Task<IActionResult> GetPosts() public async Task<IActionResult> GetPosts()
@@ -65,6 +65,7 @@ public class BlogApi(BlogService blogService, DbExecutor dbExecutor) : Controlle
if (post is null) if (post is null)
return StatusCode(500, new { error = "Failed to create post" }); return StatusCode(500, new { error = "Failed to create post" });
_ = InvalidateFrontendCacheAsync();
return Ok(MapToAdminDto(post)); return Ok(MapToAdminDto(post));
} }
@@ -91,6 +92,7 @@ public class BlogApi(BlogService blogService, DbExecutor dbExecutor) : Controlle
if (post is null) if (post is null)
return NotFound(new { error = "Post not found" }); return NotFound(new { error = "Post not found" });
_ = InvalidateFrontendCacheAsync();
return Ok(MapToAdminDto(post)); return Ok(MapToAdminDto(post));
} }
@@ -104,6 +106,7 @@ public class BlogApi(BlogService blogService, DbExecutor dbExecutor) : Controlle
var deleted = await blogService.DeletePostAsync(id); var deleted = await blogService.DeletePostAsync(id);
if (!deleted) return NotFound(new { error = "Post not found" }); if (!deleted) return NotFound(new { error = "Post not found" });
_ = InvalidateFrontendCacheAsync();
return Ok(new { success = true }); return Ok(new { success = true });
} }
@@ -158,6 +161,26 @@ public class BlogApi(BlogService blogService, DbExecutor dbExecutor) : Controlle
post.UpdatedAt post.UpdatedAt
}; };
private async Task InvalidateFrontendCacheAsync()
{
try
{
var url = configuration["BlogCache:InvalidateUrl"];
var key = configuration["BlogCache:InvalidateKey"];
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(key)) return;
var client = httpClientFactory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(5);
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Add("X-Invalidate-Key", key);
await client.SendAsync(request);
}
catch (Exception ex)
{
logger.LogWarning(ex, "Failed to invalidate frontend blog cache");
}
}
private async Task<bool> IsAdmin(long userId) private async Task<bool> IsAdmin(long userId)
{ {
return await dbExecutor.ExecuteAsync<bool>( return await dbExecutor.ExecuteAsync<bool>(
+1
View File
@@ -21,6 +21,7 @@ builder.Services.AddScoped<MedicalDocsService>();
builder.Services.AddSingleton<MedicalAiService>(); builder.Services.AddSingleton<MedicalAiService>();
builder.Services.AddScoped<ThemeService>(); builder.Services.AddScoped<ThemeService>();
builder.Services.AddScoped<BlogService>(); builder.Services.AddScoped<BlogService>();
builder.Services.AddHttpClient();
// Add session support // Add session support
builder.Services.AddDistributedMemoryCache(); builder.Services.AddDistributedMemoryCache();
+4
View File
@@ -20,6 +20,10 @@
"FromName": "Media App", "FromName": "Media App",
"EnableSsl": "true" "EnableSsl": "true"
}, },
"BlogCache": {
"InvalidateUrl": "https://joshheaps.net/api/blog/invalidate",
"InvalidateKey": "CHANGE_ME"
},
"FileUpload": { "FileUpload": {
"MaxFileSizeMB": 10, "MaxFileSizeMB": 10,
"AllowedImageTypes": ["image/jpeg", "image/png", "image/gif", "image/webp"], "AllowedImageTypes": ["image/jpeg", "image/png", "image/gif", "image/webp"],