6

Laravel Api 开发基础篇

准备工作

创建应用

$ laravel new api-basic

创建数据库

> create database ApiBasic

配置 .env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=ApiBasic
DB_USERNAME=root    
DB_PASSWORD=123456

创建 Lesson 相关

$ php artisan make:model Lesson -rm

编辑迁移

/database/migrations/2017_06_03_052535_create_lessons_table.php
Schema::create('lessons', function (Blueprint $table) {
    $table->increments('id');
    $table->string('title'); // 标题
    $table->text('body'); // 内容
    $table->boolean('free'); // 免费否
    $table->timestamps();
});

执行迁移

$ php artisan migrate

定义模型工厂

/database/factories/ModelFactory.php
$factory->define(App\Lesson::class, function (Faker\Generator $faker) {
    static $password;

    return [
        'title' => $faker->sentence,
        'body'  => $faker->paragraph,
        'free'  => $faker->boolean(),
    ];
});

填充数据

$ php artisan tinker
factory(\App\Lesson::class,50)->create(); 

基本的 Api 认证

定义路由

/routes/api.php
Route::group(['prefix' => 'v1'], function() {
    Route::resource('lessons', 'LessonController');
});
  • api.php 中定义的路由会自动添加 api 前缀;

  • 添加版本 v1 方便进行 api 版本管理;

数据的基本返回 - 取出数据,格式化,然后返回

/app/Http/Controllers/LessonController.php
use App\Lesson;

public function index()
{
    $lessons = Lesson::all();
    return response()->json([
        'status'      => 'success',
        'status_code' => 200,
        'data'        => $this->transforms($lessons->toArray()),
    ]);
}

public function show(Lesson $lesson)
{
    return response()->json([
        'status'      => 'success',
        'status_code' => 200,
        'data'        => $this->transform($lesson->toArray()),
    ]);
}

/**
 * 对多条数据进行格式化
 * @param  array  $lessons [description]
 * @return [type]          [description]
 */
private function transforms(array $lessons)
{
    return array_map([$this, 'transform'], $lessons);
}

/**
 * 对单条数据进行格式化
 * @param  array  $lesson [description]
 * @return [type]         [description]
 */
private function transform(array $lesson)
{
    return [
        'title'   => $lesson['title'],
        'content' => $lesson['body'],
        'is_free' => (bool)$lesson['free'],
    ];
}

测试

  • 访问全部课程 - /api/v1/lessons

  • 访问某一课程 - /api/v1/lessons/2

重构

接下来,考虑的是对上面代码的重构与优化。

Transform Class

首先是数据的转化部分,其他模块也需要用到该功能,因此可以将其抽象出来:

  • 多条数据的转化 - 不同模块用法都相同,都是遍历并每一条数据进行处理;

  • 单条数据的转换 - 不同模块可根据自己的需求定制;

因此,可以使用 PHP 抽象类来实现,创建一个通用的 TransFormer

/app/TransFormer/Transformer.php
<?php

namespace App\Transformer;

abstract class Transformer
{   
    /**
     * 转换多条数据
     * @param  {[type]} array $items        [description]
     * @return {[type]}       [description]
     */
    public function transforms(array $items)
    {
        return array_map([$this, 'transform'], $items);
    }

    abstract public function transform(array $item);
}

然后创建一个 LessonsTransform 来实现对 lessons 数据的转化

/app/TransFormer/LessonsTransformer.php
<?php

namespace App\Transformer;

class LessonsTransform extends Transformer
{
    /**
     * [transform description]
     * @param  array  $lesson [description]
     * @return [type]         [description]
     */
      public function transform(array $lesson)
      {
          return [
            'title'   => $lesson['title'],
            'content' => $lesson['body'],
            'is_free' => (bool) $lesson['free'],
        ];
      }
}

控制器的方法,就可以改成

/app/Http/Controllers/LessonController.php
<?php

namespace App\Http\Controllers;

use App\Lesson;
use App\Transformer\LessonsTransform;
use Illuminate\Http\Request;

class LessonController extends Controller
{
    protected $lessonsTransform;
    public function __construct(LessonsTransform $lessonsTransform)
    {
        $this->lessonsTransform = $lessonsTransform;
    }
   
    public function index()
    {
        $lessons = Lesson::all();
        return response()->json([
            'status'      => 'success',
            'status_code' => 200,
            'data'        => $this->lessonsTransform->transforms($lessons->toArray()),
        ]);
    }
    public function show(Lesson $lesson)
    {
        return response()->json([
            'status'      => 'success',
            'status_code' => 200,
            'data'        => $this->lessonsTransform->transform($lesson->toArray()),
        ]);
    }

}

Api Controller

之前只处理了成功返回的情况,实际上还包含了错误返回、重定向等等,因此可以进一步完善这些功能,我们将其封装到 ApiController 中。

$ php artisan make:controller ApiController

实现

/app/Http/Controllers/ApiController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ApiController extends Controller
{
    private $statusCode = 200;  // 默认返回码

    public function __construct($statusCode)
    {
        $this->statusCode = $statusCode;
    }

    /**
     * 获取返回码
     * @return [int] [description]
     */
    public function getStatusCode()
    {
        return $this->statusCode;
    }

    /**
     * 设置返回码,连贯操作
     * @param [object] $statusCode [description]
     */
    public function setStatusCode($statusCode)
    {
        $this->statusCode = $statusCode;
        return $this;
    }

    /**
     * 基本的响应方法
     * @param  [type] $data [description]
     * @return [type]       [description]
     */
    public function response($data)
    {   
        return response()->json($data);
    }

    /**
     * 错误响应
     * @param  string $message [description]
     * @return [type]          [description]
     */
    public function responseErrors($message = 'Not Found')
    {
        return $this->response([
            'status'      => 'failed',
            'status_code' => $this->getStatusCode(),
            'massage'     => $message
        ]);
    }

    /**
     * 请求数据的成功响应
     * @param  string $message [description]
     * @return [type]          [description]
     */
    public function responseSuccess($data, $message = 'Success')
    {
        return $this->response([
            'status'      => 'success',
            'status_code' => $this->getStatusCode(),
            'massage'     => $message,
            'data'        => $data
        ]);
    }

    /**
     * 不带数据的状态成功响应
     * @param  {String} $message [description]
     * @return {[type]}          [description]
     */
    public function responseOk($message ='Ok')
    {
        return $this->response([
            'status'      => 'success',
            'status_code' => $this->getStatusCode(),
            'massage'     => $message
        ]);
    }
}

控制器可以简化成

/app/Http/Controllers/LessonController.php
<?php

namespace App\Http\Controllers;

use App\Lesson;
use App\Transformer\LessonsTransform;
use Illuminate\Http\Request;

class LessonController extends ApiController
{
    protected $lessonsTransform;
    public function __construct(LessonsTransform $lessonsTransform)
    {
        $this->lessonsTransform = $lessonsTransform;
    }
   
    public function index()
    {
        $lessons = Lesson::all();
        return $this->responseSuccess($this->lessonsTransform->transforms($lessons->toArray()));
    }

    public function show($id)
    {
        $lesson = Lesson::find($id);
        if (!$lesson) {
            return $this->setStatusCode(400)->responseErrors('错误的 id 请求');
        }

        return $this->responseSuccess($this->lessonsTransform->transform($lesson->toArray()));
    }
}

附录


心智极客
1k 声望645 粉丝