3. A Simple HTTP API
Up to now, Autobarn has only produced HTML for people using a browser. This module adds a first, deliberately simple HTTP API that returns the same data as JSON for other programs to use. It’s built with ASP.NET Core minimal APIs and runs alongside the MVC controllers in the same web application.
What’s in this module
Autobarn.Website/
├── Api/
│ └── AutobarnApiEndpointRouteBuilderExtensions.cs (new)
└── Program.cs (changed)
Everything else is the same as Module 02.
Changes from Module 02
| File | Change |
|---|---|
Autobarn.Website/Api/AutobarnApiEndpointRouteBuilderExtensions.cs | Added. Defines four GET endpoints |
Autobarn.Website/Program.cs | Modified. Maps the API under /api |
Step 1: Define the API endpoints as an extension method
File: Autobarn.Website/Api/AutobarnApiEndpointRouteBuilderExtensions.cs (new)
using Autobarn.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
namespace Autobarn.Website.Api;
public static class AutobarnApiRouteBuilderExtensions {
public static IEndpointRouteBuilder MapAutobarnApi(this IEndpointRouteBuilder endpoints, string pattern) {
endpoints.MapGet(pattern + "/vehicles",
async (AutobarnDbContext db) => await db.Vehicles.ToListAsync());
endpoints.MapGet(pattern + "/vehicles/{registration}",
async (AutobarnDbContext db, string registration) => await db.Vehicles.FindAsync(registration));
endpoints.MapGet(pattern + "/makes",
async (AutobarnDbContext db) => await db.Makes.ToListAsync());
endpoints.MapGet(pattern + "/makes/{code}/models",
async (AutobarnDbContext db, string code) => await db.Models.Where(m => m.MakeCode == code).ToListAsync());
return endpoints;
}
}
How it works:
- Minimal APIs. Each
MapGetcall links a route template to a lambda. ASP.NET Core fills in the lambda’s parameters automatically.AutobarnDbContextcomes from dependency injection, andstring registrationandstring codecome from the{registration}and{code}route segments. - Automatic JSON serialisation. Whatever the lambda returns is written to the response as JSON using
System.Text.Json. - Extension method on
IEndpointRouteBuilder. Putting the API in its ownMapAutobarnApi()method keepsProgram.csshort and the API code in one place. It’s the same pattern the framework uses forMapControllerRouteandMapStaticAssets. patternparameter. The caller chooses the URL prefix, so the API isn’t tied to/api.
| Method | URL | Returns |
|---|---|---|
GET | /api/vehicles | Every vehicle in the database |
GET | /api/vehicles/{registration} | One vehicle |
GET | /api/makes | Every make |
GET | /api/makes/{code}/models | Every model for one make |
Step 2: Map the API in Program.cs
File: Autobarn.Website/Program.cs
using Autobarn.Data;
using Autobarn.Website.Api; // new
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
app.MapStaticAssets();
app.MapAutobarnApi("/api"); // new
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}")
.WithStaticAssets();
Why: The API and the MVC site share one process, one DbContext registration and one in-memory database. A vehicle added through the website’s Advertise form shows up straight away in /api/vehicles.
What’s wrong with this API?
The API is intentionally naive so that later modules have something to fix. Some things to point out to attendees:
- It returns entities directly. EF Core entities are serialised as they are, so the JSON shape is tied to the database schema. Navigation properties appear too.
Vehicle.Modelisnullbecause it wasn’t loaded withInclude, andVehicleMake.Modelsis an empty list. (Module 05 adds dedicated resource types.) - No pagination.
/api/vehiclesreturns all ~5,000 vehicles in one response. (Module 05 addsindexandcountpaging.) - No 404s.
/api/vehicles/NOPEdoesn’t return404 Not Found, and/api/makes/nope/modelsreturns an empty list, which looks the same as a real make with no models. (Module 04 adds typed results.) - No documentation. A client developer can only find out what endpoints exist by reading the source. (Module 04 adds OpenAPI and Scalar.)
- No links between resources. A client has to know it should build
/api/makes/{code}/modelsitself. (Module 05 adds hypermedia.) - Inconsistent route parameters. The make is
{code}in one place, and there’s no endpoint for a single make or model.
Trying it out
dotnet run --project Autobarn.Website
curl http://localhost:5000/api/makes
curl http://localhost:5000/api/makes/nissan/models
What’s next
Module 04 makes the API self-documenting with OpenAPI and adds an interactive API reference with Scalar.