lujo/lumen-rest

Lumen包,用于创建简单的REST API

2.0.0 2023-10-13 14:40 UTC

README

Lumen包,用于创建简单的REST API。

安装

使用以下命令通过composer安装此包:

composer require lujo/lumen-rest

或者在composer.json中添加以下行:

"require": {
    ...
    "lujo/lumen-rest": "*"
}

然后运行:

composer install

描述

此Lumen包由两个类组成:RestRouteRestController

  • RestRoute在函数route(...)中执行特定资源的所有路由操作。
  • RestController应该被扩展为其他控制类,用于特定资源。

使用方法

1. 创建Eloquent模型

为了使用此REST包,首先你必须为某些资源创建Eloquent模型。

例如:文章模型

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model {

    protected $table = 'article';

    protected $fillable = [
        'title',
        'description',
        'content'
    ];

    // Optional realtions and other Eloquent stuff
    public function articleAuthor() {
        return $this->hasOne('App\Models\Author');
    }
}

2. 创建控制器

创建模型后,你可以创建简单的控制器类,并从这个包中扩展RestController类。你还必须实现函数getModel(),该函数必须返回你在上一步中创建的Eloquent模型,这是你想通过此REST API公开的资源。

例如:控制器类

<?php

namespace App\Http\Controllers;

use Illuminate\Database\Eloquent\Model;
use App\Models\Article;
use Lujo\Lumen\Rest\RestController;


class ArticleController extends RestController {

    /**
     * @return Model
     */
    protected function getModel() {
        return new Article();
    }
    
    // Optional override, transforms every model before returning it from API.
    protected function beforeGet($model) {
        return $model;
    }
    
    // Optional override, transform received request before creating new model from it.
    protected function beforeCreate($request) {
        return $request->all();
    }
    
    // Optional override, transform received request before updating existing model from it.
    protected function beforeUpdate($request) {
        return $request->all();
    }
    
    // Optional override, perform some action on/with model before it is deleted.
    protected function beforeDelete($model) {
        return null;
    }
    
    // Optional override, specify list of relations to return on specific action
    protected function getWith($request, $action) {
        if($action === 'INDEX') {
            return ['text'];
        }
        return ['author', 'comments', 'text'];
    }
    
    // Optional override, specify list of where statements to return on specific action
    protected function getWhere($request, $action) {
        if($action === 'DELETE') {
            return [['name', 'Test']];
        }
        return [['status', 'ACTIVE'], ['enabled', true]];
    }
    
    // Optional override, specify additional where query statement in form of a anonymous function
    protected function getWhereFunction($request, $action) {
        return function($q) {
            $q->where('name', 'Test')->orWhere('status', 'ACTIVE');
        };
    }
    
    // Optional override, when INDEX method is called and this method returns true, the returend JSON will contain 
    // count data used for pagination e.g. {result_count: 10, total_count: 45, data: [...results]}
    protected function withCountMetadata($request) {
        return false;
    }

}

如果你不使用它们,所有可选的覆盖函数都不需要,它们可以从你的控制器类实现中安全地省略。

3. 创建路由

完成前两个步骤后,打开你的Lumen路由文件routes/web.php,并使用RestRoute类的静态函数route($router, $prefix, $controller, $include = null)创建路由结构。

例如:routes/web.php路由

<?php 

use Laravel\Lumen\Routing\Router;
use Lujo\Lumen\Rest\RestRoute;

/**
 * @var $router Router
 */

// This will create all article routes ('INDEX', 'ONE', 'CREATE', 'UPDATE', 'DELETE') for routes /articles/*
RestRoute::route($router, 'articles', 'ArticleController', 'middleware1');

// This will create only 'INDEX' and 'ONE' for routes /users/*
RestRoute::route($router, 'users', 'UserController', ['middleware1', 'middleware2'], ['INDEX', 'ONE']);

// This will create only 'INDEX', 'CREATE' and 'UPDATE' routes for /example/* but apply middlewares only on CREATE and UPDATE
RestRoute::route($router, 'examples', 'ExampleController', ['CREATE' => ['middleware1', 'middleware2'], 'UPDATE' => 'middleware2'], 
        ['INDEX', 'CREATE', 'UPDATE']);

// This will create all routes and apply middleware1 and middleware2 to INDEX and ONE route, on others will middleware3 be applied.
RestRoute::route($router, 'users', 'UserController', ['INDEX,ONE' => ['middleware1', 'middleware2'], 'middleware3']);

// Example subgroup of routes (/article/authors/*) with middleware
$router->group(['prefix' => 'article', 'middleware' => 'middleware1'], function ($subRoute) {
        RestRoute::route($subRoute, 'authors', 'AuthorController');
    }
);

生成的REST资源路由格式如下

** 获取所有资源 ** 具有以下HTTP GET URL参数

  • skip - 跳过的资源数量(例如,30)
  • limit - 要检索的资源数量(例如,15)
  • sort - 要排序返回资源的字段(例如,'first_name')
  • order - 返回资源的排序('asc'或'desc')

示例HTTP GET请求: http://site.com/api/resource?skip=30&limit=6&sort=name&order=desc

响应

头部

Content-type: application/json
X-Total-Count: 10
X-Result-Count: 6

当方法withCountMetadata()返回false时的主体

[
    {"id": 31, "resource_name": "Resource name", "description": "Some resource description"}, 
    {"id": 32, "resource_name": "Resource name", "description": "Some resource description"},
    {"id": 33, "resource_name": "Resource name", "description": "Some resource description"}, 
    {"id": 34, "resource_name": "Resource name", "description": "Some resource description"}, 
    {"id": 35, "resource_name": "Resource name", "description": "Some resource description"},
    {"id": 36, "resource_name": "Resource name", "description": "Some resource description"}
]

当方法withCountMetadata()返回true时的主体

{
    total_count: 10,
    result_count: 6,
    data: [
        {"id": 31, "resource_name": "Resource name", "description": "Some resource description"}, 
        {"id": 32, "resource_name": "Resource name", "description": "Some resource description"},
        {"id": 33, "resource_name": "Resource name", "description": "Some resource description"}, 
        {"id": 34, "resource_name": "Resource name", "description": "Some resource description"}, 
        {"id": 35, "resource_name": "Resource name", "description": "Some resource description"},
        {"id": 36, "resource_name": "Resource name", "description": "Some resource description"}
    ]
}

许可

MIT