DeveloperHA / Learn / ASP.NET APIs
ASP.NET APIs learning path

ASP.NET APIs that are easy to use and operate

Design HTTP endpoints with clear contracts, validation, cancellation, errors and operational behavior.

Practical30–45 min4 lessons

Outcome: Make an API contract explicit and avoid common integration surprises.

Your local progress0 / 4 complete

A good endpoint is a small agreement: what comes in, what can happen, what comes out and how failure is represented.

Work through the path

Open a card when you need it. Marking a lesson complete is optional and stays only in this browser.

1Let HTTP status codes carry meaning

Contracts5 min

A predictable status code and response shape help clients handle success, absence, validation and conflict without guessing.

Use the status code for the broad outcome and the body for useful details. A successful create commonly returns 201 with a location or representation.

Consistency matters more than picking the theoretically perfect code for every edge case. Document the choice in OpenAPI and test it.

Try it

Write a table of outcomes for one endpoint: valid, missing, invalid, conflict and unexpected failure.

Watch outDo not return 200 with an error object for every failure; clients should not invent status semantics.
Generate a client from OpenAPI →
Example
app.MapGet("/orders/{id:guid}", async (
    Guid id, IOrderQueries queries, CancellationToken token) =>
{
    var order = await queries.FindAsync(id, token);
    return order is null ? Results.NotFound() : Results.Ok(order);
});

2Validate at the boundary, enforce in the domain

Input5 min

Transport validation checks shape and basic rules; domain logic protects business invariants wherever the object is used.

A request DTO can reject an empty name or malformed identifier before the handler does work. The domain still needs rules such as a submitted order requiring at least one line.

Return a stable problem-details shape so clients can show field errors without parsing prose.

Try it

Separate a malformed request from a valid request that violates a business rule. Give each a different test and response reason.

Watch outAttributes are not a complete validation strategy for complex invariants or authorization.
Run a test request →
Example
public sealed record CreateLine(
    Guid ProductId,
    [property: Range(1, 10000)] int Quantity);

public sealed record CreateOrderRequest(
    Guid CustomerId,
    [property: MinLength(1)] IReadOnlyList<CreateLine> Lines);

3Return errors clients can act on

Errors5 min

Problem Details gives HTTP APIs a consistent error envelope without leaking stack traces or internal secrets.

Clients need a status, stable type or code and human-readable title. Validation errors also need field-level details.

Keep internal exception messages and connection details in server logs, not in responses. A correlation ID connects the two safely.

Try it

Take one exception response and remove details a consumer does not need. Put them in structured logs instead.

Watch outA generic 500 response is safer than a stack trace, but it still needs server-side logging.
Inspect the HTTP response →
Example
return Results.Problem(
    statusCode: StatusCodes.Status409Conflict,
    title: "Order cannot be submitted",
    detail: "The order changed. Reload and try again.",
    type: "https://developerha.com/problems/order-conflict");

4Make retries safe for commands

Integration6 min

A client may retry after a network failure even when the server already processed the command, so define an idempotency strategy.

GET is intended to be safe to repeat; payment or order submission may not be. An idempotency key associates repeats with the same intended operation and original result.

Store the key with a request fingerprint and result. Decide how long it is valid and what happens when the same key is reused with different input.

Try it

Simulate a client timeout after sending a command. Decide what the second request receives and how the server recognizes it.

Watch outAn idempotency key is not authentication; authorize the caller and protect stored results.
Send a safe test request →
Example
POST /payments HTTP/1.1
Idempotency-Key: 4a8a0a8d-demo
Content-Type: application/json

{ "amount": 1200, "currency": "EUR" }

No lesson matches that phrase.

Related tools

Turn the concept into a working example with the browser-based tools.

Need a second pair of eyes?

When the quick answer turns into an architecture or delivery decision, use a fixed-price review or talk to DeveloperHA.

See packages All learning paths