关键词搜索

源码搜索 ×
×

Laravel文档阅读笔记-How to Build a Rest API with Laravel: A Beginners Guide①

发布2023-01-16浏览1615次

详情内容

 

随着移动端和JavaScript框架的发展,比如React和Vue,Restful风格的API越来越流行。使用Restful风格的好处就是一个后端程序可以与多个版本的前端用户界面关联。

Laravel提供了创建Rest API的环境和生态。

首先得导入依赖包比如Laravel Passport和Laravel Sanctum,这两个包提供了Restful API的权限功能,并且使用起来非常简单。

Laravel Breeze包提供了重置密码的模版功能。

Socialite和Scout提供了登陆和查找功能。

Laravel生态圈提供了程序员开发程序时遇到问题的所有解决方案,为开发人员提供最大的开发效率。

此篇教材展示了如何创建Laravel Rest API,并且使用Sanctum进行权限认证。

Resful API是什么?

Resful其实是一种传输状态,是应用间的一种交流方式,这种方式使用了HTTP协议。这种方式是无状态的,短连接的方式,并且不存储seswsion。每个请求都需要像新请求的情况进行处理。

Restful API的好处就是他方便缓存。返回的数据从Redis或Memcached中获取是非常方便的。

一个API是否是Restful分割的,需要满足如下2点:

  • 能够使用URL或Endpoint进行访问;
  • 能够使用Restful方法;
  • 使用HTTP头;
  • 必须返回有效的相应diam

通常Restful方法有如下几种:

GET:获取数据;

POST:新增数据;

PUT/PATCH:更新数据;

DELETE:删除数据;

如何使用Laravel创建REST API

首先创建一个Laravel应用。

laravel new rest 

然后创建model和migration,在这个实例中,使用Products来代表资源。

php artisan make:model Products -m 

-m标签会让Laravel去创建Products模型对应的数据库迁移文件。

下面是模型文件:

  1. //App/Models/Products
  2. <?php
  3. namespace App\Models;
  4. use Illuminate\Database\Eloquent\Factories\HasFactory;
  5. use Illuminate\Database\Eloquent\Model;
  6. class Products extends Model
  7. {
  8. use HasFactory;
  9. }

下面是模型文件对应的数据库迁移文件:

  1. <?php
  2. use Illuminate\Database\Migrations\Migration;
  3. use Illuminate\Database\Schema\Blueprint;
  4. use Illuminate\Support\Facades\Schema;
  5. return new class extends Migration
  6. {
  7. /**
  8. * Run the migrations.
  9. *
  10. * @return void
  11. */
  12. public function up()
  13. {
  14. Schema::create('products', function (Blueprint $table) {
  15. $table->id();
  16. $table->timestamps();
  17. });
  18. }
  19. /**
  20. * Reverse the migrations.
  21. *
  22. * @return void
  23. */
  24. public function down()
  25. {
  26. Schema::dropIfExists('products');
  27. }
  28. };

这里需要手动更新下迁移文件,在文件中添加字段也就是列,这也数据库中也会有对应的字段和列。在Products这个表中添加name、price、description。

  1. <?php
  2. use Illuminate\Database\Migrations\Migration;
  3. use Illuminate\Database\Schema\Blueprint;
  4. use Illuminate\Support\Facades\Schema;
  5. return new class extends Migration
  6. {
  7. /**
  8. * Run the migrations.
  9. *
  10. * @return void
  11. */
  12. public function up()
  13. {
  14. Schema::create('products', function (Blueprint $table) {
  15. $table->id();
  16. $table->string('name');
  17. $table->double('price');
  18. $table->longText('description');
  19. $table->timestamps();
  20. });
  21. }
  22. /**
  23. * Reverse the migrations.
  24. *
  25. * @return void
  26. */
  27. public function down()
  28. {
  29. Schema::dropIfExists('products');
  30. }
  31. };

随后在Products模型中将name、price、description注册下。好处是使得数据库字段名和类名一一对应,这样能有效的防止SQL注入,比较安全。

  1. //App/Models/Products
  2. <?php
  3. namespace App\Models;
  4. use Illuminate\Database\Eloquent\Factories\HasFactory;
  5. use Illuminate\Database\Eloquent\Model;
  6. class Products extends Model
  7. {
  8. use HasFactory;
  9. protected $fillable = [
  10. 'name', 'price', 'description'
  11. ];
  12. }

随后在.env文件中添加数据库认证信息:

  1. DB_CONNECTION=mysql
  2. DB_HOST=127.0.0.1
  3. DB_PORT=3306
  4. DB_DATABASE=laravel-rest
  5. DB_USERNAME=root
  6. DB_PASSWORD=password

最后一步是将Products表迁移到数据库里面:

php artisan migrate 

创建数据库Seeder和Factory

在开发的时候需要一些虚拟数据,这也程序员开发起来就比较方便快捷。Laravel提供了Factory facade,并且使用Faker生成仿真数据。

使用下面的命令创建Factory。

php artisan make:factory ProductsFactory

这个文件会在databases/factories文件夹被创建。

这里需要更新下这个文件,改成如下:

  1. //database/factories/ProductsFactory
  2. <?php
  3. namespace Database\Factories;
  4. use Illuminate\Database\Eloquent\Factories\Factory;
  5. /**
  6. * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Products>
  7. */
  8. class ProductsFactory extends Factory
  9. {
  10. /**
  11. * Define the model's default state.
  12. *
  13. * @return array<string, mixed>
  14. */
  15. public function definition()
  16. {
  17. return [
  18. 'name' => $this->faker->word,
  19. 'price' => $this->faker->numberBetween(1, 99),
  20. 'description' => $this->faker->sentence()
  21. ];
  22. }
  23. }

现在factory已经准备好了,下面就是在DatabaseSeeder文件中进行seed。

  1. //database/seeders/DatabaseSeeder
  2. <?php
  3. namespace Database\Seeders;
  4. // use Illuminate\Database\Console\Seeds\WithoutModelEvents;
  5. use Illuminate\Database\Seeder;
  6. class DatabaseSeeder extends Seeder
  7. {
  8. /**
  9. * Seed the application's database.
  10. *
  11. * @return void
  12. */
  13. public function run()
  14. {
  15. \App\Models\Products::factory(10)->create();
  16. }
  17. }

使用下面的命令进行seed。

php artisan db:seed

创建控制器

下面创建Products的控制器,这个控制器里面需要编写对于的逻辑,使用下面的命令进行创建。

php artisan make:controller ProductsController -r

-r参数代表resourceful,他会创建http相关的通用请求。

请求包括index、show、store、update、destory,对于这些方法,可以删除、创建、编辑他们,他们并不是都需要,也并不是非要这样命名。下面将Products控制器写成如下。

  1. //App/Http/Controllers/ProductsController
  2. <?php
  3. namespace App\Http\Controllers;
  4. use App\Http\Resources\ProductResource;
  5. use App\Models\Products;
  6. use Illuminate\Http\Request;
  7. class ProductsController extends Controller
  8. {
  9. /**
  10. * Display a listing of the resource.
  11. *
  12. * @return \Illuminate\Http\Response
  13. */
  14. public function index()
  15. {
  16. //
  17. }
  18. /**
  19. * Store a newly created resource in storage.
  20. *
  21. * @param \Illuminate\Http\Request $request
  22. * @return \Illuminate\Http\Response
  23. */
  24. public function store(Request $request)
  25. {
  26. //
  27. }
  28. /**
  29. * Display the specified resource.
  30. *
  31. * @param Products $product
  32. * @return \Illuminate\Http\Response
  33. */
  34. public function show(Products $product)
  35. {
  36. //
  37. }
  38. /**
  39. * Update the specified resource in storage.
  40. *
  41. * @param \Illuminate\Http\Request $request
  42. * @param Products $product
  43. * @return \Illuminate\Http\Response
  44. */
  45. public function update(Request $request, Products $product)
  46. {
  47. //
  48. }
  49. /**
  50. * Remove the specified resource from storage.
  51. *
  52. * @param Products $product
  53. * @return \Illuminate\Http\Response
  54. */
  55. public function destroy(Products $product)
  56. {
  57. //
  58. }
  59. }

上面的方法和HTTP中的get、post、patch/put、delete对应。

Index(获取所有产品)

此方法中返回数据库中的所有products:

  1. use App\Models\Products;
  2. public function index()
  3. {
  4. return Products::all();
  5. }

Show(获取一个产品)

此方法从数据库中获取一个产品,并返回给前端。

通过产品id这个参数获取指定的产品

注意:下面使用的ProductResource()函数,是获取指定产品的,在文章后面将会给出这个函数的详细代码:

  1. use App\Http\Resources\ProductResource;
  2. use App\Models\Products;
  3. public function show(Products $product)
  4. {
  5. return new ProductResource($product);
  6. }

Store(新增一条产品记录)

使用此方法在数据库中新增一记录,这里使用的是HTTP的post方法。代码如下:

  1. use App\Http\Resources\ProductResource;
  2. use App\Models\Products;
  3. public function store(Request $request)
  4. {
  5. $product_name = $request->input('name');
  6. $product_price = $request->input('price');
  7. $product_description = $request->input('description');
  8. $product = Products::create([
  9. 'name' => $product_name,
  10. 'price' => $product_price,
  11. 'description' => $product_description,
  12. ]);
  13. return response()->json([
  14. 'data' => new ProductResource($product)
  15. ], 201);
  16. }

Update(更新产品信息)

更新产品的名字、价格、描述信息,具体的逻辑代码如下:

  1. use App\Http\Resources\ProductResource;
  2. use App\Models\Products;
  3. public function update(Request $request, Products $product)
  4. {
  5. $product_name = $request->input('name');
  6. $product_price = $request->input('price');
  7. $product_description = $request->input('description');
  8. $product->update([
  9. 'name' => $product_name,
  10. 'price' => $product_price,
  11. 'description' => $product_description,
  12. ]);
  13. return response()->json([
  14. 'data' => new ProductResource($product)
  15. ], 200);
  16. }

Destroy(删除一条产品记录)

如下代码所示:

  1. use App\Models\Products;
  2. public function destroy(Products $product)
  3. {
  4. $product->delete();
  5. return response()->json(null,204);
  6. }

Routes&EndPoints

下面创建EndPoints,这样就能进行HTTP访问了,在routes/api.php中新增如下代码:

  1. //routes/api.php
  2. <?php
  3. use App\Http\Controllers\ProductsController;
  4. use Illuminate\Http\Request;
  5. use Illuminate\Support\Facades\Route;
  6. /*
  7. |--------------------------------------------------------------------------
  8. | API Routes
  9. |--------------------------------------------------------------------------
  10. |
  11. | Here is where you can register API routes for your application. These
  12. | routes are loaded by the RouteServiceProvider within a group which
  13. | is assigned the "api" middleware group. Enjoy building your API!
  14. |
  15. */
  16. Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
  17. return $request->user();
  18. });
  19. Route::get('products', [ProductsController::class, 'index'])->name('products.index');
  20. Route::get('products/{product}', [ProductsController::class, 'show'])->name('products.show');
  21. Route::post('products', [ProductsController::class, 'store'])->name('products.store');
  22. Route::put('products/{product}', [ProductsController::class, 'update'])->name('products.update');
  23. Route::delete('products/{product}', [ProductsController::class, 'destroy'])->name('products.destroy');

上面的Endpoints和ProductsController中方法是对应的。

下面测试下ProductsController中的index函数,是HTTP的Get请求,返回值如下:

  1. [
  2. {
  3. "id": 1,
  4. "name": "quo",
  5. "price": 15,
  6. "description": "Ut rerum aut deleniti eveniet ad et ullam perferendis.",
  7. "created_at": "https://files.jxasp.com:9443/image/2022-11-18T15:18:13.000000Z",
  8. "updated_at": "https://files.jxasp.com:9443/image/2022-11-18T15:18:13.000000Z"
  9. },
  10. {
  11. "id": 2,
  12. "name": "maxime",
  13. "price": 70,
  14. "description": "Natus officiis repellat vero ea voluptatem mollitia similique.",
  15. "created_at": "https://files.jxasp.com:9443/image/2022-11-18T15:18:13.000000Z",
  16. "updated_at": "https://files.jxasp.com:9443/image/2022-11-18T15:18:13.000000Z"
  17. }
  18. ]

格式化响应

上面的响应是以Json格式返回的,内容包括了数据库中的所有列。

如果想返回指定的列。比如不需要返回created_at,update_at,以及关于商品打折的信息。所有就需要定制下响应。创建响应类:

php artisan make:resource ProductResource

改变下返回数组。

  1. //App/Http/Resources/ProductResource
  2. <?php
  3. namespace App\Http\Resources;
  4. use Illuminate\Http\Resources\Json\JsonResource;
  5. class ProductResource extends JsonResource
  6. {
  7. /**
  8. * Transform the resource into an array.
  9. *
  10. * @param \Illuminate\Http\Request $request
  11. * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
  12. */
  13. public function toArray($request)
  14. {
  15. return [
  16. 'id' => $this->id,
  17. 'product_name' => $this->name,
  18. 'product_price' => "$" . $this->price,
  19. 'discounted_price' => "$" . ($this->price * 0.9),
  20. 'discount' => "$" . ($this->price * 0.1),
  21. 'product_description' => $this->description,
  22. ];
  23. }
  24. }

再到ProductsController中index更新成如下代码:

  1. public function index()
  2. {
  3. return ProductResource::collection(Products::all());
  4. }

返回新的响应内容如下:

  1. {
  2. "data": [
  3. {
  4. "id": 1,
  5. "product_name": "quo",
  6. "product_price": "$15",
  7. "discounted_price": "$13.5",
  8. "discount": "$1.5",
  9. "product_description": "Ut rerum aut deleniti eveniet ad et ullam perferendis."
  10. },
  11. {
  12. "id": 2,
  13. "product_name": "maxime",
  14. "product_price": "$70",
  15. "discounted_price": "$63",
  16. "discount": "$7",
  17. "product_description": "Natus officiis repellat vero ea voluptatem mollitia similique."
  18. }
  19. ]
  20. }

Response Codes

每一个响应最好都带有一个序列。这样客户端可以知道当前服务端的状态。

一般的相应码如下:

  • 200-OK,响应正常;
  • 201-Created,通过在Post请求里面,代表资源创建成功;
  • 204-No Content,无数据返回,通常在删除资源的时候用;
  • 400-Bad Request,用户提交的密码或参数不正确;
  • 401-Unauthorized,用户无权限,需要身份验证;
  • 403-Forbidden,用户权限不够,禁止访问;
  • 404-Not Found,无对应的此资源;
  • 500-Internal Server Error,服务端内部错误。

Laravel使用jsonse->json()函数可以带个响应码。代码如下:

response->json(data,status code)

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载