100行代码中Laravel上的REST API

inb4:从文档中复制粘贴


该指南着重于根据最佳实践快速部署用于成熟API开发的最小集合,该最佳集合取自Laravel 5.7文档,该文献收集在一个地方。 我为自己和同事写了备忘单,希望对其他人有用。


预设值


我们提出了一个框架


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


删除不必要的UI组件(vuejs,react)


php artisan preset none


配置数据库连接


转到文件夹,编辑.env文件:


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

开始生成


我们在控制台中执行
php artisan make:model Game -mrc


我们得到模型,迁移和控制器:


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

在数据库表中创建列


我们通过向表中添加列来更正迁移。 最常用的类型:


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

对于可选字段,请不要忘记使用->default()添加默认值


通过运行php artisan migrate migration应用php artisan migrate


我们生成验证规则


运行php artisan make:request GameRequest


打开App/Http/Requests/GameRequest.php
authorize()方法中,将return true设置为return true直到我们添加授权为止。
rules()方法中返回的数组描述了我们在迁移中列出的所有列的规则。 这里可用的规则


为了尽量减少代码,我们将switch构造用于不同的http动词,而不是单独执行StoreGameRequest,UpdateGameRequest等。


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

自定义错误描述选项


如果您需要自己的错误文本,我们将重新定义messages()方法,该方法返回一个包含每个规则翻译的数组:


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

为了确保验证规则中不仅可以使用在请求主体中传递的参数,而且可以在验证规则中使用URL中传递的参数,我们重新定义了all方法(在控制器中通常以$ 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; } 

我们配置控制器并描述业务逻辑


打开Http\Controllers\GameController 。 我们删除了用于渲染表单的生成的create(), edit()方法(因为我们有REST API,所以不需要它们)。


替换标准use Illuminate\Http\Request; ,在我们的use App\Http\Requests\GameRequest;use App\Http\Requests\GameRequest;


接下来,编辑方法:


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

如果逻辑很多,最好将其放在单独的服务/存储库层中


定制模型


打开app / Http / Game.php模型并添加属性:


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

配置中间件


为了使我们的应用程序始终返回json而不管传递的标头如何,我们创建了中间件:


 php artisan make:middleware ForceJsonResponse 

并添加代码:


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

app/Http/Kernel.php注册该中间件:


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

我们配置路由


打开routes/api.php并添加:


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

与资源方法不同,静态Route :: apiResource方法不包括edit和create方法,仅保留索引,显示,存储,更新,销毁。


可以通过更明显的记录实现相同的目的:


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

现在,您可以看到带有php artisan route:list命令的路径并使用它。


REST API已准备就绪!


后记

后记


如果您需要授权,则可以使用标准的Laravel Passport。


配置Laravel Passport授权


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

Laravel\Passport\HasApiTokens添加到App\User模型,并在boot app/AuthServiceProvider调用Passport::routesmethod app/AuthServiceProvider


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

config/auth.php将驱动程序更改为通行证:


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

为授权“ php artisan make”创建控制器:controller Api / AuthController.php`


在此处添加代码


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

之后,您可以使用api/register, api/login, api/logout方法进行授权,并阻止对api的访问。 为此,我们需要将REST控制器的路由包装在中间件中:


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

后记

后记:


仍然会有大量的功能测试和文档生成,但这超出了脚手架教程的范围,因此在另一时间


Source: https://habr.com/ru/post/zh-CN441946/


All Articles