-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started with Basic
This guide helps you build your first REST API using the Atc.Rest.Api.SourceGenerator. You'll go from OpenAPI specification to a working API in minutes!
Before you begin, ensure you have:
- ✅ .NET 10 SDK installed (download)
- ✅ An IDE (Visual Studio 2026, VS Code, or Rider)
- ✅ Basic familiarity with C# and ASP.NET Core
Some features require additional ATC packages:
| Package | Required For | Install |
|---|---|---|
Atc |
String utilities, extensions | dotnet add package Atc |
Atc.Rest.Client |
EndpointPerOperation client mode |
dotnet add package Atc.Rest.Client |
<!-- Add to .csproj if using EndpointPerOperation mode -->
<ItemGroup>
<PackageReference Include="Atc" Version="3.*" />
<PackageReference Include="Atc.Rest.Client" Version="2.*" />
</ItemGroup>💡 Note: The
TypedClientmode (default) does not require these packages. Only add them if usingEndpointPerOperationgeneration mode.
By the end of this guide, you'll have:
- 📝 An OpenAPI YAML file defining your API
- 🌐 A working ASP.NET Core minimal API
- ⚙️ Auto-generated code for models, endpoints, handlers, and more
- 📁 A complete project structure you can extend
Choose the setup that fits your needs:
Best for: Small APIs, prototypes, learning
MyApi/
├── MyApi.yaml # OpenAPI specification
├── MyApi.Api/ # Everything in one project
│ ├── MyApi.Api.csproj
│ ├── Program.cs
│ ├── .atc-rest-api-server-contracts
│ └── Handlers/ # Your handler implementationsBest for: Production APIs, larger teams, clean architecture
MyApi/
├── MyApi.yaml # OpenAPI specification
├── MyApi.Api/ # ASP.NET Core host
│ ├── MyApi.Api.csproj
│ └── Program.cs
├── MyApi.Api.Contracts/ # Generated contracts
│ ├── MyApi.Api.Contracts.csproj
│ ├── .atc-rest-api-server-contracts
│ └── (generated code appears here)
├── MyApi.Api.Domain/ # Your business logic
│ ├── MyApi.Api.Domain.csproj
│ ├── .atc-rest-api-server-handlers
│ └── Handlers/ # Handler implementations
└── MyApi.ClientApp/ # Optional HTTP client
├── MyApi.ClientApp.csproj
└── .atc-rest-api-client-contractsCreate a file named PetStore.yaml in your solution root:
# PetStore.yaml - Your API contract
openapi: 3.0.3
info:
title: Pet Store API
version: 1.0.0
description: A simple pet store API
paths:
/pets:
get:
operationId: listPets # Used for handler naming
summary: List all pets
parameters:
- name: limit
in: query
schema:
type: integer
maximum: 100
responses:
'200':
description: A list of pets
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
post:
operationId: createPet
summary: Create a new pet
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
responses:
'201':
description: Pet created
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
/pets/{petId}:
get:
operationId: getPetById
summary: Get a pet by ID
parameters:
- name: petId
in: path
required: true
schema:
type: integer
format: int64
responses:
'200':
description: A single pet
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
'404':
description: Pet not found
components:
schemas:
Pet:
title: Pet # Required for strict mode
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
minLength: 1
maxLength: 100
tag:
type: string💡 Tip: The
operationIdbecomes your handler interface name.listPets->IListPetsHandler
# Create solution and project
dotnet new sln -n PetStore
dotnet new web -n PetStore.Api
dotnet sln add PetStore.Api
# Add the source generator package
cd PetStore.Api
dotnet add package Atc.Rest.Api.SourceGenerator# Create solution
dotnet new sln -n PetStore
# Create projects
dotnet new web -n PetStore.Api
dotnet new classlib -n PetStore.Api.Contracts
dotnet new classlib -n PetStore.Api.Domain
# Add to solution
dotnet sln add PetStore.Api
dotnet sln add PetStore.Api.Contracts
dotnet sln add PetStore.Api.Domain
# Add project references
dotnet add PetStore.Api reference PetStore.Api.Contracts
dotnet add PetStore.Api reference PetStore.Api.Domain
dotnet add PetStore.Api.Domain reference PetStore.Api.Contracts
# Add the source generator to Contracts and Domain projects
dotnet add PetStore.Api.Contracts package Atc.Rest.Api.SourceGenerator
dotnet add PetStore.Api.Domain package Atc.Rest.Api.SourceGeneratorEdit PetStore.Api.Contracts.csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Make generated code visible for debugging -->
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Atc.Rest.Api.SourceGenerator" Version="*">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<!-- Tell the generator where to find the OpenAPI spec and config -->
<ItemGroup>
<AdditionalFiles Include="..\PetStore.yaml" />
<AdditionalFiles Include=".atc-rest-api-server-contracts" />
</ItemGroup>
</Project>Create the marker file .atc-rest-api-server-contracts in the Contracts project:
{
"generate": true,
"validateSpecificationStrategy": "Standard",
"includeDeprecated": false
}Edit PetStore.Api.Domain.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PetStore.Api.Contracts\PetStore.Api.Contracts.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Atc.Rest.Api.SourceGenerator" Version="*">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\PetStore.yaml" />
<AdditionalFiles Include=".atc-rest-api-server-handlers" />
</ItemGroup>
</Project>Create the marker file .atc-rest-api-server-handlers in the Domain project:
{
"generate": true,
"generateHandlersOutput": "Handlers",
"subFolderStrategy": "FirstPathSegment",
"stubImplementation": "throw-not-implemented"
}dotnet buildAfter building, you'll see generated files in:
-
obj/Generated/Atc.Rest.Api.SourceGenerator/(whenEmitCompilerGeneratedFilesis true)
The source generator creates these files for you:
| File | Description |
|---|---|
PetStore.Pets.Models.g.cs |
📦 C# record types (Pet) |
PetStore.Pets.Parameters.g.cs |
📥 Parameter DTOs with [FromQuery], [FromRoute]
|
PetStore.Pets.Results.g.cs |
📤 Result classes with factory methods |
PetStore.Pets.Handlers.g.cs |
🎯 Handler interfaces (IListPetsHandler, etc.) |
PetStore.Pets.Endpoints.g.cs |
🛣️ Minimal API endpoint registrations |
PetStore.DependencyInjection.g.cs |
💉 DI extension methods |
Create Handlers/Pets/ListPetsHandler.cs in the Domain project:
using PetStore.Generated.Pets.Handlers;
using PetStore.Generated.Pets.Parameters;
using PetStore.Generated.Pets.Results;
using PetStore.Generated.Pets.Models;
namespace PetStore.Api.Domain.Handlers.Pets;
public sealed class ListPetsHandler : IListPetsHandler
{
// Inject your dependencies
private readonly IPetRepository repository;
public ListPetsHandler(IPetRepository repository)
{
this.repository = repository;
}
public async Task<ListPetsResult> ExecuteAsync(
ListPetsParameters parameters,
CancellationToken cancellationToken = default)
{
// Your business logic here
var pets = await repository.GetAllAsync(parameters.Limit, cancellationToken);
// Return using the generated result factory
return ListPetsResult.Ok(pets);
}
}Create Handlers/Pets/GetPetByIdHandler.cs:
public sealed class GetPetByIdHandler : IGetPetByIdHandler
{
private readonly IPetRepository repository;
public GetPetByIdHandler(IPetRepository repository)
{
this.repository = repository;
}
public async Task<GetPetByIdResult> ExecuteAsync(
GetPetByIdParameters parameters,
CancellationToken cancellationToken = default)
{
var pet = await repository.GetByIdAsync(parameters.PetId, cancellationToken);
if (pet is null)
{
return GetPetByIdResult.NotFound(); // ❌ Returns 404
}
return GetPetByIdResult.Ok(pet); // ✅ Returns 200 with pet
}
}Edit PetStore.Api/Program.cs:
using PetStore.Api.Domain;
using PetStore.Generated;
var builder = WebApplication.CreateBuilder(args);
// Add OpenAPI/Swagger support
builder.Services.AddOpenApi();
// Register all handler implementations from Domain project
builder.Services.AddApiHandlersFromDomain();
// Register your own services
builder.Services.AddSingleton<IPetRepository, InMemoryPetRepository>();
var app = builder.Build();
// Enable Swagger UI for development
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
app.UseSwaggerUI(options => options.SwaggerEndpoint("/openapi/v1.json", "PetStore API"));
}
// Map all generated endpoints with single call
app.MapApiEndpoints();
app.Run();cd PetStore.Api
dotnet runVisit:
- 📖
https://localhost:5001/swagger- Swagger UI - 🐾
https://localhost:5001/pets- List pets endpoint
- Ensure marker files are in
AdditionalFiles:
<AdditionalFiles Include=".atc-rest-api-server-contracts" />-
Check the marker file has valid JSON
-
Enable
EmitCompilerGeneratedFilesto see generated files:
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>- Look in
obj/Generated/folder after building
-
Ensure project references are correct:
- Api -> Contracts
- Api -> Domain
- Domain -> Contracts
-
The Contracts project needs
Microsoft.NET.Sdk.WebSDK for ASP.NET Core types
- Ensure
AddApiHandlersFromDomain()is called in Program.cs - Check your handler implements the interface correctly
- Verify handler class is
publicand notabstract
- 📝 Working with OpenAPI - Learn YAML patterns and what gets generated
- ✅ Working with Validations - DataAnnotations and FluentValidation
- 🔢 Working with Versioning - Configure API versioning
- 🎪 Showcase Demo - Run the comprehensive demo with Blazor UI
- 🗺️ Roadmap - See what features are planned
| Marker File | Purpose | Project |
|---|---|---|
.atc-rest-api-server-contracts |
Server code (models, endpoints) | Contracts |
.atc-rest-api-server-handlers |
Handler scaffolds | Domain |
.atc-rest-api-client-contracts |
HTTP client | Client apps |
💡 Tip: You can customize project names and namespaces using options in marker-files.
| Extension Method | Purpose |
|---|---|
AddApiHandlersFromDomain() |
Register all handler implementations |
MapApiEndpoints() |
Map all generated endpoints |
AddPetStoreEndpoints() |
Register client endpoint DI (EndpointPerOperation mode) |