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()));
}
}
附录
学习交流 QQ 群 – 416179157