From c046553fcbb1785b38a1d078ebb599779856867b Mon Sep 17 00:00:00 2001 From: Lea Foreman Date: Tue, 26 May 2026 14:14:13 +0100 Subject: [PATCH] Add API documentation and implement sample todos endpoint --- .instructions.md | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ Program.cs | 25 +++++++++----- 2 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 .instructions.md diff --git a/.instructions.md b/.instructions.md new file mode 100644 index 0000000..bd09153 --- /dev/null +++ b/.instructions.md @@ -0,0 +1,89 @@ +# WebAPI Code Review Guidelines + +## API Documentation + +This is a todo management REST API built with ASP.NET Core 10 using the minimal APIs pattern. + +### Current Endpoints + +#### GET /todos +- **Name**: GetTodos +- **Description**: Retrieves all todo items +- **Response**: Array of `Todo` objects +- **Status Codes**: 200 OK + +#### GET /todos/{id} +- **Name**: GetTodoById +- **Description**: Retrieves a specific todo item by ID +- **Path Parameters**: `id` (int) - The todo item ID +- **Response**: `Todo` object if found, 404 if not found +- **Status Codes**: 200 OK, 404 Not Found + +#### POST /todos +- **Name**: CreateTodo +- **Description**: Creates a new todo item +- **Request Body**: Plain string - the todo title +- **Response**: Created `Todo` object with generated ID +- **Status Codes**: 201 Created +- **Location Header**: `/todos/{newId}` pointing to the newly created resource + +### Data Model + +```csharp +public record Todo( + int Id, + string? Title, + DateOnly? DueBy = null, + bool IsComplete = false +); +``` + +- **Id**: Unique identifier (auto-generated on creation) +- **Title**: The todo item description +- **DueBy**: Optional due date +- **IsComplete**: Completion status (default: false) + +## Code Review Checklist + +When reviewing changes to this API, ensure: + +### Endpoint Design +- [ ] New endpoints follow the `MapGet/MapPost/MapPut/MapDelete` pattern with the `/todos` group +- [ ] All endpoints have meaningful `WithName()` identifiers +- [ ] HTTP status codes are appropriate (201 for creation, 404 for not found, etc.) +- [ ] POST endpoints use `TypedResults.Created()` and return the created resource + +### Data Handling +- [ ] New IDs are generated correctly (current logic: `Max(t => t.Id) + 1`) +- [ ] All todo items are properly serialized/deserialized with `AppJsonSerializerContext` +- [ ] Optional fields are properly nullable (`DateOnly?`, `string?`) + +### In-Memory Storage +- [ ] The `sampleTodos` list is a `List` (mutable for POST/PUT/DELETE operations) +- [ ] Data operations maintain data integrity +- [ ] Consider future migration to a database when needed + +### API Contract +- [ ] All new endpoints are documented with `WithName()` +- [ ] OpenAPI/Swagger documentation is accurate (enable with `app.MapOpenApi()` in Development) +- [ ] Request/response types align with the `Todo` record definition + +### Testing Considerations +- [ ] POST endpoint should test ID generation with multiple creates +- [ ] GET endpoints should handle both existing and non-existent IDs +- [ ] Consider testing edge cases (empty lists, max int IDs, etc.) + +## Technology Stack + +- **.NET**: 10.0 +- **Framework**: ASP.NET Core (Minimal APIs) +- **Serialization**: System.Text.Json +- **API Documentation**: OpenAPI (Swagger) support enabled + +## Future Enhancement Areas + +- Implement DELETE and PUT endpoints for updating and deleting todos +- Add database persistence (Entity Framework Core) +- Add input validation (title length, date validation) +- Implement filtering/pagination for GET /todos +- Add async database operations diff --git a/Program.cs b/Program.cs index f96530e..6993a82 100644 --- a/Program.cs +++ b/Program.cs @@ -18,14 +18,14 @@ app.MapOpenApi(); } -Todo[] sampleTodos = -[ - new(1, "Walk the dog"), - new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)), - new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))), - new(4, "Clean the bathroom"), - new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2))) -]; +var sampleTodos = new List +{ + new Todo(1, "Walk the dog"), + new Todo(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)), + new Todo(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))), + new Todo(4, "Clean the bathroom"), + new Todo(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2))) +}; var todosApi = app.MapGroup("/todos"); todosApi.MapGet("/", () => sampleTodos) @@ -37,6 +37,15 @@ : TypedResults.NotFound()) .WithName("GetTodoById"); +todosApi.MapPost("/", (string title) => +{ + var newId = sampleTodos.Max(t => t.Id) + 1; + var newTodo = new Todo(newId, title); + sampleTodos.Add(newTodo); + return TypedResults.Created($"/todos/{newId}", newTodo); +}) + .WithName("CreateTodo"); + app.Run(); public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false);