Laravel5.5更新,通过Laravel5.5开发Api更加顺畅了,在这里就分享一下Laravel开发Api的经验吧
返回的自定义消息,和错误消息,我自己封装了一个Trait,用来做基本的返回,Trait的封装如下
namespace App\Api\Helpers\Api;
use Symfony\Component\HttpFoundation\Response as FoundationResponse;
use Response;
trait ApiResponse
{
/**
* @var int
*/
protected $statusCode = FoundationResponse::HTTP_OK;
/**
* @return mixed
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* @param $statusCode
* @return $this
*/
public function setStatusCode($statusCode)
{
$this->statusCode = $statusCode;
return $this;
}
/**
* @param $data
* @param array $header
* @return mixed
*/
public function respond($data, $header = [])
{
return Response::json($data,$this->getStatusCode(),$header);
}
/**
* @param $status
* @param array $data
* @param null $code
* @return mixed
*/
public function status($status, array $data, $code = null){
if ($code){
$this->setStatusCode($code);
}
$status = [
'status' => $status,
'code' => $this->statusCode
];
$data = array_merge($status,$data);
return $this->respond($data);
}
/**
* @param $message
* @param int $code
* @param string $status
* @return mixed
*/
public function failed($message, $code = FoundationResponse::HTTP_BAD_REQUEST, $status = 'error'){
return $this->setStatusCode($code)->message($message,$status);
}
/**
* @param $message
* @param string $status
* @return mixed
*/
public function message($message, $status = "success"){
return $this->status($status,[
'message' => $message
]);
}
/**
* @param string $message
* @return mixed
*/
public function internalError($message = "Internal Error!"){
return $this->failed($message,FoundationResponse::HTTP_INTERNAL_SERVER_ERROR);
}
/**
* @param string $message
* @return mixed
*/
public function created($message = "created")
{
return $this->setStatusCode(FoundationResponse::HTTP_CREATED)
->message($message);
}
/**
* @param $data
* @param string $status
* @return mixed
*/
public function success($data, $status = "success"){
return $this->status($status,compact('data'));
}
/**
* @param string $message
* @return mixed
*/
public function notFond($message = 'Not Fond!')
{
return $this->failed($message,Foundationresponse::HTTP_NOT_FOUND);
}
}
然后创建一个ApiController,通过所有的Api控制器继承该控制器,实现简洁的Api返回
<?php
namespace App\Http\Controllers\Api;
use App\Api\Helpers\Api\ApiResponse;
use App\Http\Controllers\Controller;
class ApiController extends Controller
{
use ApiResponse;
// 其他通用的Api帮助函数
}
然后,Api控制器就可以简洁的返回
<?php
namespace App\Http\Controllers\Api;
class IndexController extends ApiController
{
public function index(){
return $this->message('请求成功');
}
}
资源返回通过5.5的新特性,API资源实现,具体参见
https://d.laravel-china.org/docs/5.5/eloquent-resources
使用方面比之前的Transformer方式更好用更优雅
比如返回用户的分页数据,只需要这样
文档已经很详细了,这里不再做概述
<?php
namespace App\Http\Controllers\Api;
use App\Models\User;
use App\Http\Resources\User as UserCollection;
use Illuminate\Support\Facades\Input;
class IndexController extends ApiController
{
public function index(){
return UserCollection::collection(User::paginate(Input::get('limit') ?: 20));
}
}
这里直接抛弃之前的jwt转向passport的认证方式,之前论坛已经有相关认证的帖子了
这里通过重写AuthenticatesUsers
通过password
的的授权模式模式进行实现
<?php
namespace App\Http\Controllers\Api;
use Carbon\Carbon;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
use Laravel\Passport\Client;
use Socialite;
use App\Models\User;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Validator;
class AuthenticateController extends ApiController
{
use AuthenticatesUsers;
public function __construct()
{
$this->middleware('auth:api')->only([
'logout'
]);
}
public function username()
{
return 'phone';
}
// 登录
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'phone' => 'required|exists:user',
'password' => 'required|between:5,32',
]);
if ($validator->fails()) {
$request->request->add([
'errors' => $validator->errors()->toArray(),
'code' => 401,
]);
return $this->sendFailedLoginResponse($request);
}
$credentials = $this->credentials($request);
if ($this->guard('api')->attempt($credentials, $request->has('remember'))) {
return $this->sendLoginResponse($request);
}
return $this->setStatusCode(401)->failed('登录失败');
}
// 退出登录
public function logout(Request $request)
{
if (Auth::guard('api')->check()){
Auth::guard('api')->user()->token()->revoke();
}
return $this->message('退出登录成功');
}
// 第三方登录
public function redirectToProvider($driver) {
if (!in_array($driver,['qq','wechat'])){
throw new NotFoundHttpException;
}
return Socialite::driver($driver)->redirect();
}
// 第三方登录回调
public function handleProviderCallback($driver) {
$user = Socialite::driver($driver)->user();
$openId = $user->id;
// 第三方认证
$db_user = User::where('xxx',$openId)->first();
if (empty($db_user)){
$db_user = User::forceCreate([
'phone' => '',
'xxUnionId' => $openId,
'nickname' => $user->nickname,
'head' => $user->avatar,
]);
}
// 直接创建token
$token = $db_user->createToken($openId)->accessToken;
return $this->success(compact('token'));
}
//调用认证接口获取授权码
protected function authenticateClient(Request $request)
{
$credentials = $this->credentials($request);
// 个人感觉通过.env配置太复杂,直接从数据库查更方便
$password_client = Client::query()->where('password_client',1)->latest()->first();
$request->request->add([
'grant_type' => 'password',
'client_id' => $password_client->id,
'client_secret' => $password_client->secret,
'username' => $credentials['phone'],
'password' => $credentials['password'],
'scope' => ''
]);
$proxy = Request::create(
'oauth/token',
'POST'
);
$response = \Route::dispatch($proxy);
return $response;
}
protected function authenticated(Request $request)
{
return $this->authenticateClient($request);
}
protected function sendLoginResponse(Request $request)
{
$this->clearLoginAttempts($request);
return $this->authenticated($request);
}
protected function sendFailedLoginResponse(Request $request)
{
$msg = $request['errors'];
$code = $request['code'];
return $this->setStatusCode($code)->failed($msg);
}
}
这里我的做法是直接拦截App\Exceptions\Handler
的render
方法,实现自定义返回
<?php
namespace App\Exceptions;
use App\Api\Helpers\Api\ExceptionReport;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* 其他代码...
*/
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
// 将方法拦截到自己的ExceptionReport
$reporter = ExceptionReport::make($exception);
if ($reporter->shouldReturn()){
return $reporter->report();
}
return parent::render($request, $exception);
}
}
然后在该方法实现自定义返回
<?php
namespace App\Api\Helpers\Api;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
class ExceptionReport
{
use ApiResponse;
/**
* @var Exception
*/
public $exception;
/**
* @var Request
*/
public $request;
/**
* @var
*/
protected $report;
/**
* ExceptionReport constructor.
* @param Request $request
* @param Exception $exception
*/
function __construct(Request $request, Exception $exception)
{
$this->request = $request;
$this->exception = $exception;
}
/**
* @var array
*/
public $doReport = [
AuthenticationException::class => ['未授权',401],
ModelNotFoundException::class => ['改模型未找到',404]
];
/**
* @return bool
*/
public function shouldReturn(){
if (! ($this->request->wantsJson() || $this->request->ajax())){
return false;
}
foreach (array_keys($this->doReport) as $report){
if ($this->exception instanceof $report){
$this->report = $report;
return true;
}
}
return false;
}
/**
* @param Exception $e
* @return static
*/
public static function make(Exception $e){
return new static(\request(),$e);
}
/**
* @return mixed
*/
public function report(){
$message = $this->doReport[$this->report];
return $this->failed($message[0],$message[1]);
}
}
好啦,所有的基础模块都构建完了,现在就可以开发你需要的业务逻辑啦~
个人博客地址:https://www.timenotes.me/articles/code/11
欢迎大佬参观~~~
Original url: Access
Created at: 2018-10-10 14:18:15
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论