C# Programming Tutorial 0/45 lessons ~6 min read Lesson 40

    Working with APIs

    ASP.NET Core builds REST APIs with minimal APIs or controllers, model binding, validation, OpenAPI/Swagger, and ProblemDetails error responses.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    ASP.NET Core builds REST APIs with minimal APIs or controllers, model binding, validation, OpenAPI/Swagger, and ProblemDetails error responses. HttpClient (via IHttpClientFactory) consumes external APIs.

    Interviewers ask REST principles, status codes, idempotency, versioning, and middleware pipeline order.

    The story

    A fintech startup exposes a POST /api/payments endpoint that validates the amount, charges the customer through a gateway abstraction, and returns HTTP 201 Created with a location header pointing to the new payment record. Invalid amounts return 400 with structured validation errors — the same ProblemDetails format front-end apps expect.

    Understanding the topic

    Key concepts

    • Minimal APIs MapGet/MapPost with lambda or delegate.
    • Controller [ApiController] with automatic 400 on validation.
    • Model binding from route, query, body.
    • IHttpClientFactory typed clients with resilience.
    • ProblemDetails RFC 7807 standard errors.
    • OpenAPI document generation Swashbuckle/NSwag.
    text
    flowchart LR
    Client --> Kestrel
    Kestrel --> Middleware[Middleware Pipeline]
    Middleware --> Routing
    Routing --> Controller[Minimal API / Controller]
    Controller --> Response[JSON Response]

    Step-by-step explanation

    1. Request hits middleware → routing → endpoint.
    2. Binding populates parameters; validation runs.
    3. Handler returns IResult or IActionResult.
    4. JSON serializer writes response.
    5. Exception handler middleware maps to 500 ProblemDetails.
    6. Typed HttpClient registers base address and policies.

    Practical code example

    Minimal API with validation filter and typed HttpClient consumer:

    csharp
    namespace TechLearningPro.Apis;
    public record CreatePaymentRequest(decimal Amount, string Currency);
    public record PaymentResponse(Guid Id, string Status);
    public static class PaymentEndpoints
    {
    public static void MapPaymentApi(this WebApplication app)
    {
    app.MapPost("/api/payments", async (
    CreatePaymentRequest req,
    IPaymentGateway gateway,
    CancellationToken ct) =>
    {
    if (req.Amount <= 0)
    return Results.ValidationProblem(new Dictionary<string, string[]>
    {
    ["amount"] = ["Must be positive."]
    });
    var result = await gateway.ChargeAsync(req.Amount, req.Currency, ct);
    return Results.Created(
    quot;/api/payments/{result.Id}", result);
    });
    }
    }
    public interface IPaymentGateway
    {
    Task<PaymentResponse> ChargeAsync(decimal amount, string currency, CancellationToken ct);
    }

    Line-by-line code explanation

    • record CreatePaymentRequest(decimal Amount, string Currency) is the JSON request body shape.
    • record PaymentResponse(Guid Id, string Status) is the success response DTO.
    • MapPaymentApi(this WebApplication app) is an extension method organizing endpoint registration.
    • app.MapPost("/api/payments", async (...)) registers a POST handler on the route.
    • if (req.Amount <= 0) return Results.ValidationProblem(...) returns 400 with field-level errors.
    • await gateway.ChargeAsync(req.Amount, req.Currency, ct) delegates payment to the injected gateway.
    • Results.Created($"/api/payments/{result.Id}", result) returns 201 with Location header and body.
    • IPaymentGateway abstraction allows swapping Stripe, Adyen, or a test fake in DI.

    Key takeaway: Results.ValidationProblem returns 400 ProblemDetails. Created returns 201 with Location. Gateway injected via DI for testability.

    Real-world use

    Where you'll use this in production

    • Mobile backend BFF aggregating microservices.
    • Payment webhook receivers.
    • Internal admin APIs with OpenAPI docs.
    • Third-party SaaS integration via HttpClient.

    Best practices

    • Use correct HTTP verbs and status codes.
    • Validate input; never trust client.
    • IHttpClientFactory not new HttpClient().
    • Version APIs /api/v1/ or header.
    • Enable HTTPS, rate limiting, authentication.

    Common mistakes

    • GET with side effects.
    • Returning 200 with error in body only.
    • Leaking exception details in production 500.
    • Missing CancellationToken on I/O endpoints.

    Advanced interview questions

    Q1BeginnerREST idempotent methods?
    GET, PUT, DELETE idempotent; POST creates new.
    Q2Beginner201 vs 200?
    201 Created with Location for new resource; 200 OK for success without create semantics.
    Q3IntermediateIHttpClientFactory why?
    Manages handler lifetime, DNS refresh, Polly policies centrally.
    Q4IntermediateMinimal API vs controllers?
    Minimal concise for small services; controllers better for large MVC conventions.
    Q5AdvancedDesign idempotent POST payment endpoint.
    Idempotency-Key header stored unique; duplicate returns original 201; body hash match; 409 on key reuse different body.

    Summary

    ASP.NET Core exposes REST via minimal APIs or controllers. Model binding, validation, and ProblemDetails standardize APIs. IHttpClientFactory integrates external HTTP services. Correct status codes and idempotency matter in production. Next: Entity Framework Core.

    Ready to mark this lesson complete?Track your journey across the entire course.