-
Notifications
You must be signed in to change notification settings - Fork 1
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, file uploads |
dotnet add package Atc.Rest.Client |
<!-- Add to .csproj if using EndpointPerOperation mode or file uploads -->
<ItemGroup>
<PackageReference Include="Atc" Version="3.*" />
<PackageReference Include="Atc.Rest.Client" Version="2.*" />
</ItemGroup>π‘ Note: The
TypedClientmode (default) does not require these packages unless you're using file uploads (IFileContent). Only add them if usingEndpointPerOperationgeneration mode or working with file upload operations.
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
β βββ 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
β βββ (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-clientCreate 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" />
</ItemGroup>
</Project>Create the marker file .atc-rest-api-server 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" />-
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 Files
| File | Purpose |
|---|---|
.atc-rest-api-server |
Server code (models, endpoints, handlers) |
.atc-rest-api-server-handlers |
Handler implementation scaffolds |
.atc-rest-api-client |
HTTP client generation |
π‘ Tip: You can customize project names and namespaces using options in marker files. See Marker Files for complete configuration reference.
| Extension Method | Purpose |
|---|---|
AddApiHandlersFromDomain() |
Register all handler implementations |
MapApiEndpoints() |
Map all generated endpoints |
AddPetStoreEndpoints() |
Register client endpoint DI (EndpointPerOperation mode) |
π Home
- πΌ FAQ Business Value
- π Getting Started with Basic
- π οΈ Getting Started with CLI
- π Migration Guide
- β¬οΈ Upgrading to v2
- π Working with OpenAPI
- π³οΈ Working with Nullability
- π οΈ Working with CLI
- π How-To Guides
- π Working with Security
- π¦ Working with Rate Limiting
- π Working with Resilience
- ποΈ Working with Caching
- π’ Working with Versioning
- β Working with Validations
- π Working with Webhooks
- βοΈ Working with Aspire
- π£οΈ Working with Endpoint Definitions
- π Working with Multi-Part Specs
- π§ͺ Working with Code Coverage
- π Working with C# Client
- π§ͺ Working with C# Client Testing
- π¦ Working with TypeScript Client
- πͺ Showcase Demo
- π§ͺ Working with E2E Testing
- βοΈ Working with Configuration
- π Marker Files
- π API Reference
- π Analyzer Rules
- β FAQ and Troubleshooting
- πΊοΈ Roadmap
- π§ Development Notes
- π¦ GitHub Repository
- π₯ NuGet Package
- π Report Issues