[[oktatas:web:back-end_framework:laravel:laravel_rest_api|< Laravel API]] ====== Laravel API kezdés ====== * **Szerző:** Sallai András * Copyright (c) Sallai András, 2021, 2023 * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC Attribution-Share Alike 4.0 International]] * Web: https://szit.hu ===== Projekt ===== Hozzuk létre a projektet: composer create-project laravel/laravel emp Lépjünk be könyvtárba, majd indítsuk el a szervert: cd emp php artisan serve ===== Adatbázis ===== Használhatunk többféle adatbázis, itt most SQLite-t fogunk használni. A database könyvtárban **hozzuk létre** az SQLite adatbázist, **database.sqlite** néven, egy üres fájl formájában: * database/database.sqlite **Szerkesszük** a **.env** fájlt, írjuk bele milyen adatbázist használunk. DB_CONNECTION=sqlite A MySQL-ra vonatkozó beállításokat tegyük megjegyzésbe. ===== Routes ===== A routes vagy magyarul útválasztásban határozzuk meg, milyen végpontokat érhetünk el, és a végpontokat elérve, mi kell történjen. Szerkesszük a routes/api.php fájlt: get('/user', function (Request $request) { return $request->user(); }); A két use kezdetű sor lehetővé teszik hogy használjuk a Request és a Route osztályokat. A Route::middleware() függvényhívással kezdődő sor egy útválasztási bejegyzés. Töröljük, vagy tegyük megjegyzésbe. Vegyünk fel egy saját útválasztó bejegyzést, GET metódussal: //... Route::get('/employees', function(){ return 'employees'; }); A /employees végpontot határoztuk meg és egy névtelen függvényben, az 'employees' szóval térünk vissza. ==== Ellenőrzés ==== Használjuk egy HTTP klienst a teszteléshez. Lehet egy böngésző, az Insomnia, vagy a curl parancssoros program. Készítsünk egy GET kérést a következő címre: http://localhost:8000/api/employees Ügyeljünk arra, hogy fusson a szerver. Ha valamiért leállítottuk, akkor nem kapunk eredményt. ==== Gyakorlat ==== * Készítsünk legalább három másik végpontot, GET metódussal, különféle üzenetekkel. ===== Dolgozók modell és tábla ===== Hozzuk létre a dolgozók táblát gyártó PHP osztályt: php artisan make:model Employee --migration A --migration kapcsoló, létrehozza a migrációs fájlokat, amiből leképezhető az adatbázis tábla. A Laravel alapértelmezetten tartalmaz néhány migrációs táblát, ezek szükségesek a működéshez. A migrációs fájlok a **database/migrations** könyvtárban vannak. Szerkesszük a database/migrations/*create_employees_table.php fájlt. A * helyén az aktuális dátum szerepel. //... public function up() { Schema::create('employees', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('city'); $table->decimal('salary', 5, 2); $table->timestamps(); }); } //... Ezt követően a táblák elkészíthetők Hozzuk létre a táblákat: php artisan migrate További lehetőségek a migrációs fájlokban: $table->increments('id'); $table->boolean('done'); $table->tinyInteger('status')->default('1'); ==== Tábla frissítése ==== Ha szeretnénk javítani a migrációs állományt, szükség van a migráció újabb futtatására. Ez a :refresh utótaggal tehetjük meg. Ez a művelet törli a tábla tartalmát. php artisan migrate:refresh ===== Útválasztás javítása ===== Vegyük használatba az útválasztóban az Employee osztályt: use App\Models\Employee; //... Route::get('/employees', function(){ return Employee::all(); }); Ellenőrizzük Insomnia-ban: * Metódus: GET * URL: http://localhost:8000/api/employees A tábla üres, de 200-s kódot kell kapjunk. ===== A post metódus ===== Szeretnénk új dolgozót felvenni. Ehhez engedélyezzük a **name**, **city** és **salary** mezők megadását: //... class Employee extends Model { use HasFactory; protected $fillable = [ 'name', 'city', 'salary' ]; } A routingban beállítunk egy dolgozót: //... Route::post('/employees', function(){ return Employee::create([ 'name' => 'Rágó Ferenc', 'city' => 'Szolnok', 'salary' => 2873000 ]); }); Ellenőrizzük egy POST kéréssel az Insomnia-ban. Nézzük meg az adatbázisban az új dolgozót. Így most, mindig ezt a felhasználót fogja felvenni. A következő fejezetben megoldjuk, hogy a bejövő HTTP kérésből vegyük a dolgozó adatait. ===== A dolgozó kontroller ===== Hozzunk létre egy Employee nevű kontrollert: php artisan make:controller EmployeeController --resource --api Kapcsolók: * A --resource hatására létrejönnek az alapértelmezett metódusok. * A --api hatására nem jön létre create és edit metódus. A create és edit metódusok nem szükségesek REST API készítése során. Szerkesszük az EmployeeController.php fájlt. Szükség van az Employee modellre, vegyük azt használatba: //... use App\Models\Employee; Az index függvényben kérjük le az összes dolgozó adatait: public function index() { return Employee::all(); } Állítsuk be az útválasztás: use App\Http\Controllers\EmployeeController; //... Route::get('/employees', [EmployeeController::class, 'index']); A [EmployeeController::class, 'index'], azt jelenti, az EmployeeController osztályon belül szeretnénk az index metódust hívni, ha valaki a /employees végpontra hivatkozik. Ellenőrizzük API klienssel. Ha szeretnénk dolgozót tárolni egy store() nevű metódust hozunk létre. Írjuk meg a store függvényt: //... public function store(Request $request) { return Employee::create($request->all()); } Írjunk hozzá útválasztást: use App\Http\Controllers\EmployeeController; //... Route::get('/products', [EmployeeController::class, 'index']); Route::post('/employees', [EmployeeController::class, 'store']); Teszteljük API klienssel. JSON tartalmat küldünk. Insomnia esetén figyeljük meg a "Header" fülön, hogy beállításra kerül a "Content-Type" "application/json" fejléc adat. ==== Válaszkód küldése ==== //... public function store(Request $request) { $employees = Employee::create($request->all()); return response($employees, 201); } A sikeres létrehozást 201-s válaszkóddal jelezzük. ==== Validáció beállítása ==== //... public function store(Request $request) { $request->validate([ 'name' => 'required', 'salary' => 'required' ]); $employees = Employee::create($request->all()); return response($employees, 201); } ===== Egyetlen dolgozó lekérdezése ===== //... public function show($id) { return Employee::find($id); } Írjunk hozzá útválasztást: Route::get('/products/{id}', [EmployeeController::class, 'show']); A végpont után írt {id} az show() metódusban elérhető paraméterként a kontrollerben. ===== Dolgozó módosítása ===== //... public function update(Request $request, $id) { $employee = Employee::find($id); $employee->update($request->all()); return $employee; } Írjunk hozzá útválasztást: //... Route::put('/employees/{id}', [EmployeeController::class, 'update']); Ellenőrizzük API klienssel. ===== Dolgozó törlése ===== //... public function destroy($id) { return Employee::destroy($id); } Írjunk hozzá útávlasztást: //... Route::delete('/employees/{id}', [EmployeeController::class, 'destroy']); Ellenőrizzük API klienssel. Siker esetén 1-el tér vissza. ===== Összes erőforrás ===== Az összes CRUD műveletet egyetlen útválasztó bejegyzéssel megoldhatjuk: use App\Http\Controllers\EmployeeController; //... Route::resource('/employees', EmployeeController::class); /* Route::get('/products', [EmployeeController::class, 'index']); Route::post('/employees', [EmployeeController::class, 'store']); Route::get('/products/{id}', [EmployeeController::class, 'show']); Route::put('/employees/{id}', [EmployeeController::class, 'update']); Route::delete('/employees/{id}', [EmployeeController::class, 'destroy']); */ Ellenőrizzük, milyen router információk vannak: php artisan route:list Ellenőrizzük API klienssel. Cím: http://localhost:8000/api/employees/2 ===== Keresés ===== //... public function search($name) { return Employee::where('name', 'like', '%'.$name.'%')->get(); } Routing szerkesztése: use App\Http\Controllers\EmployeeController; //... Route::get('/employees/search/{name}', [EmployeeController::class, 'search']); Ellenőrizzük API klienssel. Például: http://localhost:8000/api/employees/search/László ===== Sanctum ===== A csomagok (package) között található a Sanctum: * https://laravel.com/docs/8.x/sanctum use App\Http\Controllers\EmployeeController; //... Route::resource('/employees', EmployeeController::class); // Route::get('/employees/search/{name}', [EmployeeController::class, 'search']); // Route::get('/employees', [EmployeeController::class, 'index']); // Route::post('/employees', [EmployeeController::class, 'store']); Route::group(['middleware' => ['auth:sanctum']], function () { Route::get('/employees/search/{name}', [EmployeeController::class, 'search']); }); Route::middleware('auth:sanctum')->get('/user', function (Request $request) { return $request->user(); }); Ellenőrizzük: http://localhost:8000/api/employees/search/László A következő hibát kapjuk: Route [login] not defined. Állítsuk be fejlécben -> "Header" fülön: Accept application/json A következő választ kapjuk: { "message": "Unauthenticated." } ==== Auth kontroller ==== php artisan make:controller AuthController validate([ 'name' => 'required|string', 'email' => 'required|string|unique:users,email', 'password' => 'required|string|confirmed' ]); $user = User::create([ 'name' => $fields['name'], 'email' => $fields['email'], 'password' => bcrypt($fields['password']) ]); $token = $user->createToken('sajatToken')->plainTextToken; $response = [ 'user' => $user, 'token' => $token ]; return response($response, 201); } public function login(Request $request) { if( Auth::attempt([ "name" => $request->name, "password" => $request->password ])) { $authUser = Auth::user(); $success[ "token" ] = $authUser->createToken( "myapptoken" )->plainTextToken; $success[ "name" ] = $authUser->name; return response( $success); }else { return response( "Hiba! A bejelentkezés sikertelen", [ "error" => "Hibás adatok" ]); } } public function logout( Request $request ) { auth( "sanctum" )->user()->currentAccessToken()->delete(); return response()->json('Kijelentkezve'); } } Az AuthController tartalmát, akár be is másolhatjuk, de van egy hivatkozás User osztályra, ezért ne felejtsük el használatba vennei: use App\Models\User; use Illuminate\Http\Response; use Illuminate\Support\Facades\Hash; use Illuminate\Support\facades\Auth; //... Regisztrációnál a jelszó elkérhető kétszer: $validator = Validator::make( $request->all() , [ "name" => "required", "email" => "required", "password" => "required", "confirm_password" => "required|same:password", ]); ==== Regisztráció ==== Az api számára is fel kell vennünk felhasználókat az azonosításhoz. Használhatunk hozzá egy REST API klienst, például Insomnia. Fejléc: Accept application/json Ezt küldjük: { "name": "mari", "email": "mair@zold.lan", "password": "titok", "password_confirmation": "titok" } Eredmény: { "user": { "name": "mari", "email": "mari@zold.lan", "updated_at": "2021-11-24T19:57:43.000000Z", "created_at": "2021-11-24T19:57:43.000000Z", "id": 3 }, "token": "3|7eBr5iAUPgqQz3lxIFgC72Yh3ERO76g1MyuHNOGD" } ==== Keresés azonosítással ==== Insomnia-ban: * Auth fül * Kiválasztjuk: Bearer * Token: 3|7eBr5iAUPgqQz3lxIFgC72Yh3ERO76g1MyuHNOGD * [Send] ==== Útválasztás ==== Route::post('/register', [AuthController::class, 'register']); Route::post('/login', [AuthController::class, 'login']); ===== Kilépés ===== //... public function logout(Request $request) { auth()->user()->tokens()->delete(); return [ 'message' => 'Logged out' ]; } Útválasztás: Route::group(['middleware' => ['auth:sanctum']], function () { Route::get('/employees/search/{name}', [EmployeeController::class, 'search']); Route::post('/logout', [AuthController::class, 'logout']); }); Teszteléshez: http://localhost:8000/api/logout