28 grudnia 2021

Wprowadzenie do Rest API z wykorzystaniem Laravel

Niniejszy tekst jest wprowadzeniem do wykonania API, przy pomocy frameworka Laravel, czyli typowej aplikacji backendowej. Charakterystyką tego typu aplikacji, jest operacja na danych, z pominięciem ich prezentacji.

API może posłużyć jako jeden z elementów większej struktury programów komputerowych, może również posłużyć jako warstwa backendowa Twojej aplikacji internetowej lub mobilnej. Elementy sieciowe gier komputerowej również bazują na API, a to ciągle tylko część zastosowań.

Dlaczego Laravel?

Laravel jest według wielu zestawień najpopularniejszym frameworkiem php (czasem pojawia się na drugim miejscu). Popularność wspomnianego frameworka, nie jest wynikiem przypadku.

Próg wejścia do pracy w Laravel, jest zdecydowanie niski, o czym przekonasz się za chwilę, ja natomiast udowodnię jednocześnie, że wykorzystanie go do napisania REST API, jest bardzo przyjemne.

Rest API

Zapewne wiesz, że api mogą być różne, a raczej różne ich rodzaje, ja opiszę natomiast REST API w Laravel.

Co oznacza „REST”?

Pomijając definicję, to API zgodne z kilkoma ogólnie przyjętymi zasadami. Pomińmy w tej chwili teorię, o zasadach wspomnę w dalszej części tekstu.

Czego potrzebujesz?

  • Edytora kodu IDE – ja używam PHP Storm, jeśli natomiast jesteś na początku swej drogi, wybór płatnych aplikacji może okazać się zbędnym wydatkiem. Alternatywą jest tutaj Visual Studio Code, darmowy świetny program, posiadający całą masę wtyczek, dzięki którym możesz dostosować go do własnych potrzeb.
  • Klienta bazy danych MySQL –  wybierając IDE PHP Storm, nie będziesz potrzebować dodatkowego klienta bazy danych. Jeśli jednak, uznasz że wbudowany klient w powyższym IDE to za mało lub po prostu korzystasz z innego edytora kodu, polecam zainstalować klienta baz danych DBeaver.
  • Serwera – to niezbędne narzędzie. PHP musi zostać gdzieś odpalony. Baza danych musi również zostać uruchomiona oraz serwer www (przykładowo Nginx lub Apatche). Nie ważne, jak bardzo brzmi to skomplikowanie na początku, istnieją rozwiązania kompleksowe.

Jedną z możliwości, jest wykup serwera, rozwiązanie to daje korzyść w postaci prostej publikacji naszej pracy.

Możesz również zainteresować się skorzystaniem z Dockera, nie jest to najprostsza metoda „na początek”, ale dająca najwięcej możliwości.

Rozwiązaniem najprostszym jest skorzystanie z jednego z programu Xampp lub Wamp, oba programy są bardzo podobne i umożliwiają postawienie serwera niemalże jednym kliknięciem myszki.

Zaczynamy

Po czystej instalacji frameworka i odpaleniu serwera, możemy wywołać odpowiedni adres w przeglądarce i zobaczyć logo Laravel wraz z kilkoma linkami, w tym do dokumentacji.

Ciebie natomiast nie interesuje strona WWW, a API – chcesz bowiem pominąć całą warstwę wizualną tego programu.

Spróbuj zatem odpalić adres zgodny z poniższym wzorem:

„http://127.0.0.1:{port}/api"

Otrzymamy najpewniej kod błędu „404”.

Nie masz bowiem takiego adresu zdefiniowanego w Laravel, w takim razie… zdefiniuj go.

Wszystkie adresy definiujemy w tzw Rutingu (ang. Routing).

Krok 1: Ruting

Domyślnie, po wykonaniu czystej instalacji omawianego frameworka, masz wykonanych kilka plików odpowiadających za adresy Twojej aplikacji.

Wśród plików znajdziesz konfigurację adresów dla aplikacji WWW, konsoli, kanału nasłuchiwania oraz API.

Zapewne domyślasz się, że Ciebie w obecnej sytuacji interesuje ostatni plik nazwany „api.php”.

Dopisz do wspomnianego pliku kod:

Route::get('/', function () {
     return 'API';
});

Oznacza on, że każde wywołanie naszej aplikacji metodą http:get i adresem wywołania równym „/„ wywoła funkcję która zwróci ciąg znaków „API”.

Pamiętaj, aby odwołać się do adresów znajdujących się w pliku „api.php” należy po domenie i podaniu portu dopisać „api”. Czyli Twoja funkcja zostanie wywołana gdy wyślesz request metodą „get” na adres:

„http://127.0.0.1:{port}/api"

W celu wykonania testów, polecam program „postman”.

To moment w którym można się zastanowić, co umożliwi wykonywane przez Ciebie API, bowiem na tej podstawie wykonać należy adresy.

Proponuję, abyś zostawił swój adres główny, który zwraca string „api”, w późniejszym etapie dodasz do niego wersję programu.

W ramach poradnika, przyjmij, że tworzone przez Ciebie API to baza filmów. Jak to zwykle z api bywa, korzystając z tworzonej aplikacji, będziesz mieć możliwość przeglądać bazę filmów, dodawać nowe, usuwać oraz je edytować.

Krok 2: Metody http

Wspomniałem wcześniej o zasadach jakimi rządzi się Rest API, to odpowiedni moment aby wspomnieć o jednej z nich, mianowicie o metodach Http.

Metod http jest sporo,ale do wykonania api potrzebujesz tylko czterech:

GET: tą metodą będziesz pobierać zasób

POST: ta metoda służy do wysłania nowych zasobów

PATCH: umożliwia edycję istniejących zasobów

DELETE: powoduje usunięcie zasobu

Ponadto, często można się spotkać w Rest API z metodami:

PUT: wysyła dane, api zaś decyduje czy tworzy nowy zasób danych, czy modyfikuj istniejący (decyzja jest podejmowana na podstawie tego, czy dany zasób już istnieje).

Deklarując adresy w Laravel, programista jest zmuszony również do wybrania odpowiedniej metody Http, zapis wygląda następująco

„Route::{metoda_http}(‚{adres}’, {funkcja});”

Wracając do bazy filmów, na podstawie przyjętej tematyki, adresy powinny wyglądać tak:

Route::get('/movies', function(){
    return 'wyświetlam listę filmów';
});

Route::get('/movies/{id}', function(int $id){
    return 'wyświetlam pojedynczy wpis o id: ' . $id;
})->where('id', '[0-9]+');

Route::post('/movies', function(){
    return 'dodaje film';
});

Route::patch('/movies/{id}', function(int $id){
    return 'edytuje film o id: ' . $id;
})->where('id', '[0-9]+');

Route::delete('/movies/{id}', function(int $id){
    return 'usuwam film o id: ' . $id;
})->where('id', '[0-9]+');

});

Jak widać, mamy kilka adresów które odpowiadają kolejno za:

  • Wyświetlenie listy filmów
  • Wyświetlanie pojedynczego wpisu
  • Dodanie nowego rekordu do bazy (film)
  • Edytowanie istniejącego filmu
  • Usuwanie podanego film

Oczywiście dodanie powyższych linii kodu do pliku „api.php” nie spowoduje, że wszystko zacznie magicznie działać. Wywołanie powyższych adresów, spowoduje wyświetlenie tekstu, który zwracany jest przez powyższe funkcje.

Zwróć uwagę, że trzy z powyższych adresów, pobierają parametr id, mowa o metodzie „get”, „patch” oraz „delete”. Laravel umożliwia już na tym etapie wstępną walidację przekazywanych danych, parametr get w powyższym przykładzie musi być liczbą.

Aby całość nabrała kształtu, potrzebujesz bazy danych, w której będziesz przechowywać swoją bazę filmów.

Krok 3: Baza danych

Dostęp do bazy danych zapisujesz w zmiennych środowiskowych: 

Oczywiście zaczynasz od podmiany powyższych wartości na prawidłowe, zależne od tego, pod którym hostem, na jakim użytkowniku i pod jakim hasłem możesz połączyć się ze swoją bazą danych.

Kolejnym krokiem będzie usunięcie zbędnych nam w tej chwili migracji, a znajdują się one w katalogu: „/database/migrations”.

Proponuję na potrzeby tego poradnika, usunąć z podanego katalogu wszystkie dostępne migracje.

Następnie w katalogu głównym naszej aplikacji, wykonaj polecenie:

„php artisan make:migration CreateMoviesTable”

Powyższe polecenie stworzy nową migrację, odpal zatem nowo powstały plik i dokonaj w nim poniżej opisanych modyfikacji.

Klasa „CreateMoviesTable” która znajduje się w wygenerowanym powyższym poleceniem pliku, posiada dwie funkcje „up” oraz „down”.

Funkcja „up” zostaje wywołana w momencie tworzenia migracji.

Funkcja „down” zostaje wywołana w momencie cofania migracji, przykładowo w sytuacji gdy chcemy powrócić do poprzedniej wersji naszej aplikacji.

W funkcji „up” należy zapisać konfigurację tabeli w bazie danych, jaką chcesz wykonać.

Tabela Movies na pewno powinna zawierać takie elementy jak numer id, data produkcji, opis, tytuł i przykładowo ocenę filmu. Przyda się również kolumna zapisująca datę utworzenia oraz modyfikacji wpisu.

Aktualnie Twoja funkcja „up” wygląda następująco:

public function up()
{
    Schema::create('movies', function (Blueprint $table) {
        $table->id();
        $table->timestamps();
    });
}

Jeśli pozostawisz skrypt bez zmian, stworzona tabela będzie posiadała kolumnę „id” jako klucz podstawowy oraz kolumny z datą utworzenia oraz modyfikacji.

Dopisz zatem kolejne kolumny do powyższej funkcji, jej finalna wersja powinna wyglądać następująco:

{
    Schema::create('movies', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->longText('description')->nullable();
        $table->date('release');
        $table->unsignedInteger(‚rating')->nullable();
	  $table->timestamps();
    });
}

Dodane zostały brakujące kolumny, zauważ, że opis filmu nie jest wymagany. Osiągasz to dzięki wywołaniu funkcji „nullable”.

Funkcja „down” nie wymaga od nas zmian, a jej domyślna zawartość prezentuje się następująco: 

public function down()
{
    Schema::dropIfExists('movies');
}

Czas zająć się migracją. A to wymaga od Ciebie przejścia znów do głównego katalogu z aplikacją i wydania dwóch poleceń:

„php artisan migrate:install”

Powyższe polecenie implementuje cały „system” migracji, tworzy repozytorium w naszej bazie danych w postaci tabeli „migrations”. Dzięki zapisie w bazie, jesteś w stanie w prosty sposób „doinstalowywać” kolejne zmiany w bazie danych oraz je cofać.

Drugie polecenie to:

„php artisan migrate”

Powyższe polecenie wywołuje wszystkie funkcje „up” z Twoich plików wewnątrz katalogu „migrations”, które to jeszcze wywołane nie zostały. Skąd Laravel wie, które to pliki? Dzięki wspomnianej wcześniej tabeli „migrations”.

Zachęcam do ręcznego sprawdzenia, czy tabela „movies” została wykonana.

To idealny moment na uzupełnienie tabeli. W tym celu będziesz potrzebować model oraz funkcję zapisu danych.

Krok 4: Model

Do wykonania modelu służy polecenie:

„Php artisan make:model `Movie”

Nowo powstały plik znajdziesz w katalogu „app/Models/„ a jego nazwa będzie zgodna z podaną w poleceniu terminalowym, czyli w tym przypadku „Movie”.

Z modelem pracę na tym etapie się kończą, nie jest konieczne podawanie nazwy tabeli i innych parametrów – są one opcjonalne.

Laravel, odczytując podaną przez nas nazwę modelu, jest w stanie przypisać do niego odpowiednią tabelę w bazie.

Modele zgodnie z przyjętymi zasadami, ładowane powinny być w kontrolerach, zatem to dobry moment na stworzenie go.

Krok 5: Kontroler

Kontroler (ang. Controller), czyli serce programu, choć to sprawa dyskusyjna, ale raczej większość osób zgodzi się ze mną, że to najważniejsze naszego API.

Kontroler możesz stworzyć przy pomocy polecenia:

„php artisan make:controller MovieController”

Nowo powstały plik stworzony został w katalogu „app/Http/Controllers/„ a nazwa pliku, jak pewnie się domyślasz, jest zgodna z parametrem podanym przy wywołaniu polecenia „artisan”.

Kontroler w czystej swej formie jest bezużyteczny. Potrzebujesz wykonać w nim funkcje publiczne oraz wywołania wykonanych funkcji wpisać w rutingu.

Przechodząc do rutingu (odpal plik „app/routes/api.php”), wskaż w nim plik z którego chcesz korzystać:

use App\Http\Controllers\MovieController;

Wpisując powyższą linię na górze pliku (tuż pod linią zaczynającą się od „Namespace”) dajesz znać frameworkowi, że będziesz korzystał z klasy „MovieController”.

Zacznij zatem korzystać.

Znajdź adres, który został zdefiniowany na początku poradnika. Było to  „/movies”, wywołanie tego adresu odpala funkcję, która zwraca string „Wyświetlam listę filmów”.

Nie jest dobrą praktyką, aby adresy API uruchamiały funkcje napisane w tym samym pliku, z czasem może się okazać, że będzie ich zbyt dużo, a programista nie będzie w stanie pracować przy tak chaotycznym kodzie.

Ty nie musisz się o to martwić, bowiem swój kod umieszczasz w odpowiednich do tego klasach 🙂

Dodaj deklarację użycia klasy „MovieController” w górnej części pliku:

use App\Http\Controllers\MovieController;

Usuń zatem wspomnianą funkcję i zmień parametr wywołania funkcji „get” na tablicę, która wskaże odpowiednią klasę i publiczną funkcję w niej umieszczoną.

Brzmi skomplikowanie, a to zaledwie jedna linia:

Route::get('/movies', [MovieController::class, ‚list']);

Przypomnę jeszcze raz: pierwszym parametrem funkcji get jest adres, drugim funkcja, którą należy wywołać po wywołaniu zapisanego adresu. Powyższy przykład ukazuje wskazanie funkcji, która znajduje się wewnątrz klasy „MovieController”. Nie wspomniałem jeszcze, że należy taką funkcję oczywiście zapisać. Poniżej przykład:

public function list(): string
{
    return 'wyświetlamy listę filmów';
}

Wywołując adresu „/movies” nie zauważysz różnicy, bowiem zwracany tekst jest taki sam, jak na początku poradnika, ale tym razem, masz lepiej ułożony kod, bowiem wywoływany jest odpowiedni kontroler. Z czasem użyjesz również modelu do pobrania danych z bazy.

Teraz zachęcam Cię do przepisania wszystkich adresów na wzór „listy filmów”.

Na ten moment, ruting powinien wyglądać tak:

<?php
 
use App\Http\Controllers\MovieController;
use Illuminate\Support\Facades\Route;
 
Route::get('/', function () {
    return 'API';
});
 
Route::get('/movies', [MovieController::class, 'list']);

Route::get('/movies/{id}', [MovieController::class, 'get'])
    ->where('id', '[0-9]+');
 
Route::post('/movies', [MovieController::class, 'add']);
 
Route::patch('/movies/{id}', [MovieController::class, 'edit'])
    ->where('id', '[0-9]+');
 
Route::delete('/movies/{id}', [MovieController::class, 'delete'])
    ->where('id', ‚[0-9]+');

Kontroler prezentuje się natomiast odpowiednio:

<?php
 
namespace App\Http\Controllers;
 
class MovieController extends Controller
{
    public function list(): string
    {
        return 'wyświetlamy listę filmów';
    }
 
    public function get(int $id): string
    {
        return 'wyświetlam pojedynczy wpis o id: ' . $id;
    }
 
    public function add(): string
    {
        return 'dodaje film';
    }

    public function edit(int $id): string
    {
        return 'edytuje film o id: ' . $id;
    }
 
    public function delete(int $id): string
    {
        return 'usuwam film o id: ' . $id;
    }
}

Czas na pracę na realnych danych, nie po to tworzona była migracja bazy, aby teraz nie zrobić z niej użytku.

Krok 6: Dane

Jak wspomniałem, przy użyciu programu „Postman” lub jakiegokolwiek innego, możesz napisać nawet swój frontend w Javascript lub aplikację w Flutter. Możesz wywołać adresy zapisane w Rutingu i otrzymać w odpowiedzi odpowiednie teksty, które to znajdują się w kontrolerze „MovieController”.

Cel do którego dążysz, to nie wyświetlanie tekstu, czyli inaczej mówiąc „stringu”, tylko realnych danych, pobranych z bazy danych.

Na początku poradnika pokazałem Ci jak utworzyć model, jak wykonać odpowiednie tabele w bazie danych. Baza oczywiście jest w tej chwili pusta, ale to nie potrwa długo.

Na tym etapie metody zawarte w „MovieController” zostaną zastąpione realnymi funkcjami dodawania, edycji, usuwania oraz wyświetlania danych z bazy.

Nie ma sensu zaczynać od wyświetlania, bowiem baza jest pusta, zacznijmy więc od dodania pierwszego rekordu.

Funkcja dodawania

Funkcja dodawania nazwana została „add”. Odnajdź ją wewnątrz pliku „MovieController.php”. 

Do interesującej Cię funkcji, dodaj parametr „request”, którego typ to „Request” – jest Ci potrzebny w celu pobrania parametrów „POST” wysłanych, aby móc dodać nowy rekord.

Następnym krokiem jest wykonanie walidacji przesłanych danych. Ważne jest, aby sprawdzać, czy np. Klient API podesłał nam tytuł, opis filmu i resztę potrzebnych Ci informacji.

Na obecnym etapie funkcja prezentuje się następująco:

public function add(Request $request)
{
    $validator = Validator::make($request->all(), [
    'title' => 'required',
     'release' => 'required|date',
     'description' => 'required',
     'rating' => 'numeric'
]);
 
    if ($validator->fails()) {
        return response()->json(
            ['message' => 'Validation Error', 'data' => $validator->errors()],400);
    }
}

Powyżej możesz zobaczyć funkcję „add”. To do niej trafia obiekt „$request” przy pomocy którego, pobrać można wszystkie dane wysłane przez klienta.

Klientem może być nasza aplikacja frontendowa (może być to wspomniany już program „Postman”).

Walidacja wymaga, aby klient podesłał tytuł filmu, datę premiery oraz opis. To trzy wymagane dane. Ponadto ocena musi być w formacie numerycznym.

Jeśli walidacja się nie uda, zwrócisz odpowiednią informację (kod odpowiedzi będzie równy 400). To kolejna zasada REST API, czyli kody odpowiedzi. Na ten moment, najważniejsze jest, aby w sytuacji wysłania błędnych danych, zwrócić kod odpowiedzi HTTP: 400. Dzięki temu aplikacja, która korzysta z API zostanie poinformowana, że zasób nie został dodany do bazy ponieważ przesłane dane są błędne.

W sytuacji poprawnego przejścia walidacji stworzony powinien zostać obiekt klasy modelu „Movie”, wartości odpowiadające nazwom kolumn w bazie powinny wypełnić się wartościami dostępnymi w obiekcie $request, czyli wartościami wysłanymi do API.

Kod nie prezentuje się tak strasznie, jak brzmi opis:

$data = new Movie();
$data->title = $request->input('title');
$data->description = $request->input('description');
$data->release = $request->input('release');
$data->rating = ($request->input('rating')) ? $request->input('rating') : 0;

Po wykonaniu powyższego kodu masz stworzony obiekt z danymi. poniżej wywołać należy funkcję, która zapisze w bazie danych:

$data->save();

Aby Twoja funkcja była kompletna, sprawdź czy dane zapisały się prawidłowo. Jeśli tak, zwróć kod odpowiedzi 201 (jest to zasada REST API) oraz dane, które przed chwilą zostały zapisane. W przeciwnym przypadku kod odpowiedzi 500, który oznacza błąd serwera.

Kompletna funkcja prezentuje się następująco:

public function add(Request $request)
{
    $validator = Validator::make($request->all(), [
        'title' => 'required',
        'release' => 'required|date',
        'description' => 'required',
        'rating' => 'numeric'
    ]);
 
    if ($validator->fails()) {
        return response()->json(
            ['message' => 'Validation Error', 'data' => $validator->errors()],400);
    }
 
    $data = new Movie();
    $data->title = $request->input('title');
    $data->description = $request->input('description');
    $data->release = $request->input('release');
    $data->rating = ($request->input('rating')) ? $request->input('rating') : 0;
 
    if ($data->save()) {
        return response()->json($data, 201)
            ->header('Content-Type', 'text/json')
            ->setEncodingOptions(JSON_NUMERIC_CHECK);
    }
 
    return response()->json('error', 500);
}

Funkcja pobierania wpisów

Funkcja zwracająca rekordy z bazy, nazwana została „list”. Znajduje się oczywiście w kontrolerze.

Wygląda następująco:

public function list(): JsonResponse
{
    $movies = Movie::select();
 
    if ($movies->exists())
        return response()->json($movies->get());
    else
        return response()->json('Not Found', 404);
}

Przy pomocy funkcji statycznej „select” pobierasz wszystkie rekordy z tabeli „movies”.

Następną czynnością jest sprawdzenie, czy pobrane zostały dane z bazy (jeśli tabela będzie pusta, warunek nie zostanie spełniony). Jeśli dane nie pobrały się, zwrócisz HTTP CODE: 404 (to oczywiście zasada REST API). Jeśli natomiast baza zwróci Ci rekordy, wszystkie zostaną zwrócone przez funkcję „list”.

Pobieranie jednego rekordu

Nie zdziwię Ciebie, jeśli powiem, że jest to funkcja „get” przyjmująca jeden parametr, którym jest numer id rekordu. 

Funkcja jest bardzo podobna do tej opisanej wyżej. Różnica pomiędzy jedną a drugą, jest taka, że pobranie jednego rekordu następuje przy pomocy metody „find” zamiast pobrania wszystkich rekordów przy pomocy „select”.

public function get(int $id)
{
    $movies = Movie::find($id);
 
    if ($movies)
        return response()->json($movies);
    else
        return response()->json('Not Found', 404);
}

Usunięcie wpisu

W kontrolerze jest jeszcze kilka funkcji do omówienia. Skoro możesz dodawać nowe wpisy, możesz je również usunąć.

Jedną z funkcji jest „delete” – jako parametr przyjmuje numer id rekordu, który użytkownik chce usunąć.

Funkcja znów jest bardzo podobna do powyższych – pobiera konkretny rekord, sprawdza czy istnieje.

Zgodnie z zasadami REST API, jeśli rekord nie istnieje, zwraca HTTP CODE: 404, w przeciwnym wypadku usuwa rekord (odmiennie od funkcji „get”, która go wyświetla).

public function delete(int $id): JsonResponse
{
    $movie = Movie::find($id);
 
    if (!$movie)
        return response()->json('Not Found', 404);
 
    $movie->delete();
 
    return response()->json('deleted', 204);
}

Edycja

To ostatnia troszkę bardziej złożona metoda w Twoim kontrolerze, ale bez stresu. Połączy ona kilka mechanizmów z funkcji „get” oraz „add”.

Funkcja służąca do edycji rekordu, przyjmuje parametr Request podobnie jak funkcja „add”. Służy on do pobrania wartości wysłanych w body oraz parametr drugi, którym jest numer id edytowanego wpisu.

Omawiana funkcja zaczyna się od walidacji przesłanych danych, jednak będzie to walidacja prostsza, niż w przypadku dodania nowego rekordu, czyli funkcji „add”.

$validator = Validator::make($request->all(), [
    'release' => 'date',
    'rating' => 'numeric']);
 
if ($validator->fails()) {
    return response()->json(
        ['message' => 'Validation Error', 'data' => $validator->errors()], 400);
}

Tak wygląda walidacja w funkcji edytującej rekord. Różnicą, którą widać na pierwszy rzut oka, w stosunku do walidacji w funkcji „add”, jest brak wymaganych danych, a wynika to bezpośrednio z zasad REST API.

Funkcja HTTP Patch służy do edycji zasobów, nie wymaga jednak, aby podać cały zasób, a można edytować jedynie podane wartości.

W praktyce wygląda to następująco: przy dodaniu nowego zasobu, czyli filmu, musimy podać tytuł, opis, ocenę, datę premiery. Przy edycji musisz podać numer identyfikacyjny filmu (id) oraz wartość, którą chcesz zmienić – dla przykładu niech będzie to przykładowo tylko opis.

Nie możesz więc z tego powodu wymagać podanych danych innych, niż numer id.

Skoro wspomniałem o wymaganym parametrze id, jakże inaczej można dokonać edycji, nie wiedząc o którym rekord chodzi. Poniżej pokażę Ci fragment kodu, który sprawdza, czy rekord o podanym numerze id istnieje:

$movie = Movie::find($id);
 
if (!$movie)
    return response()->json('Not Found', 404);

Standardowo, jeśli nie znalazł rekordu, zwróci HTTP CODE: 404

Jeśli natomiast nie zostanie spełniony podany wyżej warunek, sprawdzone zostaną wszystkie spodziewane dane, przypisane do własności obiektu „Movie” oraz zapisane.

Poniżej całościowa funkcja „edit”:

public function edit(Request $request, int $id)
{
    $validator = Validator::make($request->all(), [
        'release' => 'date',
        'rating' => 'numeric']);
 
    if ($validator->fails()) {
        return response()->json(
            ['message' => 'Validation Error', 'data' => $validator->errors()], 400);
    }
 
    $movie = Movie::find($id);
 
    if (!$movie)
        return response()->json('Not Found', 404);
 
    if ($request->input('title'))
        $movie->title = $request->input('title');
 
    if ($request->input('description'))
        $movie->description = $request->input('description');
 
    if ($request->input('release'))
        $movie->release = $request->input('release');
 
    if ($request->input('rating'))
        $movie->rating = $request->input('rating');
 
    $movie->save();
 
    return response()->json($movie);
}

Podsumowanie

Przy pomocy kilku kroków, w prosty sposób udało się stworzyć Twoje restowe API. Prosto i przejrzyście dzięki wykorzystaniu Laravel. Powyższy poradnik pomaga zrozumieć kilka podstawowych zasad REST API oraz wprowadza do wspomnianego już frameworka. Jest jednocześnie doskonałym początkiem budowy większego systemu.

Sugeruję zapoznanie się z dokumentacją, bowiem w kilku powyższych słowach poruszyłem wiele tematów jednak bez zagłębiania się w szczegóły, a wszyscy wiemy co tam tkwi.

Powodzenia z dalszą nauką przy pisaniu rozbudowanych aplikacji backendowych.