【问题标题】:RESTful Server Design in YiiYii 中的 RESTful 服务器设计
【发布时间】:2011-06-21 15:29:52
【问题描述】:

您好,我一直在网上搜寻有关在 Yii 框架中创建宁静服务器的信息。

到目前为止,我发现的所有示例都涉及编写一个处理一个模型(IE 主题或帖子)的 restful 应用程序

我的问题的症结在于,我应该如何编写一个处理大量模型类型(即客户端、品牌、项目、任务)的宁静服务器?

每个模型对象都需要实现 CRUD 操作,例如 要创建一个新品牌,系统需要一个客户端 ID,其他 CRUD 操作也是如此。

每个模型对象应该有自己的 RESTFUl 服务器,还是应该有一种控制器将 RESTFUL 请求路由到模型对象的相应 Rest 控制器? 是否应该有一个服务器像交换机一样动态决定使用哪种模型(个人并不热衷于这个想法)

任何关于如何实现这种休息架构的建议都会很棒

我认为还值得注意的是,我正在构建的服务器将在前端使用 sproutcore,并且只会返回 JSON,因此不需要任何类型的格式检测。

【问题讨论】:

  • 我不确定您在什么情况下指的是“服务器”,但如果我理解了问题的其余部分,我会使用控制器与 URL 管理器相结合来创建一个 RESTful 服务。
  • 嗨,是的,我认为这就是我要走的路线,我想当我最初开始规划应用程序时,我想太多了!我采取这个方法,我有一个扩展 CController 的 ApiController 然后处理请求的控制器都扩展了 api 控制器

标签: php rest yii


【解决方案1】:

我正在 Yii 中开发 RESTful 应用程序。到目前为止一切正常。

  • 模型。我有两种型号:

    1. 通过 REST 接口管理(即创建/删除等)。我称它们为resources 并放入单独的目录中,但从技术上讲,它们是扩展CActiveRecord 的模型。
    2. 应用程序使用但未公开的内部模型。此外,抽象模型类可从中扩展其他模型或资源。

    资源实例可以从 REST 客户端发送的 XML 表示中构造出来,并且可以转换为 XML 表示。您可以定义一个基类AbstractResource 来处理这个问题,并在必要时覆盖子资源中的构造/转换方法。

  • 一种资源有一个控制器。控制器通常有四个 CRUD 动作,可能还有 List 动作。后者用于搜索操作。使用基于类的操作而不是内联操作是个好主意,这样您就可以在不同的控制器中重用您的操作。例如,我所有的控制器都使用ListAction 进行搜索。

  • 我有一个基本控制器,它将所有内容发送为application/xml。它还处理 HTTP 状态代码和handles all errors

  • 来自客户端的所有 XML 输入都使用 Relax NG schemes 进行验证。您需要 json 验证器。

  • TDD 摇滚!我已经广泛测试了几乎所有东西。在进行重构时有很大帮助。使用 TDD。为您的所有模型、资源和应用程序组件编写单元测试。此外,编写功能测试更容易,因为您没有 HTML/CSS/等。您只需发送 HTTP 请求并检查返回的标头、代码和内容。我使用了 php_curl 扩展,效果很好。由于您可能会执行 PUT、DELETE 和其他外来请求,因此您必须手动编写每个 HTTP 请求。就我而言,每个请求也需要签名(这涉及计算校验和、哈希等),因此几乎不可能手动测试我的应用程序。

我也推荐这本优秀的书:RESTful Web Services

【讨论】:

  • 谢谢你的回答!!!真的很丰富,我认为到目前为止我所拥有的有点像你概述的那样!我有一个访问点,ApiController,它设置了很多东西并定义了 actionAdd actionDelete actionUpdate List 和 actionView,我路由所有请求,如 api/create、pattern=>'api/' 并使用 $_GET 模型动态实例化ApiController 中请求的模型。一切似乎都在正常工作,但我注意到我在为每种类型取回相关数据时有点重复,我有 8 种类型可以使用,所以真的需要重构
【解决方案2】:

遍历这个tutorial。只需复制控制器操作。编辑第二组操作以与新模型交互。例如,本教程要求在控制器中创建以下操作:

public function actionList()
{
}
public function actionView()
{
}
public function actionCreate()
{
}
public function actionUpdate()
{
}
public function actionDelete()
{
}

您将为您的第二个模型创建替代操作。比如:

public function actionListB()
{
}
public function actionViewB()
{
}
public function actionCreateB()
{
}
public function actionUpdateB()
{
}
public function actionDeleteB()
{
}

如果您需要更多信息或说明,请发表评论。祝你好运。

【讨论】:

  • 嘿,感谢您的回答,我开始认为我不会得到一个:D 这个过程与我的想法一致,但是您能否为我澄清一下为什么简单地构建不会更好Yii 后端与普通 IE 一样,所有控制器都按正常方式布局,并简单地提供一种使用 Url 程序访问所述控制器的统一方式,而不是为每个将要使用的模型提供一个具有 CRUD 操作的巨型 Api 控制器?
  • 我只是想深入了解允许此应用程序可扩展等的最佳方法,同时请记住此应用程序将仅作为 sproutcore 前端的后端服务器,它不需要要在呈现视图等方面充当普通 Web 应用程序,只需对预定义的 url 进行调用,该 url 将执行特定任务并仅以 url 中指定的格式返回数据 - 非常感谢您的帮助非常感谢!
  • 我的错。您对 Api 控制器是正确的。拥有一个巨大的没有意义。切碎它肯定会更好地扩展。
【解决方案3】:

我正在这里对我的项目进行类似的练习。

我正在尝试确定以一种优雅、可扩展的方式使其全部运行的最佳方式。 目前这就是我所拥有的:

/controllers/apiController
/controllers/api/v1/resourceaController <extends apiController>
/controllers/api/v1/resourcebController <extends apiController>
/controllers/api/v1/resourcecController <extends apiController>

我正在构建的解决方案具有 URL 规则,根据使用的方法将用户直接重定向到 apiController 中的适当 CRUD 函数:

// REST API routes
array('api/list', 'pattern' => 'api/v<version:\d+>/<resource:\w+>', 'verb'=>'GET'),
array('api/create', 'pattern' => 'api/v<version:\d+>/<resource:\w+>', 'verb'=>'POST'),
array('api/view', 'pattern' => 'api/v<version:\d+>/<resource:\w+>/<resource_id:\d+>', 'verb'=>'GET'),
array('api/update', 'pattern' => 'api/v<version:\d+>/<resource:\w+>/<resource_id:\d+>', 'verb'=>'PUT'),
array('api/delete', 'pattern' => 'api/v<version:\d+>/<resource:\w+>/<resource_id:\d+>', 'verb'=>'DELETE'),
array('api/list', 'pattern' => 'api/v<version:\d+>/<resource:\w+>/<resource_id:\d+>/<association:\w+>', 'verb'=>'GET'),
array('api/create', 'pattern' => 'api/v<version:\d+>/<resource:\w+>/<resource_id:\d+>/<association:\w+>', 'verb'=>'POST'),
array('api/view', 'pattern' => 'api/v<version:\d+>/<resource:\w+>/<resource_id:\d+>/<association:\w+>/<association_id:\d+>', 'verb'=>'GET'),
array('api/update', 'pattern' => 'api/v<version:\d+>/<resource:\w+>/<resource_id:\d+>/<association:\w+>/<association_id:\d+>', 'verb'=>'PUT'),
array('api/delete', 'pattern' => 'api/v<version:\d+>/<resource:\w+>/<resource_id:\d+>/<association:\w+>/<association_id:\d+>', 'verb'=>'DELETE'),

接收调用的函数会尝试根据$_GET['resource']实例化资源控制器,并调用存储在$_GET['association']中的函数。

我认为这使它可以很好地扩展,因为我们可以推出新版本的 API,我们所要做的就是创建 /api/v2、/api/v2 之类的东西并放置所有必需的资源控制器在那里。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    相关资源
    最近更新 更多