Главная Новости

Как создать RESTful API Laravel


Опубликовано: 01.09.2018

видео Как создать RESTful API Laravel

Creating RESTful controller to select, insert, update and delete data in Laravel

REST stands for REpresentational State Transfer и представляет собой архитектурное решение для сетевого взаимодействия между приложениями.



HTTP Action.

В API RESTful мы используем HTTP-action как действия, а конечными точками являются ресурсы, на которые воздействуют. Мы будем использовать HTTP-action по их семантическому значению:

POST : создать

GET : получить

PUT : обновить

DELETE : удалить

 


Build a RESTful API with Laravel - Pluralsight Course Announcement

CreateReadUpdateDelete ( CRUD ) — эта аббревиатура частенько может попадаться в статьях.

Update Action: PUT vs. POST

Много копий сломано в спорах API RESTful — о том, лучше ли обновлять с помощью POST, PATCH, или PUT.

В этой статье мы будем использовать PUT для действия обновления, так как согласно HTTP RFC, PUT означает создание / обновление ресурса в определенном месте.


Rest Api laravel 5.3 Básico

Краткое отступление: те, кто любит читать, может и далее впитывать знания полнотекстово.

Для киноманов — предоставляю видео тематично статье, но не по содержанию.

 

Ресурсы

Ресурсы станут целями действий, в нашем случае «Статьи и пользователи», и у них есть свои конечные точки:

/articles

/users

В этом уроке о api laravel ресурсы будут иметь представление 1:1 для наших моделей данных, но это не является обязательным. Вы можете иметь ресурсы, представленные более чем в одной модели данных (или вообще не представленные в базе данных). В конце концов, вы решаете, как спроектировать ресурсы и модели таким образом, который наиболее подходит вашему приложению.

Пропустим момент установки Laravel 5.4, а заодно и как выбрать хостинг , и перейдем прямо к сути.

Создадим модель Article.

Запустим терминал CTRL+ALT+T

перейдем в каталог со свежеустановленным Laravel

cd /path/to/my/project

и введем команду

php artisan make:model Article -m

The опция -m кратко от —migration скажет Artisan создать модель Article и создать миграцию для нее.

use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateArticlesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('articles', function (Blueprint $table) { $table->increments('id'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('articles'); } }

Немного подробнее:

The up() and down() — методы будут выполняться при миграции и ее откате; $table->increments('id') установит автоинкремент для поля id; $table->timestamps() установит timestamps для полей —created_at и updated_at, и можно не беспокоиться о дефолтных значениях, Laravel их внесет по мере необходимости. И наконец, Schema::dropIfExists() удалит таблицу, если такая существует.

На основе вышесказанного давайте добавим в метод up() следующие строки:

public function up() { Schema::create('articles', function (Blueprint $table) { $table->increments('id'); $table->string('title'); $table->text('body'); $table->timestamps(); }); }

string() метод создаст VARCHAR столбец, а text() создаст  TEXT.

После этого:

php artisan migrate

Laravel, из коробки поставляется с двумя миграциями create_users_table и create_password_resets_table.

Мы не будем использовать миграцию password_resets table, but having the users.

Вернемся к нашей модели и добавим атрибуты $fillable чтобы мы могли их использовать в методах Article::create and Article::update нашей модели:

class Article extends Model { protected $fillable = ['title', 'body']; }

Поля с атрибутом $fillable доступны для массового заполнения.

 

Database Seeding

Не будем останавливаться на создании сидирования(автозаполнения) таблиц данными, об этом подробнее можно прочесть здесь .

Routes and Controllers (маршруты и контроллеры)

Давайте создадим конечные точки нашего приложения: создание, получение списка, получение единичной сущности(сингл), обновление, и удаление. В routes/api.php, напишем:

Use App\Article; Route::get('articles', function() { // If the Content-Type and Accept headers are set to 'application/json', // this will return a JSON structure. This will be cleaned up later. return Article::all(); }); Route::get('articles/{id}', function($id) { return Article::find($id); }); Route::post('articles', function(Request $request) { return Article::create($request->all); }); Route::put('articles/{id}', function(Request $request, $id) { $article = Article::findOrFail($id); $article->update($request->all()); return $article; }); Route::delete('articles/{id}', function($id) { Article::find($id)->delete(); return 204; })

Маршруты внутри api.php будут иметь префикс / api /, и API Middleware будет автоматически применяться к ним.

Давайте переместим наш код в Controller (Контроллер):

$ php artisan make:controller ArticleController

ArticleController.php:

use App\Article; class ArticleController extends Controller { public function index() { return Article::all(); } public function show($id) { return Article::find($id); } public function store(Request $request) { return Article::create($request->all()); } public function update(Request $request, $id) { $article = Article::findOrFail($id); $article->update($request->all()); return $article; } public function delete(Request $request, $id) { $article = Article::findOrFail($id); $article->delete(); return 204; } }

Изменим routes/api.php:

Route::get('articles', ' [email protected] '); Route::get('articles/{id}', ' [email protected] '); Route::post('articles', ' [email protected] '); Route::put('articles/{id}', ' [email protected] '); Route::delete('articles/{id}', ' [email protected] ');

Мы можем улучшить наши конечные точки, используя неявные привязки маршрутов.

Route::get('articles', ' [email protected] '); Route::get('articles/{article}', ' [email protected] '); Route::post('articles', ' [email protected] '); Route::put('articles/{article}', ' [email protected] '); Route::delete('articles/{article}', ' [email protected] '); class ArticleController extends Controller { public function index() { return Article::all(); } public function show(Article $article) { return $article; } public function store(Request $request) { $article = Article::create($request->all()); return response()->json($article, 201); } public function update(Request $request, Article $article) { $article->update($request->all()); return response()->json($article, 200); } public function delete(Article $article) { $article->delete(); return response()->json(null, 204); } }

Примечание к кодам HTTP статусов и Формату ответа(Responce)

Мы также добавили response()->json() к вызову наших конечных точек. Это позволит нам возвращать явно JSON data а также HTTP код, который будет обрабатываться клиентом.

Общий список кодов:

200: OK. Стандартный код успешного ответа. 201: Объект создан. Полезен при работе с хранилищем(магазином). 204: Отсутствует контент. Когда действие выполнено успешно, но не возвращен контент. 206: Частичный контент. Используется когда вы  возвращаете контент постранично(пагинация). 400: Bad request. Стандартная опция для запросов которые не прошли валидацию. 401: Unauthorized. Пользователь не прошел авторизацию. 403: Forbidden. Пользователь авторизован, но у него не хватает прав для выполнения запроса. 404: Not found. возвращается Laravel автоматически когда запрошенный ресурс не найден. 500: Internal server error. В идеале, вы не должны возвращать такой ответ, но когда, что то неожиданно сбоит, то пользователь получит такой ответ. 503: Service unavailable. Довольно понятно, но тоже, код который не будет явно возращен приложением.

Отправка корректного 404

Если попытаетесь запросить несуществующий ресурс, то вы получите:

Мы можем исправить это отредактировав исключение нашего класса, расположенного в  app/Exceptions/Handler.php, которое вернет JSON:

public function render($request, Exception $exception) { // This will replace our 404 response with // a JSON response. if ($exception instanceof ModelNotFoundException) { return response()->json([ 'error' => 'Resource not found' ], 404); } return parent::render($request, $exception); }

Результатом будет:

{ data: "Resource not found" }

Если вы используете Laravel для обслуживания других страниц, вы должны отредактировать код для работы с  Accept header, в противном случае ошибки 404 из регулярных запросов будут возвращены с таким же успехом.

public function render($request, Exception $exception) { // This will replace our 404 response with // a JSON response. if ($exception instanceof ModelNotFoundException && $request->wantsJson()) { return response()->json([ 'data' => 'Resource not found' ], 404); } return parent::render($request, $exception); }

В этом случае, API запросам будет нужен header Accept: application/json.

 

Аутентификация

Существует много способов аутентификации в Laravel, но статья не об этом, поэтому будем использовать упрощенную.

Для начала нужно добавить поле api_token в таблицу users :

$ php artisan make:migration --table=users adds_api_token_to_users_table

Не забудем о миграции:

public function up() { Schema::table('users', function (Blueprint $table) { $table->string('api_token', 60)->unique()->nullable(); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn(['api_token']); }); }

Создание Регистрации пользователя

Будем использовать RegisterController (в папке Auth ) , который вернет правильный ответ после регистрации пользователя. Он также доступен из коробки, но до сих пор нуждается в доработке, чтобы вернул ответ, который нам нужен.

Контроллер использует Трейт RegistersUsers реализующий регистрацию

public function register(Request $request) { // Here the request is validated. The validator method is located // inside the RegisterController, and makes sure the name, email // password and password_confirmation fields are required. $this->validator($request->all())->validate(); // A Registered event is created and will trigger any relevant // observers, such as sending a confirmation email or any // code that needs to be run as soon as the user is created. event(new Registered($user = $this->create($request->all()))); // After the user is created, he's logged in. $this->guard()->login($user); // And finally this is the hook that we want. If there is no // registered() method or it returns null, redirect him to // some other URL. In our case, we just need to implement // that method to return the correct response. return $this->registered($request, $user) ?: redirect($this->redirectPath()); }

Мы просто включим метод registered() в наш RegisterController. Метод принимает $request и $user, и это как раз то что нам нужно. Вот так метод выглядит внутри контроллера:

protected function registered(Request $request, $user) { $user->generateToken(); return response()->json(['data' => $user->toArray()], 201); }

Мы можем подключить его в файле routes

Route::post(register, 'Auth\ [email protected] );

В приведенном выше разделе мы использовали метод модели User для генерации токена. Это полезно, так что у нас есть только один способ генерации токенов. Добавьте в свою модель пользователя следующий метод:

class User extends Authenticatable { ... public function generateToken() { $this->api_token = str_random(60); $this->save(); return $this->api_token; } }

И все.

 

Вот что мы получим обращаясь к конечной точке

$ curl -X POST http://localhost:8000/api/register \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"name": "John", "email": " [email protected] ", "password": "toptal123", "password_confirmation": "toptal123"}' { "data": { "api_token":"0syHnl0Y9jOIfszq11EC2CBQwCfObmvscrZYo5o2ilZPnohvndH797nDNyAT", "created_at": "2017-06-20 21:17:15", "email": " [email protected] ", "id": 51, "name": "John", "updated_at": "2017-06-20 21:17:15" } }

Создание Login

Также как и в случае с регистрацией, мы можем отредактировать LoginController (в папке Auth ) для поддержки API аутентификации. Метод login в трейте AuthenticatesUsers может быть переопределен для поддержки нашей API:

public function login(Request $request) { $this->validateLogin($request); if ($this->attemptLogin($request)) { $user = $this->guard()->user(); $user->generateToken(); return response()->json([ 'data' => $user->toArray(), ]); } return $this->sendFailedLoginResponse($request); }

И также подключим его в routes

Route::post('login', 'Auth\ [email protected] ');

Теперь, предположим, что пользователи у нас существуют

$ curl -X POST localhost:8000/api/login \ -H "Accept: application/json" \ -H "Content-type: application/json" \ -d "{\"email\": \" [email protected] \", \"password\": \"toptal\" }" { "data": { "id":1, "name":"Administrator", "email":" [email protected] ", "created_at":"2017-04-25 01:05:34", "updated_at":"2017-04-25 02:50:40", "api_token":"Jll7q0BSijLOrzaOSm5Dr5hW9cJRZAJKOzvDlxjKCXepwAeZ7JR6YP5zQqnw" } }

Logging Out

В соответствии с нашей текущей стратегией, если токен ошибочен или отсутствует, пользователь должен получить не прошедший валидацию ответ. Поэтому для мы отправим токен, и он будет удален в базе данных.

routes/api.php: Auth\LoginController.php: public function logout(Request $request) { $user = Auth::guard('api')->user(); if ($user) { $user->api_token = null; $user->save(); } return response()->json(['data' => 'User logged out.'], 200);

Используя эту стратегию, любой токен, который есть у пользователя будет недействительным, и API откажет в доступе (используя middlewares, как описано в следующем разделе). Для этого необходимо согласование с клиентской частью(front-end), чтобы пользователь оставался залогиненым, и не имеющим доступа к какому-либо контенту.

Использование Middlewares(Посредников) для запрета доступа.

С созданием api_token, мы можем переключать middleware в файле route :

Route::middleware('auth:api') ->get('/user', function (Request $request) { return $request->user(); });

Мы можем управлять доступом текущего пользователя используя метод $request->user() иил посредством фасада Auth

Auth::guard('api')->user(); // instance of the logged user Auth::guard('api')->check(); // if a user is authenticated Auth::guard('api')->id(); // the id of the authenticated user

И получим результат подобный этому:

Это связано с тем, что нам нужно отредактировать текущий unauthenticated метод в нашем Handler class. Текущая версия возвратит JSON только если запрос будет иметь заголовок Accept: application/json давайте изменим это:

protected function unauthenticated($request, AuthenticationException $exception) { return response()->json(['error' => 'Unauthenticated'], 401); }

Изменив это, можно изменить наши конечные точки статей, обернув их auth:api middleware. Это можно сделать посредством route groups:

Route::group(['middleware' => 'auth:api'], function() { Route::get('articles', ' [email protected] '); Route::get('articles/{article}', ' [email protected] '); Route::post('articles', ' [email protected] '); Route::put('articles/{article}', ' [email protected] '); Route::delete('articles/{article}', ' [email protected] '); });

Таким образом нам не нужно прописывать middleware для каждого маршрута(Route).

В следующей статье Laravel RESTful API. Тестирование  я опишу как тестировать наши конечные точки(endpoints).

 

Оригинал статьи  Laravel API Tutorial: How to Build and Test a RESTful API

rss