【问题标题】:Design a RESTful API in Laravel 5.2, using a resource that conceptually can contain other resources在 Laravel 5.2 中设计一个 RESTful API,使用概念上可以包含其他资源的资源
【发布时间】:2016-08-05 14:58:18
【问题描述】:

首先我对 REST 实践真的不是很熟悉,对我的问题的标题也不是很自信。

所以我正在尝试使用 Laravel 为电话簿应用程序构建一个 RESTful API。电话簿可能包含员工(即真人)或办公室的电话。出于这个原因,我有三个模型

  • Directorateidname 字段,
  • Employeeidname 字段和
  • Telephoneidtelemployee_iddirectorate_iddescriptiontype 字段。

一个局办公室对应的电话只设置了idteldirectorate_iddescription字段,而一个人(即员工)对应的电话只设置了idtelemployee_iddirectorate_idtype 字段。我就是这样区分它们的:有描述的电话只能是办公室的电话,而同时设置了employee_id和type_id的电话是员工的电话。

模型相关如下:

  • 一个员工可能有很多电话
  • 一个董事会,可能有很多电话

    class Directorate extends Model
    {
        public function telephones()
        {
            return $this->hasMany(Telephone::class);
        }
    
        public function employees()
        {
            return $this->hasMany(Employee::class);
        }
    }
    
    
    class Employee extends Model
    {
        public function telephones()
        {
            return $this->hasMany(Telephone::class);
        }
    
        public function directorate()
        {
            return $this->belongTo(Directorate::class);
        }
    }
    
    
    class Telephone extends Model
    {
        public function employee()
        {
            return $this->belongsTo(Employee::class);
        }
    }
    

我的问题是我应该将什么视为我的资源

到目前为止,我正在考虑以下方法:

我将使用 contact 的概念作为资源。 联系人可以是员工和电话的联合信息,也可以是董事会和电话的联合信息。例如,“联系人”可能包含员工的姓名及其相关的电话号码和电话类型,或者它可以包含董事会的名称以及电话的描述和电话号码。

这种方法的“问题”是我最终得到(让我们这样说)两种不同类型的资源员工的联系人和主管办公室的联系人,其中包含的信息略有不同,因此,我还需要有不同的创建和编辑表单来与这两种“类型”的资源进行交互。

为了实现 REST API,我考虑了两种不同的场景:

  1. 使用两个不同的 RESTful 控制器,一个 EmployeeContacts 和另一个 OfficesContacts,用于从概念上将资源分为员工资源和办公室资源,并通过不同的像这样的 URI:

    example.com/phonebook/employees/{id}/edit

    example.com/phonebook/offices/{id}/edit

    example.com/phonebook/employees/create

    等等……

  2. 使用单个 RESTful 控制器,例如PhonebookContacts 通过与一个资源相同的 URI 访问资源(即员工和办公室的联系人资源现在都被认为只是一个“联系人”资源

    //这是指一个联系人资源,可以是办公室或员工的联系人

    example.com/phonebook/contact/{id}/edit

    //这应该列出所有资源(员工和办公室联系人)

    example.com/phonebook/contact/

    然后在控制器的create/store/edit/update 方法中使用条件语句来分别处理它们(例如,如果http POST 请求包含description_id,那么它是办公室联系人并执行此操作,否则如果有employee_id那么它是员工的联系人,所以这样做......)

我想听听您的意见,您认为这两种不同的场景中哪一个在我的电话簿应用程序的 REST 环境中更好?最好考虑一个“联系人”资源并使用控制器中具有不同返回的条件语句来处理它,或者我应该将“联系人”的概念与“员工的联系人”和“办公室的联系人”分开并使用单独的控制器和URI 来处理它们?

我可以采用其他方法吗?

【问题讨论】:

标签: api rest laravel restful-architecture


【解决方案1】:

出于速度和响应能力的简单原因,我会使用 2 个不同的控制器。加载所有联系人和过滤并不像只加载一个部分那么快。

但是,您始终可以在控制器中使用不同的数据设置相同的返回值。比如EmployeeController@index返回view('contacts.index', compact('employeeContacts'))OfficesController@index返回view('contacts.index', compact('officesContacts'))

编辑:

对不起,我看错了...我以为你想在视图中进行过滤。反正我的做法是分开做,只是因为代码更干净。如果您想让整个 REST 更具可读性,您可以将这两个资源放在一个组中,如下所示:Route::group(['prefix' => 'contact'], function(){ //routes here// }); 所以现在你会有这样的路线:

example.com/contact/employees/

example.com/contact/offices/

【讨论】:

  • 您能否再解释一下“加载所有联系人和过滤不如仅加载一个部分”是什么意思?我的意思是,使用一个控制器是否可行,只加载我想要的部分数据(例如,对于员工的联系人,例如: $employees = Employee::whereHas('telephones', function ($query) { $query- >where('description_id', null); }) ->with([ 'telephones' => function ($query) { $query->where('description_id', null); } ]) ->get();然后只将这部分返回到视图中?
  • @Norgul 您令人困惑的实现和 API 设计。这些是完全不同的事情。 API 结构与速度或响应能力无关。这些都与实现有关。 API 用于将合同与实现分离。
  • 我没有混淆它,如上所述,我误读了文本。我以为他试图在视图中进行过滤,而不是在控制器中。我已经相应地编辑了答案
【解决方案2】:

我对 Laravel 一点也不熟悉,但由于这个问题是关于 REST 概念的(我对这些概念了解不多),我应该试一试。

由于您正在构建一个 RESTful 应用程序,因此您不能将其他人视为人类,而只能将其视为机器。 IMO url 应确定将执行的操作。因此,通过对不同的操作使用不同的 url(对联系人执行 CRUD - EmployeeDirectorateSomethingElseInTheFuture)对我来说听起来不错并且适合 REST。

希望这能为你澄清事情!

[编辑]

我相信jannis 是对的。应该是动词(GET、POST、PUT、PATCH 等)而不是 URL 来执行操作。网址只是代表资源。我的错。所以你的两个观点都是正确的。每种方法对您的项目有多方便(现在和您的项目不久的将来)。 IMO,我认为 #1(两个不同的 restful 控制器)更接近。

对任何误解表示歉意!

【讨论】:

  • 您能否澄清一下您所说的“您不能将他人视为人类,而只能视为机器”是什么意思?另外,如果我理解正确,您是否建议最好在具有两种不同类型资源(即服务联系人和员工联系人)的上下文中构建应用程序,然后分别对它们中的每一个进行 CRUD?
  • 这是关于REST 概念的一个很好的答案。我只是说 REST (AFAIK) 应该将浏览器与服务器连接,而很少将用户与服务器连接。是的,你理解正确。我建议使用两种不同的资源。
  • @nik_m 相反 - 将动作嵌入到 URL 中根本不是 RESTful。 REST 中的 URL 应该标识资源,而不是操作。 操作由方法动词表示:例如GET /offices/1 获取 office 资源表示,POST /offices 在 office 集合中创建一个新的 office 资源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-17
相关资源
最近更新 更多