From 5e92ab2a96699c68b6a0609c8d9c3f7d953e78eb Mon Sep 17 00:00:00 2001 From: bubus128 Date: Sat, 22 Mar 2025 21:34:47 +0100 Subject: [PATCH 1/2] Create api endpoints --- src/IssueManager.Api/IssueManager.Api.csproj | 12 +- src/IssueManager.Api/Program.cs | 138 +++++++++++++++--- .../Properties/launchSettings.json | 2 +- src/IssueManager.Core/Class1.cs | 6 - .../Exceptions/IssueNotFoundException.cs | 4 + .../IssueManager.Core.csproj | 2 +- .../Models/Interfaces/IIssue.cs | 4 + src/IssueManager.Core/Models/Issue.cs | 6 + .../Interfaces/IRepositoryService.cs | 12 ++ .../RepositoryService/RepositoryService.cs | 38 +++++ .../IssueManager.Api.Tests.csproj | 2 +- .../IssueManager.Core.Tests.csproj | 2 +- 12 files changed, 198 insertions(+), 30 deletions(-) delete mode 100644 src/IssueManager.Core/Class1.cs create mode 100644 src/IssueManager.Core/Exceptions/IssueNotFoundException.cs create mode 100644 src/IssueManager.Core/Models/Interfaces/IIssue.cs create mode 100644 src/IssueManager.Core/Models/Issue.cs create mode 100644 src/IssueManager.Core/RepositoryService/Interfaces/IRepositoryService.cs create mode 100644 src/IssueManager.Core/RepositoryService/RepositoryService.cs diff --git a/src/IssueManager.Api/IssueManager.Api.csproj b/src/IssueManager.Api/IssueManager.Api.csproj index e30f89b..638c459 100644 --- a/src/IssueManager.Api/IssueManager.Api.csproj +++ b/src/IssueManager.Api/IssueManager.Api.csproj @@ -1,7 +1,7 @@ - + - net8.0 + net9.0 enable enable 8ebb9eeb-02e2-49c6-ada9-e14634e4aeb7 @@ -9,7 +9,15 @@ + + + + + + + + diff --git a/src/IssueManager.Api/Program.cs b/src/IssueManager.Api/Program.cs index 79d31a9..fcad9e6 100644 --- a/src/IssueManager.Api/Program.cs +++ b/src/IssueManager.Api/Program.cs @@ -1,34 +1,136 @@ +using IssueManager.Core.Exceptions; +using IssueManager.Core.Models.Interfaces; +using IssueManager.Core.RepositoryService; +using IssueManager.Core.RepositoryService.Interfaces; +using Microsoft.OpenApi.Models; +using Scalar.AspNetCore; + var builder = WebApplication.CreateBuilder(args); +builder.Services.AddOpenApi(); + // Add services to the container. +builder.Services.AddSingleton(); var app = builder.Build(); -// Configure the HTTP request pipeline. - app.UseHttpsRedirection(); -var summaries = new[] +app.MapGet("/issues", async Task (IRepositoryService repositoryService) => { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" -}; + try + { + return TypedResults.Ok(await repositoryService.GetAllIssues()); + } + catch (Exception exception) + { + Console.Error.WriteLine($"Error getting issues: {exception.Message}"); + return TypedResults.Problem("An unexpected error occurred while getting issues.", statusCode: 500); + } +}) +.WithName("GetIssues") +.WithOpenApi(x => new OpenApiOperation(x) +{ + Summary = "Get all issues", + Description = "Returns all open issues.", + Tags = new List { new() { Name = "All issues" } } +}); -app.MapGet("/weatherforecast", () => +app.MapGet("/issues/{id}", async Task (int id, IRepositoryService repositoryService) => { - var forecast = Enumerable.Range(1, 5).Select(index => - new WeatherForecast - ( - DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - Random.Shared.Next(-20, 55), - summaries[Random.Shared.Next(summaries.Length)] - )) - .ToArray(); - return forecast; + try + { + return TypedResults.Ok(await repositoryService.GetIssueById(id)); + } + catch (Exception exception) + { + Console.Error.WriteLine($"Error getting issue with ID {id}: {exception.Message}"); + return TypedResults.Problem($"An unexpected error occurred while getting issue with ID: {id}.", statusCode: 500); + } +}) +.WithName("GetIssueById") +.WithOpenApi(x => new OpenApiOperation(x) +{ + Summary = "Get issue by ID", + Description = "Returns an issue with given ID.", + Tags = new List { new() { Name = "Issue by ID" } } }); -app.Run(); +app.MapDelete("/issues/{id}", async Task (int id, IRepositoryService repositoryService) => +{ + try + { + await repositoryService.DeleteIssue(id); + } + catch (IssueNotFoundException) + { + return TypedResults.NotFound($"Issue with ID {id} not found."); + } + catch (Exception exception) + { + Console.Error.WriteLine($"Error deleting issue {id}: {exception.Message}"); + return TypedResults.Problem("An unexpected error occurred while deleting the issue.", statusCode: 500); + } + return TypedResults.Ok($"Issue with ID {id} deleted successfully."); +}) +.WithName("DeleteIssue").WithOpenApi(x => new OpenApiOperation(x) +{ + Summary = "Delete issue by ID", + Description = "Deletes an issue with given ID.", + Tags = new List { new() { Name = "Delete issue" } } +}); -internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +app.MapPost("/issues", async (IIssue issue, IRepositoryService repositoryService) => + { + try + { + var id = await repositoryService.CreateIssue(issue); + return Results.Created($"/issues/{id}", new { Id = id }); + } + catch (Exception exception) + { + Console.Error.WriteLine($"Error creating issue: {exception.Message}"); + return TypedResults.Problem("An unexpected error occurred while creating the issue.", statusCode: 500); + } + } +).WithName("CreateIssue").WithOpenApi(x => new OpenApiOperation(x) { - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + Summary = "Create issue", + Description = "Creates an issue", + Tags = new List { new() { Name = "Create issue" } } +}); + +app.MapPut("/issues/{id}", async (IIssue issue, IRepositoryService repositoryService) => +{ + try + { + var id = await repositoryService.UpdateIssue(issue); + + return Results.NoContent(); + } + catch (IssueNotFoundException) + { + return TypedResults.NotFound($"Issue with ID not found."); + } + catch (Exception ex) + { + return Results.Problem(ex.Message); + } +}).WithName("UpdateIssue").WithOpenApi(x => new OpenApiOperation(x) +{ + Summary = "Update issue", + Description = "Updates an issue", + Tags = new List { new() { Name = "Update issue" } } +}); + +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); + app.UseSwaggerUI(options => + options.SwaggerEndpoint("/openapi/v1.json", "OpenAPI V1")); + app.UseReDoc(options => + options.SpecUrl("/openapi/v1.json")); + app.MapScalarApiReference(); + } +app.Run(); diff --git a/src/IssueManager.Api/Properties/launchSettings.json b/src/IssueManager.Api/Properties/launchSettings.json index 4ced2d3..b72bed2 100644 --- a/src/IssueManager.Api/Properties/launchSettings.json +++ b/src/IssueManager.Api/Properties/launchSettings.json @@ -23,7 +23,7 @@ "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, - "launchUrl": "weatherforecast", + "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/IssueManager.Core/Class1.cs b/src/IssueManager.Core/Class1.cs deleted file mode 100644 index 4023165..0000000 --- a/src/IssueManager.Core/Class1.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace IssueManager.Core; - -public class Class1 -{ - -} diff --git a/src/IssueManager.Core/Exceptions/IssueNotFoundException.cs b/src/IssueManager.Core/Exceptions/IssueNotFoundException.cs new file mode 100644 index 0000000..e70142c --- /dev/null +++ b/src/IssueManager.Core/Exceptions/IssueNotFoundException.cs @@ -0,0 +1,4 @@ +namespace IssueManager.Core.Exceptions; +public class IssueNotFoundException : Exception +{ +} diff --git a/src/IssueManager.Core/IssueManager.Core.csproj b/src/IssueManager.Core/IssueManager.Core.csproj index bb23fb7..cdc91ea 100644 --- a/src/IssueManager.Core/IssueManager.Core.csproj +++ b/src/IssueManager.Core/IssueManager.Core.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/src/IssueManager.Core/Models/Interfaces/IIssue.cs b/src/IssueManager.Core/Models/Interfaces/IIssue.cs new file mode 100644 index 0000000..d5ae5cb --- /dev/null +++ b/src/IssueManager.Core/Models/Interfaces/IIssue.cs @@ -0,0 +1,4 @@ +namespace IssueManager.Core.Models.Interfaces; +public interface IIssue +{ +} diff --git a/src/IssueManager.Core/Models/Issue.cs b/src/IssueManager.Core/Models/Issue.cs new file mode 100644 index 0000000..e8bda6a --- /dev/null +++ b/src/IssueManager.Core/Models/Issue.cs @@ -0,0 +1,6 @@ +using IssueManager.Core.Models.Interfaces; + +namespace IssueManager.Core.Models; +public class Issue : IIssue +{ +} diff --git a/src/IssueManager.Core/RepositoryService/Interfaces/IRepositoryService.cs b/src/IssueManager.Core/RepositoryService/Interfaces/IRepositoryService.cs new file mode 100644 index 0000000..0542649 --- /dev/null +++ b/src/IssueManager.Core/RepositoryService/Interfaces/IRepositoryService.cs @@ -0,0 +1,12 @@ +using IssueManager.Core.Models.Interfaces; + +namespace IssueManager.Core.RepositoryService.Interfaces; + +public interface IRepositoryService +{ + public Task> GetAllIssues(); + public Task GetIssueById(T id); + public Task UpdateIssue(IIssue issue); + public Task CreateIssue(IIssue issue); + public Task DeleteIssue(T id); +} diff --git a/src/IssueManager.Core/RepositoryService/RepositoryService.cs b/src/IssueManager.Core/RepositoryService/RepositoryService.cs new file mode 100644 index 0000000..cfc6025 --- /dev/null +++ b/src/IssueManager.Core/RepositoryService/RepositoryService.cs @@ -0,0 +1,38 @@ +using IssueManager.Core.Models.Interfaces; +using IssueManager.Core.RepositoryService.Interfaces; + +namespace IssueManager.Core.RepositoryService; +public class RepositoryService : IRepositoryService +{ +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously + public async Task DeleteIssue(T id) + { + throw new NotImplementedException(); + } + + public async Task> GetAllIssues() + { + throw new NotImplementedException(); + } + + public async Task GetIssueById(T id) + { + throw new NotImplementedException(); + } + + public async Task CreateIssue(IIssue issue) + { + throw new NotImplementedException(); + } + + public async Task UpdateIssue(IIssue issue) + { + throw new NotImplementedException(); + } + + Task IRepositoryService.UpdateIssue(IIssue issue) + { + throw new NotImplementedException(); + } +#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously +} diff --git a/src/test/IssueManager.Api.Tests/IssueManager.Api.Tests.csproj b/src/test/IssueManager.Api.Tests/IssueManager.Api.Tests.csproj index d9e4113..781dc6d 100644 --- a/src/test/IssueManager.Api.Tests/IssueManager.Api.Tests.csproj +++ b/src/test/IssueManager.Api.Tests/IssueManager.Api.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable diff --git a/src/test/IssueManager.Core.Tests/IssueManager.Core.Tests.csproj b/src/test/IssueManager.Core.Tests/IssueManager.Core.Tests.csproj index d9e4113..781dc6d 100644 --- a/src/test/IssueManager.Core.Tests/IssueManager.Core.Tests.csproj +++ b/src/test/IssueManager.Core.Tests/IssueManager.Core.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable From b086b6b2f5c338cf2a5d43c68beceb60511ebbe3 Mon Sep 17 00:00:00 2001 From: bubus128 Date: Sat, 22 Mar 2025 21:38:23 +0100 Subject: [PATCH 2/2] Fix net version in workflow --- .github/workflows/run_unit_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml index 2cc68b4..1f260a9 100644 --- a/.github/workflows/run_unit_tests.yml +++ b/.github/workflows/run_unit_tests.yml @@ -20,7 +20,7 @@ jobs: - name: Setup .NET Core SDK uses: actions/setup-dotnet@v1 with: - dotnet-version: 8.x + dotnet-version: 9.x - name: Restore dependencies run: dotnet restore src/IssueManager.sln