API REST en Laravel en 100 líneas de código

inb4: copie y pegue de la documentación


La guía se enfoca en el despliegue rápido de un conjunto mínimo para el desarrollo completo de API de acuerdo con las mejores prácticas, tomado de la documentación de Laravel 5.7, reunido en un solo lugar. Escribí para mí y mis colegas como una hoja de trucos, espero que sea útil para otra persona.


Preestablecido


Ponemos un marco


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


Eliminar componentes innecesarios de la interfaz de usuario (vuejs, reaccionar)


php artisan preset none


Configurar conexión de base de datos


Vaya a la carpeta, edite el archivo .env:


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

Comenzando a generar


Ejecutamos en la consola
php artisan make:model Game -mrc


Obtenemos el modelo, la migración y el controlador:


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

Crear columnas en la tabla de la base de datos.


Corregimos la migración agregando columnas a la tabla. Tipos más utilizados:


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

Para campos opcionales, no olvide agregar el valor predeterminado con ->default()


Aplicar migraciones ejecutando php artisan migrate


Generamos reglas de validación.


Ejecutando php artisan make:request GameRequest


Abra la App/Http/Requests/GameRequest.php .
En el método authorize() , establezca return true hasta que agreguemos autorización.
La matriz que se devuelve en el método rules() describe las reglas para todas las columnas que enumeramos en la migración. Reglas disponibles aquí


Para minimizar el código, usamos la construcción del interruptor para diferentes verbos http, en lugar de hacer StoreGameRequest, UpdateGameRequest, 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' ]; } } 

Opciones de descripción de error personalizado


Si necesita sus propios textos de error, redefinimos el método de mensajes (), que devuelve una matriz con traducciones de cada regla:


 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', ]; } 

Para garantizar que no solo los parámetros pasados ​​en el cuerpo de la solicitud, sino también los parámetros pasados ​​en la URL estén disponibles en las reglas de validación, redefinimos el método all (que generalmente se usa en el controlador en forma 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; } 

Configuramos el controlador y describimos la lógica del negocio.


Abra Http\Controllers\GameController . Eliminamos los métodos generados create(), edit() destinados a representar formularios (ya que tenemos una API REST, no son necesarios).


Reemplace el use Illuminate\Http\Request; estándar use Illuminate\Http\Request; , en nuestro use App\Http\Requests\GameRequest;


A continuación, edite los métodos:


 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); } 

Si hay mucha lógica, entonces es mejor colocarla en una capa separada Servicio / Repositorio


Personaliza el modelo


Abra el modelo de la aplicación / Http / Game.php y agregue las propiedades:


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

Configurar middleware


Para que nuestra aplicación siempre devuelva json independientemente de los encabezados pasados, creamos middleware:


 php artisan make:middleware ForceJsonResponse 

y agregue el código:


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

Registre este middleware en la app/Http/Kernel.php :


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

Configuramos enrutamiento


Abra routes/api.php y agregue:


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

El método estático Route :: apiResource, a diferencia del método de recursos, excluye los métodos de edición y creación, dejando solo indexar, mostrar, almacenar, actualizar, destruir.


Lo mismo se puede lograr con un registro más obvio:


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

Ahora, puede mirar los caminos con la php artisan route:list comando de php artisan route:list y usarlo.


¡REST API está lista!


Epílogo

Epílogo


Si necesita autorización, lo hará el Pasaporte Laravel estándar.


Configurar la autorización del pasaporte Laravel


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

Agregue el Laravel\Passport\HasApiTokens al modelo App\User y llame a Passport::routesmethod en la app/AuthServiceProvider boot app/AuthServiceProvider :


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

En el config/auth.php cambie el controlador a pasaporte:


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

Cree un controlador para la autorización 'php artisan make: controller Api / AuthController.php`


Agrega el código allí


 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); } 

Después de eso, puede usar los métodos api/register, api/login, api/logout para la autorización y bloquear el acceso a la api. Para hacer esto, necesitamos envolver el enrutamiento de nuestros controladores REST en middleware:


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

Epílogo

Epílogo:


Todavía habría que hacer pruebas funcionales y generación de documentación en swagger, pero esto está un poco más allá del alcance del tutorial de andamios, así que más sobre eso en otro momento


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


All Articles