DEV Community

Cover image for πŸš€ Updating and Deleting Tasks in Our .NET + PostgreSQL Todo API
Asutosh Padhi
Asutosh Padhi

Posted on

πŸš€ Updating and Deleting Tasks in Our .NET + PostgreSQL Todo API

In the previous post, we created new tasks and got our backend to communicate with PostgreSQL. By including Update (PUT) and Delete (DELETE) routes, we will finish the circle today. This indicates that our small API can now perform full CRUD!

But first, a brief note before we get into the code:
πŸ‘‰ It wasn't the best idea to store PostgreSQL credentials directly in appsettings.json, as someone noted in the previous post's comments. It's true! An environment variable (or a .env file with something like dotnet user-secrets or dotenv.net) can be used instead. In this manner, you can avoid inadvertently entering your database password into GitHub.


πŸ”§ Step 1: Adding Update (PUT) Route

When we update, we take an existing task, make changes to its fields, and then save it again. That is typically a FindAsync β†’ modify β†’ SaveChangesAsync pattern in EF Core.

This is how it appears in a minimalist API style:

// Update a task
app.MapPut("/api/tasks/{id}", async (AppDbContext db, int id, TodoItem updatedTask) =>
{
    var toBeUpdated = await db.Tasks.FindAsync(id);
    if (toBeUpdated == null) return Results.NotFound();

    toBeUpdated.Title = updatedTask.Title;
    toBeUpdated.IsComplete = updatedTask.IsComplete;

    await db.SaveChangesAsync();
    return Results.Ok(toBeUpdated);
});
Enter fullscreen mode Exit fullscreen mode

πŸ” What is going on here?

  • The URL (/api/tasks/3) is where the id originates.
  • db is the database context that .NET injects into our database.
  • The request body (the updated values) is where updatedTask originates.
  • We update the task's fields, verify that it exists, and then save.

πŸ”§ Step 2: Adding the delete (DELETE) route

Deleting is even simpler:

// Delete a task
app.MapDelete("/api/tasks/{id}", async (int id, AppDbContext db) =>
{
    var task = await db.Tasks.FindAsync(id);
    if (task == null) return Results.NotFound();

    db.Tasks.Remove(task);
    await db.SaveChangesAsync();

    return Results.Ok(new { message = $"Task {id} deleted" });
});
Enter fullscreen mode Exit fullscreen mode

That’s it! If the task is found, it’s removed. Otherwise, the API returns a 404 Not Found.


πŸ”§Step 3: Trying it our on Postman

PUT: Send a request to http://localhost:5001/api/tasks/1 with body:

{
  "title": "Write blog post",
  "isComplete": true
}
Enter fullscreen mode Exit fullscreen mode

DELETE: Send a request to http://localhost:5001/api/tasks/1.

That's it! If you've done everything as suggested, the routes will update the task with ID 1 and delete it respectively.


🌱 Small Improvement: Store DB Credentials in Environment Variables

Instead of in appsettings.json:

"ConnectionStrings": {
  "DefaultConnection": "Host=localhost;Database=todo_db;Username=postgres;Password=supersecret"
}
Enter fullscreen mode Exit fullscreen mode

Use environment variables through Program.cs (cross-platform safe):

builder.Services.AddDbContext<AppDbContext>(options => options.UseNpgsql(Environment.GetEnvironmentVariable("PG_CONNECTION")));
Enter fullscreen mode Exit fullscreen mode

And in your shell:

export PG_CONNECTION="Host=localhost;Database=todo_db;Username=postgres;Password=supersecret"
Enter fullscreen mode Exit fullscreen mode

This way, you won’t leak secrets into GitHub.


πŸ—‚οΈ Full Codebase + Frontend

I've posted the complete codebase to GitHub, go there if you want to view it, tweak it and build it along with the React frontend that uses this API.

That way, you won't just be reading snippets.

Top comments (0)