What You Will Build in This Lesson
In this lesson, you will build the structure of a small Orders API. The goal is not just to create endpoints, but to create a production-minded API that is easy to debug, document, test, and extend in later lessons.
/api/orders.Part 1: Create an ASP.NET Core Web API Project
In Visual Studio 2026, create a new ASP.NET Core Web API project. For beginners, start with the standard Web API template. For lightweight cloud services, you can also choose a Minimal API style project.
Create the project
Select ASP.NET Core Web API, name it OrdersApi, and choose the latest .NET runtime available in your setup.
Enable OpenAPI
Keep OpenAPI support enabled so Visual Studio can help you test and document endpoints.
Run the app
Press F5 for debugging or Ctrl + F5 to run without the debugger.
Part 2: Use Route Groups to Organize Endpoints
Route groups keep related endpoints together. Instead of repeating /api/orders, authorization, tags, and OpenAPI settings on every endpoint, define them once on the group.
builder.Services.AddAuthorization();
builder.Services.AddOpenApi();
builder.Services.AddScoped<IOrderService, OrderService>();
var app = builder.Build();
app.MapOpenApi();
app.UseAuthorization();
var orders = app.MapGroup("/api/orders")
.WithTags("Orders")
.WithOpenApi();
orders.MapGet("/", async (IOrderService service) =>
Results.Ok(await service.GetAllAsync()));
orders.MapGet("/{id:int}", async (int id, IOrderService service) =>
await service.FindAsync(id) is { } order
? Results.Ok(order)
: Results.NotFound());
app.Run();
This structure makes the API easier to read because each route group represents a resource area: orders, customers, products, reports, accounts, and so on.
Part 3: Design Request and Response Models
A production API should not expose internal database entities directly. Use small request and response models so your API contract remains stable even when the database design changes.
[Required] string CustomerName,
[Range(1, 999999)] decimal Total);
public sealed record OrderResponse(
int Id,
string CustomerName,
decimal Total,
string Status);
Part 4: Move Logic into a Service Class
Minimal APIs are cleanest when endpoint handlers stay short. Put business rules, database queries, and validation logic into services that are injected into endpoints.
{
Task<IReadOnlyList<OrderResponse>> GetAllAsync();
Task<OrderResponse?> FindAsync(int id);
Task<OrderResponse> CreateAsync(CreateOrderRequest request);
}
public sealed class OrderService : IOrderService
{
// In Lesson 6, this can use EF Core instead of an in-memory list.
}
| Layer | Responsibility | Example |
|---|---|---|
| Endpoint | HTTP routing and response shape | MapGet, MapPost, Results.Ok |
| Service | Business rules and workflow | Check order status, calculate totals |
| Repository/Data | Database access | EF Core queries in Lesson 6 |
Part 5: Use Problem Details for API Errors
Clients should receive predictable error responses. Problem Details is a standard JSON format for describing HTTP API errors. It is especially useful for validation failures, missing resources, and server exceptions.
var app = builder.Build();
app.UseExceptionHandler();
orders.MapGet("/{id:int}", async (int id, IOrderService service) =>
await service.FindAsync(id) is { } order
? Results.Ok(order)
: Results.Problem("Order was not found.", statusCode: 404));
Part 6: Add OpenAPI and Scalar UI
OpenAPI documents describe your endpoints, request bodies, response types, authentication requirements, and error formats. Visual Studio can help you test your API during development, while OpenAPI files can also be used to generate client SDKs.
var app = builder.Build();
app.MapOpenApi(); // Usually /openapi/v1.json
For an interactive API documentation page, you can integrate Scalar by adding the Scalar.AspNetCore package and mapping its API reference page.
builder.Services.AddOpenApi();
app.MapOpenApi();
app.MapScalarApiReference();
Part 7: Add Authorization Habits Early
Even a simple API should be designed with security in mind. In early lessons, the goal is to understand where authorization belongs. Later, you can connect JWT bearer tokens, Microsoft Entra ID, Identity, or another provider.
builder.Services.AddAuthorization();
var orders = app.MapGroup("/api/orders")
.RequireAuthorization();
orders.MapPost("/", async (CreateOrderRequest request, IOrderService service) =>
{
var created = await service.CreateAsync(request);
return Results.Created($"/api/orders/{created.Id}", created);
});
| Area | Good habit |
|---|---|
| Input | Validate request models and reject bad data early. |
| Authorization | Protect write endpoints such as POST, PUT, and DELETE. |
| Secrets | Never hard-code connection strings, API keys, or tokens in source code. |
| Logging | Log useful diagnostics, but avoid storing passwords, tokens, or private user data. |
Part 8: Native AOT Readiness
Native AOT can publish an ASP.NET Core app as a native executable. It can reduce startup time and memory usage for suitable services, but it also requires careful library choices and testing.
<PropertyGroup>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
Part 9: Test the API in Visual Studio 2026
Visual Studio can run your Web API, attach the debugger, show logs, inspect exceptions, and help you test endpoints. You can also keep an .http file in your solution to test repeatable API requests.
GET {{host}}/api/orders
Accept: application/json
###
POST {{host}}/api/orders
Content-Type: application/json
{
"customerName": "Dr. Liew",
"total": 250.00
}
Part 10: Before You Deploy an API
| Checklist item | Why it matters |
|---|---|
| Health endpoint | Helps cloud platforms and monitoring tools check whether the API is alive. |
| Central error handling | Prevents inconsistent error responses across endpoints. |
| OpenAPI contract | Helps developers and client apps understand how to call the API. |
| Authentication and authorization | Protects private data and write operations. |
| Logging and diagnostics | Helps you investigate failures without guessing. |
| Unit and integration tests | Reduces the risk of breaking routes, validation, and business rules. |
Hands-On Exercise: Build a Small Orders API
Create a Minimal API project called OrdersApi. Then complete these tasks:
- Add route group
/api/orders. - Add
GET /api/ordersandGET /api/orders/{id}. - Add a
CreateOrderRequestmodel with validation attributes. - Add
POST /api/ordersand returnResults.Created. - Add OpenAPI support and test the generated endpoint document.
- Create an
orders.httpfile and test at least two requests.
Visual Studio 2026 Made Easy
Continue learning Visual Studio 2026 with a structured companion book covering C#, VB.NET, Python, JavaScript, C++, .NET 10, debugging, deployment, and practical projects.