API REST sur Laravel en 100 lignes de code

inb4: copier coller depuis la documentation


Le guide se concentre sur le déploiement rapide d'un ensemble minimal pour un développement d'API à part entière conformément aux meilleures pratiques, tiré de la documentation Laravel 5.7, collecté en un seul endroit. J'ai écrit pour moi et mes collègues comme une feuille de triche, j'espère que cela sera utile à quelqu'un d'autre.


Preset


Nous mettons un cadre


composer create-project --prefer-dist laravel/laravel scaffold-api


Supprimez les composants inutiles de l'interface utilisateur (vuejs, react)


php artisan preset none


Configurer la connexion à la base de données


Accédez au dossier, modifiez le fichier .env:


 DB_CONNECTION=mysql DB_HOST=localhost DB_PORT=3306 DB_DATABASE=api-authentification DB_USERNAME=root DB_PASSWORD= 

Commencer à générer


Nous exécutons dans la console
php artisan make:model Game -mrc


Nous obtenons le modèle, la migration et le contrôleur:


 Model created successfully. Factory created successfully. Created Migration: 2019_02_27_105610_create_games_table Controller created successfully. 

Créer des colonnes dans la table de base de données


Nous corrigeons la migration en ajoutant des colonnes à la table. Types les plus couramment utilisés:


  • increments('id')
  • string('title')
  • text('description')
  • tinyInteger('complexity')
  • boolean('isActive')
  • softDeletes()

Pour les champs optionnels, n'oubliez pas d'ajouter la valeur par défaut avec ->default()


Appliquer les migrations en exécutant php artisan migrate


Nous générons des règles de validation


Exécution de php artisan make:request GameRequest


Ouvrez App/Http/Requests/GameRequest.php .
Dans la méthode authorize() , définissez return true jusqu'à ce que nous ajoutions l'autorisation.
Le tableau renvoyé dans la méthode rules() décrit les règles de toutes les colonnes que nous avons répertoriées dans la migration. Règles disponibles ici


Pour minimiser le code, nous utilisons la construction de commutateur pour différents verbes http, au lieu de faire StoreGameRequest, UpdateGameRequest séparés, etc.


 public function rules(Request $request) { $rules = [ 'title' => 'required|string|unique:games,title', 'description' => '', 'complexity' => 'required|min:1|max:10', 'minPlayers' => 'required|min:1|max:10', 'maxPlayers' => 'required|min:1|max:10', 'isActive' => 'required|boolean' ]; switch ($this->getMethod()) { case 'POST': return $rules; case 'PUT': return [ 'game_id' => 'required|integer|exists:games,id', // .   : unique:games,id,' . $this->route('game'), 'title' => [ 'required', Rule::unique('games')->ignore($this->title, 'title') //  ,     ] ] + $rules; //      // case 'PATCH': case 'DELETE': return [ 'game_id' => 'required|integer|exists:games,id' ]; } } 

Options de description d'erreur personnalisées


Si vous avez besoin de vos propres textes d'erreur, nous redéfinissons la méthode messages (), qui retourne un tableau avec les traductions de chaque règle:


 public function messages() { return [ 'date.required' => 'A date is required', 'date.date_format' => 'A date must be in format: Ym-d', 'date.unique' => 'This date is already taken', 'date.after_or_equal' => 'A date must be after or equal today', 'date.exists' => 'This date doesn\'t exists', ]; } 

Afin de garantir que non seulement les paramètres passés dans le corps de la demande, mais aussi les paramètres passés dans l'URL sont disponibles dans les règles de validation, nous redéfinissons la méthode all (qui est généralement utilisée dans le contrôleur sous la forme de $ request-> all ()):


 public function all($keys = null) { // return $this->all(); $data = parent::all($keys); switch ($this->getMethod()) { // case 'PUT': // case 'PATCH': case 'DELETE': $data['date'] = $this->route('day'); } return $data; } 

Nous configurons le contrôleur et décrivons la logique métier


Ouvrez Http\Controllers\GameController . Nous supprimons les méthodes create(), edit() générées pour le rendu des formulaires (puisque nous avons une API REST, elles ne sont pas nécessaires).


Remplacez l' use Illuminate\Http\Request; standard use Illuminate\Http\Request; , sur notre use App\Http\Requests\GameRequest;


Ensuite, modifiez les méthodes:


 public function index() { return Game::all(); } 

 public function store(GameRequest $request) { $day = Game::create($request->validated()); return $day; } 

 public function show(Game $game) { return $game = Game::findOrFail($game); } 

 public function update(GameRequest $request, $id) { $game = Game::findOrFail($id); $game->fill($request->except(['game_id'])); $game->save(); return response()->json($game); } 

 public function destroy(GameRequest $request, $id) { $game = Game::findOrFail($id); if($game->delete()) return response(null, 204); } 

S'il y a beaucoup de logique, il est préférable de le placer dans un service / référentiel de couche séparé


Personnalisez le modèle


Ouvrez le modèle app / Http / Game.php et ajoutez les propriétés:


 protected $fillable = ['title', 'description', 'complexity', 'minPlayers', 'maxPlayers', 'isActive']; protected $hidden = ['created_at', 'updated_at', 'deleted_at']; 

Configurer le middleware


Pour que notre application retourne toujours json quels que soient les en-têtes passés, nous créons un middleware:


 php artisan make:middleware ForceJsonResponse 

et ajoutez-y le code:


 public function handle($request, Closure $next) { $request->headers->set('Accept', 'application/json'); return $next($request); } 

Enregistrez ce middleware dans app/Http/Kernel.php :


 ... 'api' => [ 'throttle:60,1', 'bindings', \App\Http\Middleware\ForceJsonResponse::class, ], 

Nous configurons le routage


Ouvrez routes/api.php et ajoutez:


 use Http\Controllers\GameController; Route::apiResource('/games', 'GameController'); 

La méthode statique Route :: apiResource, contrairement à la méthode de ressource, exclut les méthodes d'édition et de création, ne laissant que l'index, afficher, stocker, mettre à jour, détruire.


La même chose peut être obtenue avec un record plus évident:


 Route::resource('/games', 'GameController')->only([ 'index', 'show', 'store', 'update', 'destroy' ]); 

Maintenant, vous pouvez regarder les chemins avec la commande php artisan route:list et l'utiliser.


L'API REST est prête!


Postface

Postface


Si vous avez besoin d'une autorisation, le passeport Laravel standard fera l'affaire.


Configurer l'autorisation Laravel Passport


 composer require laravel/passport php artisan make:auth php artisan passport:install php artisan migrate 

Ajoutez le Laravel\Passport\HasApiTokens au modèle App\User et appelez Passport::routesmethod dans la app/AuthServiceProvider boot app/AuthServiceProvider :


 public function boot() { $this->registerPolicies(); Passport::routes(); } 

Dans le config/auth.php changez le pilote en passeport:


 'api' => [ 'driver' => 'passport', 'provider' => 'users', ], 

Créez un contrôleur pour l'autorisation «php artisan make: controller Api / AuthController.php»


Ajoutez-y le code


 use App\User; use Illuminate\Support\Facades\Validator; 

 public function register (Request $request) { $validator = Validator::make($request->all(), [ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:6|confirmed', ]); if ($validator->fails()) { return response(['errors'=>$validator->errors()->all()], 422); } $request['password']=Hash::make($request['password']); $user = User::create($request->toArray()); $token = $user->createToken('Laravel Password Grant Client')->accessToken; $response = ['token' => $token]; return response($response, 200); } public function login (Request $request) { $user = User::where('email', $request->email)->first(); if ($user) { if (Hash::check($request->password, $user->password)) { $token = $user->createToken('Laravel Password Grant Client')->accessToken; $response = ['token' => $token]; return response($response, 200); } else { $response = "Password missmatch"; return response($response, 422); } } else { $response = 'User does not exist'; return response($response, 422); } } public function logout (Request $request) { $token = $request->user()->token(); $token->revoke(); $response = 'You have been succesfully logged out!'; return response($response, 200); } 

Après cela, vous pouvez utiliser les méthodes api/register, api/login, api/logout pour l'autorisation et bloquer l'accès à l'api. Pour ce faire, nous devons encapsuler le routage de nos contrôleurs REST dans un middleware:


 Route::middleware('auth:api')->group(function () { ... Route::get('/logout', 'Api\AuthController@logout')->name('logout'); }); 

Postface

Postface:


Il y aurait encore à faire des tests fonctionnels et la génération de documentation dans swagger, mais c'est un peu au-delà de la portée du tutoriel d'échafaudage, donc plus à ce sujet une autre fois


Source: https://habr.com/ru/post/fr441946/


All Articles