Php API应该使用自身还是直接调用数据库以获取其他资源?

Php API应该使用自身还是直接调用数据库以获取其他资源?,php,api,rest,oauth,internals,Php,Api,Rest,Oauth,Internals,这个问题是一个延伸,虽然是独立的 我们有一个车库有多辆车的基本例子,所以我们的端点是 /garages /garages/{id} /garages/{id}/cars /garages/{id}/cars/{id} /cars /cars/{id} 我们可以使用/cars?garage[id]=1,2,3 这很酷。但我现在想知道的是API的内部 我可以想出两种方法来做到这一点: 在/cars端点中进行直接筛选 这意味着我们要在查询中获取汽车,我们要进行一些连接,并添加一些where's 这种

这个问题是一个延伸,虽然是独立的

我们有一个车库有多辆车的基本例子,所以我们的端点是

/garages
/garages/{id}
/garages/{id}/cars
/garages/{id}/cars/{id}
/cars
/cars/{id}
我们可以使用
/cars?garage[id]=1,2,3

这很酷。但我现在想知道的是API的内部

我可以想出两种方法来做到这一点:

在/cars端点中进行直接筛选 这意味着我们要在查询中获取汽车,我们要进行一些连接,并添加一些where's

这种方法的好处是,我们将得到最少的查询量。
这种方法的缺点是,我们最终在两个地方维护车库资源。任何时候,车库得到一个新的财产,我们现在必须支持这在汽车端点也

从/cars端点调用/garages端点 这意味着我们从/cars端点中调用/garages端点,/garages返回匹配车库中所有汽车的id。然后,我们继续在/cars端点内从后面获取车辆

此方法的好处是资源是自包含的。
这种方法的缺点是,我们最终会对数据库进行多次调用。另外,传递身份验证细节可能会变得很麻烦(假设Oauth 2.0)


那么最合适的方法是什么呢?我倾向于第二种方法,但我担心如果我们想进行更高级的查询,这可能会成为一个真正的麻烦。

好消息是,它是在幕后进行的,因此如果您犯了错误,您可以稍后更改实现。我当然也会选择2号。在您知道是否存在性能问题之前,尝试摆脱数据库调用对我来说太像是过早的优化。这取决于相关呼叫的频率以及您需要系统的性能

传递oauth令牌可能会很烦人,但与在多个位置维护一个资源相比,它的错误风险似乎更小。

使用您自己的端点(这被称为并有许多好处),但不要与端点紧密耦合

首先,我不会按数字ID进行查询,因为这与您的实现紧密相关。如果您使用URL作为车库标识符,那么您将获得更大的灵活性,并且可以轻松地在您自己的系统之外的其他系统中添加对车库的支持

使用(即链接和表单)在车辆列表中添加搜索表单。让我们假设您的汽车列表类似于(为了简洁起见,排除了scheme和host)


超媒体控件是否总是用XML指定?如果您的API是面向Json的,那么上面提到的示例会是什么样子?@Hailwood,不,它们不一定是XML,它们可以是Json或YAML格式,也可以是您选择的任何格式。我将添加一个示例。
<cars self="/cars">
    <car href="/cars/0"/>
    <car href="/cars/1"/>
    ...
</cars>
<cars self="/cars">
    <car href="/cars/0"/>
    <car href="/cars/1"/>
    ...
    <form name="search" action="/cars" method="get">
        <input name="garage" type="URL"/>
        <!-- other things to search for can go here -->
    </form>
</cars>
<garages self="/garages">
    <garage href="/garage/0"/>
    <garage href="/garage/1"/>
    ...
    <form name="search" action="/garages" method="get">
        <input name="paint" type="string"/>
        <!-- other things to search for can go here -->
    </form>
</garages>
<garages self="/garages?paint=yellow">
    <garage href="/garage/24"/>
    <garage href="/garage/36"/>
    ...
</garages>
<garages self="/garages?paint=yellow">
    <garage href="/garage/24"/>
    <garage href="/garage/36"/>
    <link rel="cars" href="/cars?garage=/garage/24,/garage/36"/>
</garages>
<garages self="/garages?paint=yellow">
    <garage href="/garage/24"/>
    <garage href="/garage/36"/>
    <link rel="cars" href="/cars?garages=/garages?paint=yellow"/>
</garages>
<garage self="/garage/24">
    ... details about the garage ...
    <link rel="cars" href="/cars?garage=/garages/24"/>
</garages>
<garages self="/garages?page=2">
    <garage href="/garage/10"/>
    <garage href="/garage/11"/>
    ...
    <link rel="next" href="/garages?page=3"/>
    <link rel="prev" href="/garages"/>
</garages>
{
    "self": "/garages?paint=yellow&page=2",
    "garages": [
        {
            "href": "/garage/24"
            //... summary properties for this garage go here ...
            //... you can even add a "media-types" array, to tell the service consumer
            //    what media types the garage is available in... 
        },
        {
            "href": "/garage/36"
        }
    ],
    "next": {
        "href": "/garages?paint=yellow"
    },
    "prev": {
        "href": "/garages?paint=yellow&page=3"
    },
    "cars": {
        "href": "/cars?garages=/garages?paint=yellow"
    },
    "search": {
        "href": "/garages?paint=yellow",
        "method": "GET",
        "inputs": {
            ... form input parameters go here ...
        }
    }
}