Przejdź do treści stopki
Iron Academy Logo
Naucz się C#
Naucz się C#

Inne Kategorie

Dodanie punktu końcowego PUT Update w .NET Aspire na Linuxie

[[academy-video-youtube({"vid": "hSRI_JKiH5M", "start_time": "0", "title": "Adding a PUT Update Endpoint in .NET Aspire on Linux", "creator": "Tim Corey", "length": "8m 43s"})]]

Gdy API może czytać i tworzyć rekordy, następną operacją jest aktualizacja istniejących. Punkt końcowy PUT zastępuje cały zasób danymi dostarczonymi przez osobę wywołującą, co oznacza, że ciało żądania potrzebuje każdego pola, a nie tylko tych, które się zmieniły. To rozróżnienie między PUT (pełne zastąpienie) a PATCH (częściowa modyfikacja) jest ważne dla tego, jak projektujesz typ wejściowy i jak osoby wywołujące współdziałają z punktem końcowym.

W swoim wideo "Dodawanie punktu końcowego PUT Update w .NET Aspire na Linux", Tim Corey dodaje punkt aktualizacji do Tiny Ticket API, tworzy dedykowany typ rekordu aktualizacji, który zawiera pola, których nie miał rekord wstawiania (takie jak ID i data zakończenia), stosuje atrybuty walidacji i testuje całkowity przebieg przez Swagger. Odcinek podąża za tym samym schematem, jak ustalono w poprzednich częściach, ale wprowadza opcjonalne pole DateTime i różnicę między semantyką PUT a PATCH. Jeśli budujesz punkty końcowe CRUD w minimalnym API, ten artykuł obejmuje stronę aktualizacji.

Tworzenie typu rekordu aktualizacji

[1:54 - 4:04] Rekord wstawiania z poprzedniego odcinka akceptował tytuł, opis i priorytet. Rekord aktualizacji wymaga dwóch dodatkowych pól: ID biletu modyfikowanego i znacznika czasu DateCompleted. Tim kopiuje rekord wstawiania i dostosowuje go.

public record TicketUpdateRecord(
    [Required, Range(1, int.MaxValue)] int Id,
    [Required, MinLength(1)] string Title,
    [Required] string Description,
    DateTime? DateCompleted,
    [Range(1, 5)] int Priority
);
public record TicketUpdateRecord(
    [Required, Range(1, int.MaxValue)] int Id,
    [Required, MinLength(1)] string Title,
    [Required] string Description,
    DateTime? DateCompleted,
    [Range(1, 5)] int Priority
);

Oznaczenie Id jako [Required] z ograniczeniem [Range(1, int.MaxValue)] zapobiega, by wartości ujemne lub zero trafiały do bazy danych. DateCompleted jest zoptymalizowane jako optionalne DateTime?, ponieważ bilet, który nie został jeszcze rozwiązany, nie powinien wymagać daty zakończenia. Na nim nie jest potrzebny żaden atrybut walidacji, ponieważ nazwa NULL jest prawidłowym stanem.

Aby zapewnić dokładne dopasowanie właściwości rekordu, Tim pobiera listę pól z procedury składowanej spTickets_Update. To wyrównanie pozwala Dapper mapować rekord bez żadnego ręcznego przypisywania właściwości do parametrów.

Mapowanie punktu końcowego PUT

[4:04 - 5:44] Rejestracja punktu końcowego podąża za ustalonym wzorcem. MapPut wiąże się z trasą /api/tickets, a obsługujący wywołuje procedurę składowaną z rekordem aktualizacji:

app.MapPut("/api/tickets", async Task<Results<NoContent, ValidationProblem>>
    (TicketUpdateRecord ticket, ISqlDataAccess sql) =>
{
    await sql.SaveDataAsync("dbo.spTickets_Update", ticket, "TicketDB");
    return TypedResults.NoContent();
});
app.MapPut("/api/tickets", async Task<Results<NoContent, ValidationProblem>>
    (TicketUpdateRecord ticket, ISqlDataAccess sql) =>
{
    await sql.SaveDataAsync("dbo.spTickets_Update", ticket, "TicketDB");
    return TypedResults.NoContent();
});

Deklarowanie Results<NoContent, ValidationProblem> jako typu zwracanego mówi frameworkowi, że punkt końcowy zwraca 204 w przypadku sukcesu lub 400, jeśli walidacja nie powiodła się. Wariant ValidationProblem jest automatycznie obsługiwany przez pipeline zarejestrowany w poprzednim odcinku; sam obsługujący tylko musi zwrócić przypadek sukcesu.

Warto zauważyć, jak opakowanie Dapper utrzymuje dostęp do danych w sposób zwięzły: nazwa procedury, model, nazwa łańcucha połączenia. Trzy parametry pokrywają całe wywołanie do bazy danych. Opakowanie zostało napisane wcześniej w serii i nadal się opłaca, ponieważ każdy nowy punkt końcowy z niego korzysta bez zmian.

PUT vs. PATCH: Kiedy pełna zamiana ma znaczenie

[6:06 - 6:46] Przed testowaniem, Tim zatrzymuje się, aby wyjaśnić różnicę między PUT i PATCH. Żądanie PUT zastępuje cały zasób: każde pole w treści żądania nadpisuje odpowiadającą kolumnę bazy danych, nawet jeśli dzwoniący nie zamierzał go zmieniać. Żądanie PATCH aktualizuje tylko pola zawarte w treści.

W projekcie Tiny Ticket, PUT jest właściwym wyborem, ponieważ frontend załaduje pełny bilet, pozwoli użytkownikowi edytować pola i odeśle kompletny obiekt. W aplikacji produkcyjnej, Tim wspomina, że prawdopodobnie dodałby punkt końcowy PATCH specjalnie do popularnych operacji na jednym polu, takich jak oznaczenie biletu jako zakończony, gdzie wysyłanie całego obiektu tylko po to, aby zmienić jedną datę wydaje się marnotrawstwem.

Testowanie aktualizacji przez Swagger

[6:46 - 8:26] Tim launches the API and opens Swagger. Przed testowaniem PUT, uruchamia punkt końcowy GET all, aby sprawdzić obecny stan danych. Jeden z rekordów testowych (ID 109) ma puste wartości dla tytułu, opisu i priorytetu z wcześniejszych testów. To staje się celem aktualizacji.

Wypełnia ciało żądania PUT z ID 109, tytułem "Przykładowy rekord", opisem i priorytetem 5. Po wykonaniu, odpowiedź wraca jako 204. Ponowne uruchomienie GET all potwierdza, że rekord ma teraz zaktualizowane wartości.

Aby zweryfikować walidację, usuwa pole tytułu i wykonuje ponownie. Odpowiedź zwraca 400 ze strukturyzowaną wiadomością o błędzie: "Pole tytułu biletu jest wymagane." Te same atrybuty walidacji z punktu końcowego wstawiania odnoszą się do aktulizacji rekordu, ponieważ używają tego samego wzorca adnotacji.

Podsumowanie: Postęp CRUD

[8:26 - 8:43] Po zakończeniu endpointu PUT, Tiny Ticket API pokrywa teraz trzy z czterech operacji CRUD: odczyt (GET all i GET by ID), tworzenie (POST) i aktualizację (PUT). Każdy endpoint stosuje ten sam wzór strukturalny, co sprawia, że kod jest przewidywalny. Pozostała operacja to DELETE, którą Tim zapowiada jako kolejny odcinek.

Wnioski

[8:38 - 8:43] Dodanie punktu końcowego PUT do minimalnego API wymaga dedykowanego rekordu aktualizacji z atrybutami walidacyjnymi, rejestracji MapPut z URL-em kolekcji oraz wywołania procedury składowanej przez wrapper dostępu do danych. Return type Results<NoContent, ValidationProblem> pozwala frameworkowi obsługiwać zarówno odpowiedzi sukcesu, jak i niepowodzenia walidacji. Pola opcjonalne, jak DateTime?, przechodzą bez potrzeby atrybutu walidacji, ponieważ null jest prawidłową wartością dla niekompletnych danych.

Nawigacja w serii: Ten artykuł jest częścią serii C# na Linuxie, budującej aplikację Tiny Ticket. Poprzedni: Dodawanie Endpointu POST Insert. Następny: Dodawanie Endpointu DELETE.

Porada przykład: Jeśli twoja procedura przechowywana zwracająca aktualizację zwraca zmodyfikowaną liczbę wierszy, sprawdź ją przed zwróceniem 204. Wartość zero oznacza, że ID nie pasuje do żadnego rekordu i należy zwrócić 404 zamiast ciszej kończyć operację.

Obejrzyj pełne wideo na jego YouTube Kanale i zdobądź więcej informacji o budowaniu endpointów CRUD w serii C# na Linuxie.

Hero Worlddot related to Dodanie punktu końcowego PUT Update w .NET Aspire na Linuxie
Hero Affiliate related to Dodanie punktu końcowego PUT Update w .NET Aspire na Linuxie

Zarabiaj więcej, dzieląc się tym, co kochasz

Tworzysz treści dla deweloperów pracujących z .NET, C#, Java, Python, czy Node.js? Zamień swoją wiedzę specjalistyczną na dodatkowy dochód!

Zespół wsparcia Iron

Jesteśmy online 24 godziny, 5 dni w tygodniu.
Czat
E-mail
Zadzwoń do mnie