API REST no Laravel em 100 linhas de código

inb4: copiar e colar da documentação


O guia concentra-se na rápida implantação de um conjunto mínimo para o desenvolvimento completo da API, de acordo com as melhores práticas, retiradas da documentação do Laravel 5.7, coletadas em um único local. Escrevi para mim e meus colegas como uma folha de dicas, espero que seja útil para outra pessoa.


Predefinição


Nós colocamos uma estrutura


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


Remova componentes desnecessários da interface do usuário (vuejs, reaja)


php artisan preset none


Configurar conexão com o banco de dados


Vá para a pasta, edite o arquivo .env:


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

Introdução à geração


Executamos no console
php artisan make:model Game -mrc


Temos o modelo, migração e controlador:


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

Crie colunas na tabela do banco de dados


Corrigimos a migração adicionando colunas à tabela. Tipos mais usados:


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

Para campos opcionais, não esqueça de adicionar o valor padrão com ->default()


Aplique migrações executando o php artisan migrate


Geramos regras de validação


Executando o php artisan make:request GameRequest


Abra App/Http/Requests/GameRequest.php .
No método authorize() , defina return true até adicionarmos autorização.
A matriz retornada no método rules() descreve as regras para todas as colunas listadas na migração. Regras disponíveis aqui


Para minimizar o código, usamos a construção switch para diferentes verbos http, em vez de fazer 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' ]; } } 

Opções de descrição de erro personalizadas


Se você precisar de seus próprios textos de erro, redefinimos o método messages (), que retorna uma matriz com traduções de cada regra:


 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 garantir que não apenas os parâmetros passados ​​no corpo da solicitação, mas também os parâmetros passados ​​na URL estejam disponíveis nas regras de validação, redefinimos o método all (normalmente usado no controlador na 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 o controlador e descrevemos a lógica de negócios


Abra Http\Controllers\GameController . Removemos os métodos gerados create(), edit() destinados a renderizar formulários (já que temos uma API REST, eles não são necessários).


Substitua o use Illuminate\Http\Request; padrão use Illuminate\Http\Request; , em nosso use App\Http\Requests\GameRequest;


Em seguida, edite os 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); } 

Se houver muita lógica, é melhor colocá-la em uma camada separada Serviço / Repositório


Personalize o modelo


Abra o modelo app / Http / Game.php e adicione as propriedades:


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

Configurar middleware


Para que nosso aplicativo sempre retorne json, independentemente dos cabeçalhos passados, criamos o middleware:


 php artisan make:middleware ForceJsonResponse 

e adicione o código a ele:


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

Registre este middleware em app/Http/Kernel.php :


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

Nós configuramos o roteamento


Abra routes/api.php e adicione:


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

O método estático Route :: apiResource, diferentemente do método de recurso, exclui os métodos de edição e criação, deixando apenas o índice, mostra, armazena, atualiza e destrói.


O mesmo pode ser alcançado com um registro mais óbvio:


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

Agora, você pode ver o caminho com o comando php artisan route:list e usá-lo.


A API REST está pronta!


Posfácio

Posfácio


Se você precisar de autorização, o Laravel Passport padrão o fará.


Configurar autorização do Laravel Passport


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

Adicione a característica Laravel\Passport\HasApiTokens ao modelo App\User e chame Passport::routesmethod no app/AuthServiceProvider boot app/AuthServiceProvider :


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

No config/auth.php altere o driver para passaporte:


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

Crie um controlador para autorização 'php artisan make: controller Api / AuthController.php`


Adicione o código lá


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

Depois disso, você pode usar os métodos api/register, api/login, api/logout para autorização e bloquear o acesso à API. Para fazer isso, precisamos agrupar o roteamento de nossos controladores REST no middleware:


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

Posfácio

Posfácio:


Ainda haveria testes funcionais e geração de documentação com arrogância, mas isso está um pouco além do escopo do tutorial do andaime, e mais sobre isso outra vez


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


All Articles