Add the Put Endpoint
In the Models folder add a new file called UpdateTaskDto.cs
namespace CrudAppAPI.Models;
public class UpdateTaskDto
{
public int Id { get; set; }
public string Title { get; set; } = default!;
public string? Description { get; set; }
public DateTime? DueDate { get; set; }
public bool Completed { get; set; }
}
You could reuse CreateTaskDto, but separating input models keeps things clearer and future-proof (e.g. if you later allow partial updates or different rules for update vs create
Add a new file to the Validators directory called UpdateTaskDtoValidator.cs
using CrudAppAPIV2.Models;
using FluentValidation;
namespace CrudAppAPIV2.Validators;
public class UpdateTaskDtoValidator : AbstractValidator<UpdateTaskDto>
{
public UpdateTaskDtoValidator()
{
RuleFor(x => x.Id).GreaterThan(0).WithMessage("Task ID must be greater than zero.");
RuleFor(x => x.Title).NotEmpty().WithMessage("Title is required.");
RuleFor(x => x.Description).MaximumLength(255).WithMessage("Description can't be longer than 255 characters.");
RuleFor(x => x.DueDate).GreaterThan(DateTime.Now).WithMessage("Due date must be in the future.");
}
}
Register the following services in the Program.cs file
builder.Services.AddValidatorsFromAssemblyContaining<UpdateTaskDtoValidator>();
In the TaskService.cs file add the following method
public async Task UpdateTaskAsync(UpdateTaskDto dto)
{
using var conn = await _connectionFactory.CreateConnectionAsync();
var spName = "UpdateTask"; // Stored procedure name
var parameters = new DynamicParameters();
parameters.Add("@Id", dto.Id);
parameters.Add("@Title", dto.Title);
parameters.Add("@Description", dto.Description);
parameters.Add("@DueDate", dto.DueDate);
parameters.Add("@Completed", dto.Completed);
await conn.ExecuteAsync(spName, parameters, commandType: CommandType.StoredProcedure);
}
In the TaskEndpoints.cs file add the following endpoint
app.MapPut("/api/tasks/{id}", async (int id, UpdateTaskDto dto, TaskService service, IValidator<UpdateTaskDto> validator) =>
{
// Validate the DTO
var validationResult = await validator.ValidateAsync(dto);
if (!validationResult.IsValid)
{
return Results.BadRequest(validationResult.Errors);
}
// Ensure the ID from the URL matches the DTO
if (dto.Id != id)
{
return Results.BadRequest("Task ID mismatch");
}
// Call the service to update the task
await service.UpdateTaskAsync(dto);
return Results.Ok();
});
In Postman or Rider etc
PUT /api/tasks/1
{
"title": "Updated Task",
"description": "Revised content",
"dueDate": "2025-07-15",
"completed": true
}