SwaggerEF CoreAugust 2026 · 6 min read

Building a REST API with Swagger and EF Core 10: End-to-End Tutorial

TL;DR

You can build a full REST API with Swagger and EF Core 10 in one file: entity, DbContext, CRUD endpoints, and Swagger wiring. Migrations keep the database and the OpenAPI contract evolving together.

A REST API with Swagger is the delivery vehicle; EF Core 10 is the engine that moves the data. Together they form the backbone of most line-of-business applications: entities mapped with EF Core, CRUD endpoints exposed over HTTP, and Swagger UI as the living documentation for every operation. This tutorial builds a complete product API from scratch — entity, DbContext, endpoints, migrations, and the Swagger configuration that ties it together.

We use a minimal API because it keeps the whole vertical slice readable in a single file — the same style used throughout the Indotalent codebase. Everything is .NET 10 and EF Core 10, and the endpoint code runs against a real DbContext, not an in-memory mock.

REST API with Swagger and EF Core 10: The Data Layer

Start with the domain: a Product entity with an identifier, name, price, and stock count. Keep the entity a plain class — EF Core maps it to the Products table by convention.

public class Product
{
    public Guid Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public int Stock { get; set; }
    public DateTimeOffset CreatedAt { get; set; }
}

Next the DbContext. Register it with the connection string and expose the Product entity through a DbSet. EF Core 10 handles tracking, change detection, and SQL generation; your endpoints only ever talk to this context.

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<Product> Products => Set<Product>();
}

REST API with Swagger: The CRUD Endpoints

Now the endpoints. Each one accepts a DTO from the body or route, works with the DbContext, and returns a typed result. The POST handler shows the pattern — create the entity, persist it, and respond with 201 Created plus the resource location.

app.MapPost("/api/products", async (ProductDto dto, AppDbContext db,
    CancellationToken ct) =>
{
    var product = new Product
    {
        Id = Guid.NewGuid(),
        Name = dto.Name,
        Price = dto.Price,
        Stock = dto.Stock,
        CreatedAt = DateTimeOffset.UtcNow
    };

    db.Products.Add(product);
    await db.SaveChangesAsync(ct);

    return Results.Created($"/api/products/{product.Id}", product);
});

The remaining endpoints follow the same shape: GET lists products with optional pagination, GET by id returns one or 404, PUT updates an existing row, and DELETE removes it. Swashbuckle documents all of them automatically — the DTOs become schemas and the endpoints appear under the Products tag in Swagger UI.

REST API with Swagger: Wiring It All Together

Registration happens in Program.cs. The DbContext, the API explorer, and SwaggerGen are registered in that order, and the Swagger middleware is enabled before the endpoints. XML comments are included from the build output so the Swagger UI shows your documentation.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo { Title = "Product API", Version = "v1" });
    options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Api.xml"));
});

var app = builder.Build();

app.UseSwagger();
app.UseSwaggerUI(options =>
    options.SwaggerEndpoint("/swagger/v1/swagger.json", "Product API v1"));

app.MapPost("/api/products", CreateProduct);

app.Run();

Generate the initial migration from the command line, then apply it to the database:

dotnet ef migrations add InitialCreate
dotnet ef database update

Run the application and open the Swagger UI at /swagger. You can create a product, list the table, fetch a single row, and delete it — every action executed against the real database and documented in real time. That is the payoff of a REST API with Swagger and EF Core 10: the database schema and the API contract evolve together.

REST API with Swagger: Why This Pattern Scales

The pattern shown here is deliberately small, but it is the same shape Indotalent uses in production. Wrap the data access in a feature folder, add validation, and version the endpoints as the schema evolves — the Swagger configuration does not change, only the documents it describes.

Two small upgrades turn this tutorial into something you would ship. First, validate the DTO in the endpoint — either with the built-in validation pipeline or a simple guard that returns a 400 with ProblemDetails when a price is negative. Second, apply pagination to the list endpoint with take and skip parameters; Swashbuckle picks up the query parameters automatically and documents them in the Swagger UI, so consumers know exactly which filters the endpoint supports before they write a single call.

  • Keep entities plain and let EF Core conventions map them to tables
  • Return DTOs, not entities, so the OpenAPI schema stays stable
  • Use Results.Created, Results.Ok, and Results.NotFound for accurate response schemas
  • Store the connection string in configuration and register the DbContext once
  • Run migrations as part of deployment so schema and contract move together

Key Takeaways

  • EF Core 10 maps entities to tables and handles all SQL generation
  • Minimal API endpoints keep each CRUD operation readable in a single file
  • Results.Created, Results.Ok, and Results.NotFound give Swagger UI accurate response schemas
  • Migrations keep the database and the OpenAPI contract moving together
  • Every Indotalent product exposes a REST API with Swagger and EF Core 10 — $21 each

FAQ

Do I need controllers for EF Core with Swagger?
No. Minimal APIs and a DbContext cover CRUD with less boilerplate, and Swashbuckle documents them just as completely.

How does Swagger know the response schema of a minimal API endpoint?
Swashbuckle inspects the return type of the endpoint and the DTOs it references; Results.Ok and Results.Created carry the schema through into the OpenAPI document.

Which database should I use with EF Core 10?
SQL Server and SQLite are the most common starting points; every Indotalent product uses SQL Server with EF Core 10 migrations.

Should the API DTOs be the same as the EF Core entities?
No. Return DTOs that match the API contract, not the full entity, so the Swagger schema stays stable when your table changes.

Ready to build a REST API with Swagger and EF Core 10?

Every Indotalent product exposes a complete REST API documented with Swagger. Complete .NET 10 source code — $21 each.

Explore Products