Skip to Content
Course content

134: Building a Minimal REST API from Scratch

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're opening a food truck. Now, if you were opening a five-star restaurant, you'd need a host to greet guests, waiters to take orders, a kitchen manager to coordinate, and a complex seating chart. That's basically what the full MVC (Model-View-Controller) pattern in .NET feels like—lots of structure, which is great for a skyscraper of an app, but overkill for a taco stand.

A Minimal API is that food truck. You've got one window. The customer walks up, asks for a specific item, and you hand it to them immediately. There's no middleman. You've stripped away the boilerplate so you can focus entirely on the actual "food"—the data your API provides.

Mapping the Truck to the Code

In a Minimal API, we map these real-world actions directly to C# methods:

  • The Window: This is your Route. It's the specific URL (like /books) where the request arrives.
  • The Order Type: This is your HTTP Verb. A GET is like asking "Do you have tacos?", while a POST is like saying "I want to order a taco."
  • The Food: This is your JSON Response. It's the actual data you send back to the client.
  • The Order Ticket: This is the Request Body. If a user wants to add a new book, they send the details in a small packet of data.

Setting Up the Shop

We don't need a bunch of separate files for this. We can do it all in Program.cs. I'll use a "Digital Bookshelf" as our example because it's simple enough to follow but covers all the basics of data handling.

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// Our "database" for now—just a simple list in memory
var books = new List<Book>
{
    new Book(1, "The Fellowship of the Ring", "J.R.R. Tolkien"),
    new Book(2, "Neuromancer", "William Gibson")
};

// We'll define our routes here...

app.Run();

public record Book(int Id, string Title, string Author);

Notice I used a record for the Book. Records are perfect for APIs because they're immutable and concise. Since we're just moving data around, we don't need a full-blown class with getters and setters.

Handling the Requests

Now we need to actually map the routes. This is where the "Minimal" part really shines. Instead of creating a BooksController class, we just call MapGet or MapPost directly on the app object.

// Get all books
app.MapGet("/books", () => books);

// Get a specific book by ID
app.MapGet("/books/{id}", (int id) => 
{
    var book = books.FirstOrDefault(b => b.Id == id);
    return book is not null ? Results.Ok(book) : Results.NotFound();
});

// Add a new book
app.MapPost("/books", (Book book) => 
{
    books.Add(book);
    return Results.Created($"/books/{book.Id}", book);
});

I've used a few different patterns here. The first one is a simple lambda that returns the whole list. .NET is smart enough to automatically turn that list into JSON. For the second one, I used Results.Ok and Results.NotFound. You want to do this because it tells the client exactly what happened via HTTP status codes (200 for success, 404 for missing), which is the "law of the land" for REST APIs.

A Note on State

You'll notice that books is just a local list. In a real app, you'd inject a database context here. But for a minimal service or a prototype, this in-memory approach is a lifesaver for speed. Just remember: every time you restart the app, your "bookshelf" resets to the original two books. It's a volatile state, but it's perfect for testing your logic before you commit to a heavy SQL Server setup.




📋 Practical Task

Build a Minimal Movie Rental Catalog

Your task is to expand on the Digital Bookshelf concept to create a Movie Rental API. You need to build a service that allows a user to track which movies are available for rent.

Requirements:

  • Create a Movie record containing an Id (int), Title (string), and IsRented (bool).
  • Initialize a list with at least three movies.
  • Implement a GET /movies endpoint that returns the full list of movies.
  • Implement a GET /movies/{id} endpoint that returns a specific movie or a 404 if not found.
  • Implement a PATCH /movies/{id}/rent endpoint. This endpoint should find the movie by ID and flip the IsRented value to true, then return the updated movie. (Hint: Since records are immutable, you'll need to replace the movie in the list or use a class instead of a record for the Movie model).
Rating
0 0

There are no comments for now.

to be the first to leave a comment.