李炎恢 Laravel API 接口学习笔记(基于 Laravel Sail 环境)

Laravel框架
503
0
0
2022-05-07

0. 学前准备:

历时三天,成功搭建Laravel Sail环境

2. 创建项目

curl -s https://laravel.build/yanhui | bash

如上所示,我创建一个名为 yanhui 的 Laravel 项目。

在 Terminal 中启动项目:

./vendor/bin/sail up

如图所示:

此时,我用浏览器打开 http://localhost/ ,就可以看到以下画面,说明项目已经成功创建并且启动(这个画面我们不需要更改):

3. 创建用于 API 操作的资源控制器和对应路由

先在 Terminal 终端配置一下 Sail 命令,让它变得简短一点:

alias sail='bash vendor/bin/sail'

然后,使用以下命令创建 API 控制器

sail artisan make:controller UserController --api

--api 参数的意义是,从控制器中排除 createedit 方法。

此处出现在我终端里面的 爆红 提示,是因为我在之前学习的时候已经创建过同名控制器,所以我再次演示就会这个提示,大家无视就好。

最后,我输入 code .,使用 VS code 打开项目文件夹。

整个流程如下图所示:

至此,控制器已经创建好,接下来是对应路由,在创建路由之前,我们我们可以使用 sail artisan route:list 命令来查看一下,当前项目的路由列表是怎样的(如果你是新建的项目,应该会看到如下所示的画面):

接下来,我们打开 routes\api.php 文件,用一下代码,创建资源路由(文件原本的代码我们先不改动,注意顶部引入控制器):

<?php
use App\Http\Controllers\UserController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});
Route::apiResource('user',UserController::class);

可以看到,与原文件相比,我只添加了两句代码:

use App\Http\Controllers\UserController;
Route::apiResource('user',UserController::class);

此时,我们再次在终端中输入 sail artisan route:list 命令,可以看到如下画面:

然后,我们来测试一下:

app\Http\Controllers\UserControllers.php 中,我们修改 index 方法:

public function index()
    {
        return '你好,Laravel~';
    }

然后我们用浏览器打开 http://localhost/api/user

可以看到如下画面:

最后,我们用专业的接口调试软件 Postman 打开http://localhost/api/user

可以看到以下画面:

至此,控制器和路由创建并测试成功。

4. 创建一个专门用于生成 API 的控制类,然后继承并调用它

在终端中使用命令创建控制器:

sail artisan make:controller ApiController

在生成的控制器中,我们编写一个 create 方法:(文件路径:app\Http\Controllers\ApiController.php)

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ApiController extends Controller
{
    protected function create($msg = '', $code = 200, $data = [])
    {
        $result = [
            // 返回状态码  
            'code'=>$code,
            // 返回提示信息  
            'msg'=>$msg,
            // 返回数据  
            'data'=>$data,
        ];
        return response($result);
    }
}

然后,我们修改 UserController.php 文件(文件路径:app\Http\Controllers\UserController.php)

使其继承 ApiController 而不是原本的 Controller,这样我们就可以很自然地调用 create 方法,来生成标准的 API 返回信息。

详情如下:

class UserController extends ApiController
{
    public function index()
    {
        return $this->create('请求成功',200,'你好,Laravel~');
    }

此时,我们用Postman 再次发送请求,可以看到如下画面,说明控制类创建成功。

5. 数据列表和分页

填充用户数据

在本小节,我们将真正编写第一个控制器方法的具体逻辑,但是,对于没有看前置课程的同学来说,我们也将面临一个问题:我们的数据库里面,没有任何数据

好在,这个问题我们可以用 Laravel 的数据填充功能来解决,至于填充的原理,我就不再赘述,只讲怎么做,想进一步了解原理的同学可以阅读 Laravel 文档,或者参考本社区 《L01 Laravel 教程》的第 8 章第 4 小节。

数据填充第一步:创建 seeder 类

sail artisan make:seeder UserSeeder

生成的 UserSeeder 文件位于:database\seeders\UserSeeder.php

让我们编辑其中的 run 方法,如下所示:

<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */ 
    public function run()
    {
        User::factory(50)->create();
    }
}

User::factory(50)->create(); 这句代码会调用用户工厂方法,为我们生成 50 条用户数据。

用户工厂,Laravel 默认自带,文件位于 database\factories\UserFactory.php,保持默认即可,暂时不需要做修改。

然后我们修改 DatabaseSeeder.php 文件中的 run 方法,让其调用我们创建的 UserSeeder 类:

文件位置:database\seeders\DatabaseSeeder.php

<?php
namespace Database\Seeders;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */ 
    public function run()
    {
        Model::unguard();
        $this->call(UserSeeder::class);
        Model::reguard();
    }
}

现在,让我们回到终端中,使用以下命令,生成 Laravel 默认的用户数据表:

sail artisan migrate

接着用以下命令,填充数据

sail artisan db:seed

终端画面如下所示:

至此,数据填充完成,如果你用 Navicat 等工具连接并打开数据库中的 users 表,就可以看到 Laravel 为我们生成的 50 条用户数据,这里就不演示了。

编写 UserController 控制器的 index 方法

数据库有了数据,我们接下来编写的控制器方法才有意义,首先我们来看第一个控制器方法:

文件位置:app\Http\Controllers\UserController.php

public function index()
    {
        // 数据获取  
        // 返回数据

        $data = User::select('id', 'name', 'email')->simplePaginate(10); // 简单分页  
        return $this->create('数据获取成功', 200, $data);
    }

可以看到,我通过查询构造器,从 users 表的每条记录中选出了三个字段,并把所有的记录进行简单分页,每页展示 10 条数据。

用 Postman 进行调试,可以看到如下画面:

可以看到,之前填充的数据,被我们从数据库调出来。

index 方法还有一些其他的写法,这里仅做记录,有兴趣的同学可以自己调试以下写法:

// 获取全部可显示字段
$data = User::get();
// 获取指定字段 
$data = User::select('id','name','email')->get();
// 获取指定字段并分页
$data = User::select('id','name','email')->paginate(10);

至此,查询所有数据并且分页的方法,编写完成。

6. 配置一个 404 的 HTTP 异常,并且用 JSON 格式返回(覆盖系统自带的 404 提示)

Larave 框架自带 404 提示,为什么我们还有重新写一个呢?

因为自带的 404 提示不符合 API 格式,这你让前端很难做事的,所以,我们要重写一个符合 API 格式的 404 提示,覆盖原有的提示。

操作起来也简单,两步走:

  1. 在 resources/views 目录下创建 errors 文件夹
  2. 在 resources/views/errors 目录下创建 404.blade.php 文件,并编写返回的内容

你可以手动创建相关目录和文件,也可以像我一样,在终端中使用命令来创建:

mkdir resources/views/errors && touch resources/views/errors/404.blade.php

同样,因为我在之前已经创建过,所以,此时演示的时候,提示文件夹已存在。

接下来我们开始编写 resources/views/errors 目录下的 404.blade.php 文件,很简单,以下就是文件的全部内容:

<?php
$result = [
    // 返回状态码  
    'code' => 404,
    // 返回提示信息  
    'msg' => '资源不存在',
    // 返回数据  
    'data' => [],
];
echo json_encode($result);

接下来我们在 Postman 里面调试一下,填入一个不存在的路径,看看是不是我们自己编写的 404 提示(如果各位的信息显示有点乱的话,可以注意我标记红框的位置):

7. 展示单个数据 API

展示单个数据,对应的是控制器的 show 方法,通过传入的 $id 来返回对应的用户信息。

但是根据 web 开发工程师第一准则:永远不要相信用户输入的数据

所以我们要考虑更多的东西,比如:

  • 我们要求用户传入的参数是数字,但是用户扔给我们一个单词,我们该怎么办?
  • 现在我们数据库里面数值的范围在 1 - 50 之内,用户给我们抛个 100 过来,超出了我们的数据范围,我们又该返回什么样的信息呢?

所以,show 方法编写如下,具体的思路请看注释部分文字:

文件位置: app\Http\Controllers\UserControllers.php

public function show($id)
    {
        // 获取数据  
        // 数据存在 返回成功信息  
        // 数据不存在  
        // 参数超出范围导致数据不存在  
        // 参数类型错误导致数据不存在

        $data = User::select('id', 'name', 'email')->find($id);

        if (isset($data)) {
            return $this->create('数据获取成功', 200, $data);
        } else {
            if (is_numeric($id)) {
                return $this->create('用户不存在', 204, []);
            } else {
                return $this->create('id 参数错误', 400, []);
            }
        }
    }

Postman 调试如下(正确参数):

非数字参数:

超范围参数:

8. 新增数据 API

新增数据对应的控制器方法,是 store 方法,这部分代码我写的与原视频里面有些不同,主要区别就是在讲数据存入数据库的时候,我将密码用 md5() 函数进行加密,虽然这种方式也比较朴素,但是,起码数据库里面的数据不再是赤裸裸的 123456 了,这是什么?这就是进步啊~

文件位置: app\Http\Controllers\UserControllers.php

编码如下:

public function store(Request $request)
    {
        // 接收数据  
        $data = $request->all();
        // 数据验证  
        $validator = Validator::make($data, [
            'name' => 'required|min:2|max:50',
            'email' => 'required|min:2|max:50|email',
            'password' => 'required|min:6|max:50',
        ]);
        if ($validator->fails()) {
            return $this->create($validator->errors(), 400);
        } else {
            $newUser = User::create([
                'name' => $request->name,
                'email' => $request->email,
                'password' => md5($request->password),
            ]);
            $newUser = User::select('id', 'name', 'email')->find($newUser['id']);
            return $this->create('用户创建成功', 200, $newUser);
        }
    }

关于数据验证代码的解析请看原视频,或者参考本社区 《L01 Laravel 教程》的第 8 章第 4 小节。或者参考本社区 《L01 Laravel 教程》的第 6 章,此处点到为止。

以下是 Postman 调试环节,请注意我标红框的部分,都是细节哦:

9. 删除数据 API

有增加就有删除,就连后端人员的自嘲——增删改查工程师 的头两个字,也是

删除数据对应的控制器方法,是 destroy 方法,其逻辑与增加数据很相似。

文件位置: app\Http\Controllers\UserControllers.php

编码如下:

public function destroy($id)
    {
        // 获取数据  
        // 数据存在,删除  
        // 数据不存在  
        // 参数超出范围导致数据不存在  
        // 参数类型错误导致数据不存在  
        $data = User::find($id);
        if (isset($data)) {
            if ($data->delete()) {
                return $this->create('用户删除成功', 200);
            }
        } else {
            if (is_numeric($id)) {
                return $this->create('用户不存在,无法删除', 204, []);
            } else {
                return $this->create('id 参数错误', 400, []);
            }
        }
    }

但是,要注意一点,在实际的生产环境中,无论我们多么想删除数据库里面的数据,事实上我们都不会删,因为我们受过专业的训练(毒打)。

那么,如何让存在数据里面的数据,看起来像是“被删除”的样子呢?

答案是增加一个 状态字段,如果一条数据的状态字段的值是 1,代表这是一条正常的记录;如果是 -1 或者其它值,代表这是一条已经被删除的记录,没有权限的人是查不到这条记录的。

由此,引申出web工程师第二准则:永远不要删除生产环境的数据。(除非你想搞破坏)

接下来是 Postman 调试(就删除我们刚刚创建的第 51 号用户好了):

此时如果我们打开数据库,发现第 51 条记录已经没有了,再次提示,这只是在本地开发环境的学习过程,在生产环境中,任何与删除有关的动作都是很危险的,一定要慎之又慎。

10. 修改数据 API

在原视频中,是没有这部分内容的,但是,出来混,要讲信用,说了增删改查工程师,就要增删改查,一个都不能少。

以下是我通过自己的理解写出来的,还是那就说话,如果有更好的写法,请在评论区 show you code

文件位置: app\Http\Controllers\UserControllers.php

编码如下:

public function update(Request $request, $id)
    {
        // 接收数据  
        // 验证数据  
        // 查找用户  
        // 如果用户不存在  
        // 更新并返回信息  
        $data = $request->all();
        $validator = Validator::make($data, [
            'name' => 'required|min:2|max:50',
            'password' => 'required|min:6|max:50',
        ]);
        if ($validator->fails()) {
            return $this->create($validator->errors(), 400);
        }
        $user = User::find($id);
        if (isset($user)) {
            if ($user->update([
                'name' => $request->name,
                'password' => md5($request->password),
            ])) {
                return $this->create('用户更新成功', 200);
            }
        } else {
            if (is_numeric($id)) {
                return $this->create('用户不存在,无法更新', 204, []);
            } else {
                return $this->create('id 参数错误', 400, []);
            }
        }
    }

代码思路请看注释文字,以下是 Postman 调试时间:

查找第一个用户的信息如下:

然后调用api,修改 1 号用户的 name 和 password 信息:

最后,再次查看,可以看到,已经修改成功:

至此,整个课程笔记已经结束。

因为之前的代码是分块编写并解释,观感并不是很好,所以在附录部分,贴上 app\Http\Controllers\UserControllers.php 的完整代码,供大家参考,以免出错。

附录

完整的app\Http\Controllers\UserControllers.php 如下:

<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Auth\Events\Validated;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class UserController extends ApiController
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */ 
    public function index()
    {
        // 数据获取  
        // 返回数据

        $data = User::select('id', 'name', 'email')->simplePaginate(10); // 简单分页  
        return $this->create('数据获取成功', 200, $data);

        // 数据获取的其它写法举例  
        // 获取全部可显示字段  
        // $data = User::get();  
        // 获取指定字段   
        // $data = User::select('id','name','email')->get();  
        // 获取指定字段并分页  
        // $data = User::select('id','name','email')->paginate(10);
    }
    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */ 
    public function store(Request $request)
    {
        // 接收数据  
        $data = $request->all();
        // 数据验证  
        $validator = Validator::make($data, [
            'name' => 'required|min:2|max:50',
            'email' => 'required|min:2|max:50|email',
            'password' => 'required|min:6|max:50',
        ]);
        if ($validator->fails()) {
            return $this->create($validator->errors(), 400);
        } else {
            $newUser = User::create([
                'name' => $request->name,
                'email' => $request->email,
                'password' => md5($request->password),
            ]);
            $newUser = User::select('id', 'name', 'email')->find($newUser['id']);
            return $this->create('用户创建成功', 200, $newUser);
        }
    }
    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */ 
    public function show($id)
    {
        // 获取数据  
        // 数据存在 返回成功信息  
        // 数据不存在  
        // 参数超出范围导致数据不存在  
        // 参数类型错误导致数据不存在

        $data = User::select('id', 'name', 'email')->find($id);
        if (isset($data)) {
            return $this->create('数据获取成功', 200, $data);
        } else {
            if (is_numeric($id)) {
                return $this->create('用户不存在', 204, []);
            } else {
                return $this->create('id 参数错误', 400, []);
            }
        }
    }
    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */ 
    public function update(Request $request, $id)
    {
        // 接收数据  
        // 验证数据  
        // 查找用户  
        // 如果用户不存在  
        // 更新并返回信息  
        $data = $request->all();
        $validator = Validator::make($data, [
            'name' => 'required|min:2|max:50',
            'password' => 'required|min:6|max:50',
        ]);
        if ($validator->fails()) {
            return $this->create($validator->errors(), 400);
        }
        $user = User::find($id);
        if (isset($user)) {
            if ($user->update([
                'name' => $request->name,
                'password' => md5($request->password),
            ])) {
                return $this->create('用户更新成功', 200);
            }
        } else {
            if (is_numeric($id)) {
                return $this->create('用户不存在,无法更新', 204, []);
            } else {
                return $this->create('id 参数错误', 400, []);
            }
        }
    }
    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */ 
    public function destroy($id)
    {
        // 获取数据  
        // 数据存在,删除  
        // 数据不存在  
        // 参数超出范围导致数据不存在  
        // 参数类型错误导致数据不存在  
        $data = User::find($id);
        if (isset($data)) {
            if ($data->delete()) {
                return $this->create('用户删除成功', 200);
            }
        } else {
            if (is_numeric($id)) {
                return $this->create('用户不存在,无法删除', 204, []);
            } else {
                return $this->create('id 参数错误', 400, []);
            }
        }
    }
}

完结,撒花,感谢阅读。