Мини API на Lumen

от автора

image

Цель этой публикации — создание простого API на Lumen и рассмотрение его отличий от старшего брата. Весь код доступен здесь.

Устанавливал я его на бокс homestead, т.ч. управился одной строчкой:

composer create-project laravel/lumen --prefer-dist Lumen 

Подробнее о homestead.

Структура проекта похожа на Laravel:

image

Бросается в глаза отсутствие папки /config. Дело в том, что Lumen полностью полагается на содержимое .env файла. Пример содержимого:

DB_CONNECTION=mysql DB_USERNAME=homestead DB_PASSWORD=secret DB_DATABASE=lumen 

Все возможные настройки можно подглядеть в vendor/laravel/lumen-framework/config/.

Итак,

Структура БД

Допустим, нам нужна сущность пост, плюс 2 метода — регистрация и логин.
Для создания миграций воспользуемся командной утилитой artisan.

php artisan make:migration create_users_table php artisan make:migration create_posts_table 

Теперь в папке /database лежит 2 новых файла. В каждом по 2 метода, up и down — миграция и отмена миграции.
Так выглядит метод up у таблицы users:

//database/*create_users_table.php Schema::create('users', function (Blueprint $table) {     $table->increments('id');     $table->string('email')->unique();     $table->string('first_name');     $table->string('last_name');     $table->string('password');     $table->rememberToken();     $table->timestamps();     $table->softDeletes(); }); 

Для постов:

//database/*create_posts_table.php Schema::create('posts', function (Blueprint $table) {     $table->increments('id');     $table->string('user_id');     $table->string('content');     $table->timestamps();     $table->softDeletes(); }); 

Миграции готовы, пытаемся их применить:

php artisan migrate 

Но артисан почему-то не видит переменные из .env файла и жалуется на плохие параметры подключения. Для того, чтобы экспортнуть переменные, нужно раскомментировать строчку в /bootstrap/app.php:

Dotenv::load(__DIR__.'/../'); 

Также по-умолчанию выключен ORM Eloquent и фасады. Штуки полезные, поэтому я их тоже включил.
Теперь всё должно получится:

image
(art — это alias для php artisan)

Также создадим Eloquent модели для этих таблиц. Например, модель поста:

use Illuminate\Database\Eloquent\Model;  class Post extends Model {     /**      * @return \Illuminate\Database\Eloquent\Relations\BelongsTo      */     public function user()     {         return $this->belongsTo('Written\Models\User');     } } 

Модели позволяют с меньшей болью отдавать данные с методов, т.к. они заботятся о взаимосвязи таблиц. Конечно, производительность «сырых» запросов к бд лучше, но скорость разработки при таком подходе будет неуклонно деградировать. Такие запросы уместны, на мой взгляд, только для статистических выборок.

Контроллеры

В Laravel 5 есть замечательный Trait, который позволяет сделать всю регистрацию в два щелчка пальцев. К сожалению в Lumen такого нет. Также сейчас принято не записывать все роуты в один файл, а пользоваться аннотациями, например:

/**  * @Middleware("auth.token")  * @Resource('post')  */ class PostsController extends Controller {     public function index() {}     public function show($id) {}     public function store() {}     public function update() {}     public function destroy() {} } 

Данная аннотация говорит, что контроллер RESTful. Т.о. имея перед глазами 1 открытый файл уже есть понимание, как обращаться к методам, и что за фильтры они имеют. Делается это с помощью либы laravelcollective/annotations. Но с Lumen она несовместима, поэтому все роуты придется пихать в /app/http/routes.php:

$app->get('/', function() use ($app) {     return $app->welcome(); }); $app->post('/register', ['uses' => 'App\Http\Controllers\AuthController@postRegister']); $app->post('/login', ['uses'    => 'App\Http\Controllers\AuthController@postLogin']);  $app->get('/post/{id}', ['uses' => 'App\Http\Controllers\PostsController@show']); $app->get('/post',      ['uses' => 'App\Http\Controllers\PostsController@index']); $app->group(['middleware' => 'logged.in'], function($app) {     $app->post('/post',     ['uses' => 'App\Http\Controllers\PostsController@store']);     /** & another protected routes */ }); 

В нормальном приложении этот файл становится монструозным быстро.

У Lumen, как и у Laravel, есть Middleware, которые могут либо фильтровать определенные запросы, либо делать всякие полезности для каждого запроса. Все такие фильтры лежат в /app/Http/Middleware/. Для того, чтобы Lumen знал об их существовании, нужно добавить соответствующие классы в /bootstrap.app.php.

Пример Middleware:

//app/Http/Middlewared/LoggedInMiddleware.php class LoggedInMiddleware {     /**      * Handle an incoming request.      *      * @param  \Illuminate\Http\Request  $request      * @param  \Closure  $next      * @return mixed      */     public function handle($request, Closure $next)     {         if(!Auth::check()) {             return new Response('', 401);         }          return $next($request);     } } 

Описанный фильтр выдаёт http код 401, если запрос исходит от неавторизованного пользователя.

Пример контроллера:

//app/Http/Controller/PostsController.php /**  * Class PostsController  * @package App\Http\Controllers  */ class PostsController extends Controller {     public function index()     {         return $this->respondWithData(Post::with('user')->all()->toArray());     }      public function show($id)     {         return $this->respondWithData(Post::find($id)->with('user')->get()->toArray());     }      public function store()     {         $rules = [             'text' => 'required',         ];          $input = $_POST;          $validator = Validator::make($input, $rules);         if ($validator->fails()) {             return $this->respondWithFailedValidation($validator);         }          $post = new Post;         $post->content = $input['content'];         $post->user()->associate(Auth::user());         $post->save();          return $this->show($post->id);     }  //    public function delete() {} } 

Пример профита от использования Eloquent можно увидеть в методе show(). Клиенту отдаётся не только информация о посте, но также об ассоциированном пользователе.

respondWith* методы — вспомогательные, для придания коду какой-то организованности. В целом метод может возвращать даже обычную строку.

Заключение

Не зря заявлено, что Lumen полностью совместим с Laravel, т.к. после всего написанного я не чувствую, что написал что-то про Lumen.

Но всё же при разработке даже вышеописанного функционала остался осадочек:
— несовместим с библиотеками, написанными для Laravel. Те же аннотации де-факто стандарт;
— для вхождения нужно знать Laravel, т.к. многое, описанное в доках Laravel не работает, а в доках Lumen написано мало. Приходится смотреть исходники. Например фасады — доступно далеко не все. Недостающие нужно регистрировать самому, ручками;
— завести тесты у меня не удалось, т.к. почему-то в метод не прилетает $_POST.

У меня только одиндва вопроса — зачем нужен Lumen, когда есть Laravel? Разве есть люди, которые хотят мегапроизводительности и при этом не пишут своё решение?

ссылка на оригинал статьи http://habrahabr.ru/post/257073/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *