Przejdź do treści
AI pisze kod szybko - ale czy Twoje API zwraca tylko to, co potrzebne?
· 3 min czytania

AI pisze kod szybko - ale czy Twoje API zwraca tylko to, co potrzebne?

AI API C# Clean Code Best Practices

AI pisze kod szybko. Czasem aż za szybko - i endpointy zaczynają zwracać więcej, niż frontend potrzebuje.

W defaultowym setupie modele lubią zwrócić cały obiekt lub całe kolekcje. Nie mówimy dokładnie czego i jak potrzebujemy - im więcej ogólników, tym większe pole do interpretacji.

Najczęściej AI:

  • Nie robi DTO
  • Nie filtruje danych
  • Nie sprawdza, co faktycznie powinno iść na zewnątrz

To nie błąd - tak po prostu działają modele, które mają pełną dowolność w działaniu. Ogólny prompt = ogólny feature.

Problem: over-fetching generowany przez AI

W kilku projektach widziałem ten sam schemat:

// AI wygenerowało taki endpoint:
[HttpGet("{id}")]
public async Task<User> GetUser(int id)
{
return await _context.Users.FindAsync(id);
// Zwraca CAŁY obiekt User ze wszystkimi polami:
// Id, Name, Email, PasswordHash, CreatedAt, UpdatedAt,
// InternalNotes, Role, LastLoginIp, FailedLoginAttempts...
}

Endpoint zwraca 10-20 pól, choć interfejs korzysta z 5. Endpoint zwraca całą kolekcję, a frontend potrzebuje tylko listy nazw i ich ilości.

Efekt? Bałagan, trudniejsze utrzymanie i dodatkowa praca przy każdym refaktorze.

Dlaczego to problem?

Każde dodatkowe pole to:

  • Większa odpowiedź - więcej transferu, wolniejszy frontend
  • Niepotrzebna ekspozycja szczegółów implementacji - PasswordHash, InternalNotes czy LastLoginIp nie mają prawa opuścić serwera
  • Kruche API - zmiana wewnętrznego modelu łamie kontrakt z frontendem
  • Trudniejsze testowanie - więcej pól = więcej edge case’ów

Nie chodzi o dramatyczne ryzyka bezpieczeństwa. Chodzi o higienę: API powinno zwracać tylko to, co jest potrzebne do działania UI.

Rozwiązanie: małe, celowe DTO

// DTO - tylko pola potrzebne frontendowi
public record UserProfileDto(int Id, string Name, string Email);
// Endpoint zwraca dokładnie to, czego UI potrzebuje
[HttpGet("{id}")]
public async Task<UserProfileDto> GetUser(int id)
{
return await _context.Users
.Where(u => u.Id == id)
.Select(u => new UserProfileDto(u.Id, u.Name, u.Email))
.FirstOrDefaultAsync();
}

Dla list - analogicznie:

// Zamiast zwracać całą kolekcję obiektów:
public record ProductListDto(int TotalCount, List<string> Names);
[HttpGet]
public async Task<ProductListDto> GetProducts(int categoryId)
{
var query = _context.Products
.Where(p => p.CategoryId == categoryId);
return new ProductListDto(
TotalCount: await query.CountAsync(),
Names: await query.Select(p => p.Name).ToListAsync()
);
}

Reguła, którą dodaję do kontekstu AI

Poza code review przydaje mi się prosta reguła, którą wrzucam jako instrukcję dla agenta:

Przy pobieraniu i wyświetlaniu danych używaj minimalnej liczby pól.
Między bazą a klientem stosuj małe DTO.
Zawsze sprawdzaj, czy odpowiedź nie ujawnia więcej, niż potrzebuje UI.

To naprawdę wystarczy. Wrzucam to do .github/copilot-instructions.md lub do pliku CLAUDE.md i agent zaczyna generować kod z DTO od początku, zamiast wymagać poprawek po fakcie.

Praktyczne zasady

  1. Jeden endpoint = jedno DTO - nie reużywaj tego samego DTO do różnych widoków, jeśli potrzebują różnych pól
  2. Nigdy nie zwracaj encji bazodanowej bezpośrednio z API - zawsze mapuj na DTO
  3. Nazywaj DTO po przeznaczeniu: UserProfileDto, ProductListItemDto, OrderSummaryDto
  4. Używaj record w C# - immutable, zwięzłe, idealne do DTO
  5. Projekcja w LINQ (.Select()) zamiast .ToList() + mapowanie - to nie tylko czystsze, ale i szybsze (EF generuje SELECT tylko po potrzebne kolumny)

Efekt

API jest lżejsze, czystsze i łatwiejsze do rozwijania. Front jest szybszy i bezpieczniejszy. A Ty masz mniej pracy przy każdym kolejnym refaktorze.

Czy AI generuje zbyt „bogate” odpowiedzi w Twoich projektach, czy masz już proces, który to trzyma w ryzach?

Udostępnij X / Twitter LinkedIn
🤖

Chcesz opanować GitHub Copilot od podstaw?

Kurs GitHub Copilot - 5 poziomów, 15 modułów, od instalacji do własnych agentów. Pisany przez człowieka, weryfikowany z oficjalną dokumentacją VS Code.

Sprawdź kurs