Aplikacje internetowe 1 (AI1) – laboratorium nr 11
Laravel, REST API –
realizacja kontrolera CRUD (cz. 1)
Początek laboratorium:
• w XAMPP uruchomić Apache oraz MySQL, następnie przejść do phpMyAdmin,
• pobrać na pulpit archiwum Lab011_AI1_start.zip
, w którym umieszczony jest projekt
startowy do wykonania zadań oraz rozpakować to archiwum,
• przejść do rozpakowanego folderu oraz w przypadku posiadania innych ustawień niż
domyślne (np. połączenia z bazą), wykonać ich zmianę w .env.example
oraz start.…,
• uruchomić skrypt start.bat
(Windows, 2x kliknięciem) lub start.sh
(inne systemy,
przez polecenie bash start.sh),
• zainstalować program Postman oraz pominąć zakładanie konta: lightweight API client,
• zainstalować link.
Zadania (Laravel):
Zadanie 11.1:
Wyjaśnić zagadnienia z ostatniego zadania z poprzedniego laboratorium. Zapoznać się z już wprowadzonymi modyfikacjami: • wyłączenie sesji, ciasteczek oraz tokenów CSRF (w migracji …_create_users_table.php oraz boostrap/app.php),
• dodanie pliku api.php, w którym będą ustalane ścieżki/endpoint’y API,
• usunięcie Laravel Sanctum (na tym laboratorium nie potrzebne jest uwierzytelnianie, a na Lab013 będzie JWT),
• utworzenie middleware’u dodającego nagłówek Accept: ‘application/json’ do każdego żądania, co zapobiega zwracaniu widoków np. gdy wystąpi błąd.
(występują różnice pomiędzy Laravel’em 10.x a 11.x)
php artisan install:api
composer remove laravel/sanctum
php artisan make:middleware ForceJsonResponse
Zadanie 11.2:
Otworzyć terminal cmd (Command Prompt) w VSCode. Uruchomić serwer deweloperski php dla przy użyciu komendy serve artisan’a.
php artisan serve
Zadanie 11.3:
Otworzyć drugą kartę terminala cmd (Command Prompt) w VSCode. Wykonać poniższe polecenie w celu wygenerowania nowego kontrolera z obecnymi funkcjami do przeprowadzania operacji CRUD na „zasobie”, który nie będzie zawierał dwóch niepotrzebnych funkcji (wyjaśnić dlaczego są one niepotrzebne *).
php artisan make:controller CountryController --api --resource
Zadanie 11.4:
Ustawić trasowanie dla kontrolera CountryController (pamiętając, że jest to API kontroler), odtąd będzie to w pliku routes/api.php. Wyświetlić obecnie skonfigurowane trasowanie.
Route::apiResource('countries', CountryController::class);
GET|HEAD api/countries ........................ countries.index › CountryController@index
POST api/countries ........................ countries.store › CountryController@store
GET|HEAD api/countries/{country} ................ countries.show › CountryController@show
PUT|PATCH api/countries/{country} ............ countries.update › CountryController@update
DELETE api/countries/{country} .......... countries.destroy › CountryController@destroy
Zadanie 11.5:
Uzupełnić funkcję index kontrolera CountryController o zwracanie wszystkich krajów. Sprawdzić rezultat jej działania poprzez:
• przeglądarkę Chrome/Edge/Opera…,
• przeglądarkę Firefox,
• wykonanie żądania GET
w narzędziu Postman,
• plik requesty.rest do używania poprzez rozszerzenie REST Client w VSCode (kliknąć Send Request) lub samego PhpStorm’a.
public function index()
{
$countries = DB::table('countries')->get();
return $countries; // 200
}
Zadanie 11.6:
W następnym zadaniach przystąpić do realizacji funkcji CountryController’a według następujących założeń:
• formatem wymiany danych jest JSON: zwracany w ciele odpowiedzi (Response body), odczytywany z ciała żądania (Request body),
• dostępny jest walidator (Validator), który na podstawie ustalonych reguł walidacji określa poprawność obiektu: Tak lub Nie (fails) z informacją o błędach (errors),
• nieużywanie …Resource
, …Collection
,
• nieużywanie …StoreRequest
, …UpdateRequest
,
• nieużywanie model binding’u obiektu $country
jako parametru funkcji, tylko int $id
,
• nieużywanie funkcji Eloquent’a na modelu Country
, tylko operacje na fasadzie DB::…
,
Powyżej wymienione elementy będą wykorzystane na następnym laboratorium. Na razie należy zaprogramować kontroler „manualnie” żeby wiedzieć jakie operacje w jakich sytuacjach mają zwracać odpowiednie kody odpowiedzi.
Nieużywanie:
Zadanie 11.7:
Przystąpić do realizacji funkcji CountryController’a
tak, aby były zaprogramowane według
wcześniej ustalonych założeń oraz dokładnie według postaci opisanej poniżej (obsłużone
sytuacje „pozytywne”, zakończone sukcesem).
Następnie wykonać przykładowe żądania HTTP sprawdzające działanie tych funkcji.
Ponadto spróbować dodać do bazy kraj z powierzchnią null.
CountryController:
index():
Pobrać wszystkie kraje z bazy danych.
Zwrócić je jako tablicę JSON z obiektami i status 200.
show(id_kraju):
Pobrać kraj o id_kraju z bazy danych.
Zwrócić ten kraj jako obiekt JSON i status 200.
store(żądanie):
Odczytać dane z ciała żądania (z JSONa) tzn. właściwości obiektu i ich wartości.
Korzystając z danych dodać nowy kraj do bazy i uzyskać jego nowe id.
Pobrać nowy kraj po id.
Zwrócić ten kraj jako obiekt JSON i status 201.
update(żądanie, id_kraju)
Odczytać dane z ciała żądania (z JSONa) tzn. właściwości obiektu i ich wartości.
Zaktualizować kraj o tym id_kraju danymi z ciała żądania.
Pobrać kraj o tym id_kraju z bazy.
Zwrócić ten kraj jako obiekt JSON i status 200.
destroy(id_kraju):
Usunąć kraj o tym id_kraju z bazy.
Zwrócić status 204.
$inputs = [
'name' => $request->input('name'),
'code' => $request->input('code'),
'currency' => $request->input('currency'),
'area' => $request->input('area'),
'language' => $request->input('language')
];
return response()->json($country, 201);
return response()->json(null, 204);
Zadanie 11.8:
Zmodyfikować istniejące funkcje CountryController’a
tak, aby były zaprogramowane
według wcześniej ustalonych założeń oraz poszerzone według postaci opisanej poniżej
(dochodzi uwzględnienie sytuacji „niepozytywnych”, zakończonych brakiem sukcesu, np.
nieodnalezienie obiektu, błąd walidacji).
Następnie wykonać przykładowe żądania HTTP sprawdzające działanie tych funkcji, pod
kątem sytuacji „niepozytywnych”.
CountryController:
index():
Pobrać wszystkie kraje z bazy danych.
Zwrócić je jako tablicę JSON z obiektami i status 200.
show(id_kraju):
Pobrać kraj o id_kraju z bazy danych, w celu sprawdzenia czy istnieje.
Gdy nie istnieje:
Zwrócić status 404, oznajmujący o nieodnalezieniu tego kraju, czyli brak
możliwości jego zwrócenia.
Gdy istnieje:
Zwrócić ten kraj jako obiekt JSON i status 200.
store(żądanie):
Odczytać dane z ciała żądania (z JSONa) tzn. właściwości obiektu i ich wartości.
Ustalić reguły walidacji.
Zwalidować dane.
Gdy dane niepoprawne:
Zwrócić informację co było niepoprawne i status 400/422.
Gdy dane poprawne:
Korzystając z danych dodać nowy kraj do bazy i uzyskać jego nowe id.
Pobrać nowy kraj po id.
Zwrócić ten kraj jako obiekt JSON i status 201.
update(żądanie, id_kraju)
Pobrać kraj o id_kraju z bazy danych, w celu sprawdzenia czy istnieje.
Gdy nie istnieje:
Zwrócić status 404, oznajmujący o nieodnalezieniu tego kraju, czyli brak
możliwości jego aktualizacji.
Gdy istnieje:
Odczytać dane z ciała żądania (z JSONa) tzn. właściwości obiektu i ….
Ustalić reguły walidacji.
Zwalidować dane.
Gdy dane niepoprawne:
Zwrócić informację co było niepoprawne i status 400/422.
Gdy dane poprawne:
Zaktualizować kraj o tym id_kraju danymi z ciała żądania.
Pobrać kraj o tym id_kraju z bazy.
Zwrócić ten kraj jako obiekt JSON i status 200.
destroy(id_kraju):
Pobrać kraj o id_kraju z bazy danych, w celu sprawdzenia czy istnieje.
Gdy nie istnieje:
Zwrócić status 404, oznajmujący o nieodnalezieniu tego kraju, czyli brak
możliwości jego usunięcia.
Gdy istnieje:
Usunąć kraj o tym id_kraju z bazy.
Zwrócić status 204.
$rules = [
'name' => 'required|string|unique:countries,name,|max:50',
'code' => 'required|string|unique:countries,code,|max:3',
'currency' => 'required|string|max:30',
'area' => 'required|integer|min:0',
'language' => 'required|string|max:50',
];
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($inputs, $rules);
if($validator->fails()) {
return response($validator->errors()), 422); // lub 400
}
$rules = [
'name' => 'required|unique:countries,name,'.$this->country->id.'|max:50',
'code' => 'required|string|unique:countries,code,'.$this->country->id.'|max:3',
'currency' => 'required|string|max:30',
'area' => 'required|integer|min:0',
'language' => 'required|string|max:50',
]
Zadanie 11.9: *
Zmodyfikować istniejące funkcje CountryController’a
tak, aby były zaprogramowane
według wcześniej ustalonych założeń oraz poszerzone według postaci opisanej poniżej
(dochodzi zastąpienie zwracania obiektów bazodanowych na rzecz przekształconych
obiektów np. z tylko potrzebnymi polami, w odpowiednim formacie). Wykluczyć ze zwracanych obiektów:
"created_at": null
,
"updated_at": null
Następnie wykonać przykładowe żądania HTTP sprawdzające działanie tych funkcji, pod kątem nowej postaci JSON’ów.
CountryController:
index():
Pobrać wszystkie kraje z bazy danych i umieścić je w kolekcji.
Utworzyć nową kolekcję, do której dodać kolejno przekształcone kraje.
Zwrócić tą kolekcję jako tablicę JSON z obiektami i status 200.
show(id_kraju):
Pobrać kraj o id_kraju z bazy danych, w celu sprawdzenia czy istnieje.
Gdy nie istnieje:
Zwrócić status 404, oznajmujący o nieodnalezieniu tego kraju, czyli brak
możliwości jego zwrócenia.
Gdy istnieje:
Przekształcić kraj z postaci bazodanowej na postać przekształconą.
Zwrócić ten przekształcony kraj jako obiekt JSON i status 200.
store(żądanie):
Odczytać dane z ciała żądania (z JSONa) tzn. właściwości obiektu i ich wartości.
Ustalić reguły walidacji.
Zwalidować dane.
Gdy dane niepoprawne:
Zwrócić informację co było niepoprawne i status 400/422.
Gdy dane poprawne:
Korzystając z danych dodać nowy kraj do bazy i uzyskać jego nowe id.
Pobrać nowy kraj po id.
Przekształcić kraj z postaci bazodanowej na postać przekształconą.
Zwrócić ten przekształcony kraj jako obiekt JSON i status 201.
update(żądanie, id_kraju)
Pobrać kraj o id_kraju z bazy danych, w celu sprawdzenia czy istnieje.
Gdy nie istnieje:
Zwrócić status 404, oznajmujący o nieodnalezieniu tego kraju, czyli brak
możliwości jego aktualizacji.
Gdy istnieje:
Odczytać dane z ciała żądania (z JSONa) tzn. właściwości obiektu i ….
Ustalić reguły walidacji.
Zwalidować dane.
Gdy dane niepoprawne:
Zwrócić informację co było niepoprawne i status 400/422.
Gdy dane poprawne:
Zaktualizować kraj o tym id_kraju danymi z ciała żądania.
Pobrać kraj o tym id_kraju z bazy.
Przekształcić kraj z postaci bazo… na postać przekształconą.
Zwrócić ten przekształcony kraj jako obiekt JSON i status 200.
public function index()
{
$countries = DB::table('countries')->get();
$countriesCollection = [];
foreach ($countries as $country) {
$countriesCollection[] = [
'id' => $country->id,
'code' => $country->code,
'currency' => $country->currency,
'area' => $country->area,
'language' => $country->language,
];
}
return $countriesCollection; // 200
}
$countryResource = [
'id' => $country->id,
'code' => $country->code,
'currency' => $country->currency,
'area' => $country->area,
'language' => $country->language,
];
return $countryResource; // 200
W innych framework’ach byłoby to jak zwracanie DTO:
W Laravel’u nie ma wbudowanej obsługi DTO, ale w zastępstwie są …Resource i …Collection (następne laboratorium).
Zadania (Laravel, cd.):
Zadanie 11.10: *
Zainstalować pakiet Telescope, oraz wykonać migrację dla tabel potrzebnych do
przechowywania danych Telescope’a.
Wykonać kilka dowolnych żądań (do api/countries/…
).
Przejść pod poniższy adres. Zapoznać się z zakładkami i ich zawartością:
• Requests,
• Commands,
• Exceptions,
• Models,
• Queries.
composer require laravel/telescope
php artisan telescope:install
php artisan migrate
http://localhost:8000/telescope/
Zadanie 11.11: *
Zapoznać się z 3 poziomem dojrzałości API – Hypermedia Controls, HATEOAS. Jako prosty przykład zmodyfikować $countriesCollection, tak aby każdy kraj posiadał odnośnik do siebie:
-
– zadania/podpunkty do samodzielnego dokończenia/wykonania,
-
– zadania/podpunkty dla zainteresowanych.
Wersja pliku: v1.0