如何建立RESTful API?


77

问题是这样的:我有一个在PHP服务器上运行的Web应用程序。我想为此构建一个REST API。
我进行了一些研究,发现REST api使用带有身份验证密钥(不一定)的某些URI的HTTP方法(GET,POST ...),并且信息以HTTP响应的形式返回,信息为XML或JSON。 (我宁愿使用JSON)。

我的问题是:

  1. 作为应用程序的开发人员,我如何构建这些URI?我需要在该URI上编写PHP代码吗?
  2. 如何构建JSON对象以作为响应返回?


我写了这篇博客文章,其中包含一些示例代码和说明。
mevdschee

Answers:


68

这是简单php中的一个非常简单的示例。

有2个文件client.phpapi.php。我将两个文件放在相同的url:上http://localhost:8888/,因此您必须将链接更改为您自己的url。(该文件可以位于两个不同的服务器上)。

这只是一个例子,它非常快捷,肮脏,而且自从我完成php以来已经很长时间了。但这是一个api的想法。

client.php

<?php

/*** this is the client ***/


if (isset($_GET["action"]) && isset($_GET["id"]) && $_GET["action"] == "get_user") // if the get parameter action is get_user and if the id is set, call the api to get the user information
{
  $user_info = file_get_contents('http://localhost:8888/api.php?action=get_user&id=' . $_GET["id"]);
  $user_info = json_decode($user_info, true);

  // THAT IS VERY QUICK AND DIRTY !!!!!
  ?>
    <table>
      <tr>
        <td>Name: </td><td> <?php echo $user_info["last_name"] ?></td>
      </tr>
      <tr>
        <td>First Name: </td><td> <?php echo $user_info["first_name"] ?></td>
      </tr>
      <tr>
        <td>Age: </td><td> <?php echo $user_info["age"] ?></td>
      </tr>
    </table>
    <a href="http://localhost:8888/client.php?action=get_userlist" alt="user list">Return to the user list</a>
  <?php
}
else // else take the user list
{
  $user_list = file_get_contents('http://localhost:8888/api.php?action=get_user_list');
  $user_list = json_decode($user_list, true);
  // THAT IS VERY QUICK AND DIRTY !!!!!
  ?>
    <ul>
    <?php foreach ($user_list as $user): ?>
      <li>
        <a href=<?php echo "http://localhost:8888/client.php?action=get_user&id=" . $user["id"]  ?> alt=<?php echo "user_" . $user_["id"] ?>><?php echo $user["name"] ?></a>
    </li>
    <?php endforeach; ?>
    </ul>
  <?php
}

?>

api.php

<?php

// This is the API to possibility show the user list, and show a specific user by action.

function get_user_by_id($id)
{
  $user_info = array();

  // make a call in db.
  switch ($id){
    case 1:
      $user_info = array("first_name" => "Marc", "last_name" => "Simon", "age" => 21); // let's say first_name, last_name, age
      break;
    case 2:
      $user_info = array("first_name" => "Frederic", "last_name" => "Zannetie", "age" => 24);
      break;
    case 3:
      $user_info = array("first_name" => "Laure", "last_name" => "Carbonnel", "age" => 45);
      break;
  }

  return $user_info;
}

function get_user_list()
{
  $user_list = array(array("id" => 1, "name" => "Simon"), array("id" => 2, "name" => "Zannetie"), array("id" => 3, "name" => "Carbonnel")); // call in db, here I make a list of 3 users.

  return $user_list;
}

$possible_url = array("get_user_list", "get_user");

$value = "An error has occurred";

if (isset($_GET["action"]) && in_array($_GET["action"], $possible_url))
{
  switch ($_GET["action"])
    {
      case "get_user_list":
        $value = get_user_list();
        break;
      case "get_user":
        if (isset($_GET["id"]))
          $value = get_user_by_id($_GET["id"]);
        else
          $value = "Missing argument";
        break;
    }
}

exit(json_encode($value));

?>

在此示例中,我没有对数据库进行任何调用,但是通常这是您应该做的。您还应该将“ file_get_contents”功能替换为“ curl”。


西蒙,非常感谢你的榜样。我只想确定:假设我有一个名为User的资源,那么我需要将API文件放入:mydomain.com/api/user对 吗?
沙龙海姆·普

您可以根据需要命名文件。但是,是的,最好使用显式名称调用文件。在我的api文件中查找,我检查了get参数并由于此值而调用了一个函数。您可以包含user.php并调用此文件中的函数,也可以将文件放在api / user并从此处处理参数。
西蒙马克

因此,基本上,我需要更新服务器路由表以将某些URL映射到服务器上的某些PHP文件。正确?
沙龙海姆·普尔

1
是的,但是与创建普通网站一样,这只是您发送给更改者的信息。
西蒙·马克

6
这仅使用“ GET”,并且从不查看请求方法,因此它不是RESTful的。有关示例,请参见stackoverflow.com/a/897311/1766230,以及en.wikipedia.org/wiki/…–
路加福音

34

在2013年,您应该使用SilexSlim之类的东西

Silex示例:

require_once __DIR__.'/../vendor/autoload.php'; 

$app = new Silex\Application(); 

$app->get('/hello/{name}', function($name) use($app) { 
    return 'Hello '.$app->escape($name); 
}); 

$app->run(); 

苗条的例子:

$app = new \Slim\Slim();
$app->get('/hello/:name', function ($name) {
    echo "Hello, $name";
});
$app->run();

1
谢谢。我使用了Slim,几分钟后运行了一个裸API。
2013年

对于更复杂(详细)的api,您有什么建议?Slim方便使用,但所有功能都在一个文件中,因此可读性非常难。
Ilker Baltaci

2
@IlkerBaltaci使用Silex,您可以将控制器提取到类中。这是一篇很好的文章,以及使用微框架与全栈框架igor.io/2012/11/09/scaling-silex.html的利弊。我个人更喜欢Silex,因为它可以为我提供最重要的信息,并让我选择其余的堆栈。
全息原理

10

这与创建普通网站几乎相同。

php网站的正常模式是:

  1. 用户输入一个URL
  2. 服务器获取URL,对其进行解析并执行操作
  3. 在此操作中,您将获取/生成页面所需的所有信息
  4. 您使用操作中的信息创建html / php页面
  5. 服务器生成一个完整的html页面并将其发送回用户

使用api,您只需在3和4之间添加一个新步骤。3之后,创建一个包含所有所需信息的数组。将此数组编码为json并退出或返回此值。

$info = array("info_1" => 1; "info_2" => "info_2" ... "info_n" => array(1,2,3));
exit(json_encode($info));

这全部用于api。对于客户端,您可以通过url调用api。如果api仅与get调用一起使用,我认为可以进行简单的操作(要检查,我通常使用curl)。

$info = file_get_contents(url);
$info = json_decode($info);

但是使用curl库执行get和post调用更为常见。您可以问我是否需要卷曲帮助。

从api获取信息后,您可以执行4和5步骤。

在php文档中查找json函数和file_get_contents。

curl:http : //fr.php.net/manual/fr/ref.curl.php


编辑

不,等等,我不明白。“ php API页面”是什么意思?

api只是项目的创建/存储。您永远不要直接发送html结果(如果您正在建立一个网站),并抛出api。您使用URL调用api,api返回信息,并使用此信息创建最终结果。

例如:您想编写一个HTML网页,说“你好XXX”。但是要获取用户名,您必须从api获取信息。

因此,假设您的api包含一个函数,该函数使用user_id作为参数并返回该用户的名称(假设为getUserNameById(user_id)),并且您仅在类似your / api / ulr / getUser / id的url上调用此函数。

Function getUserNameById(user_id)
{
  $userName = // call in db to get the user
  exit(json_encode($userName)); // maybe return work as well.
}

客户端,您可以

    $username = file_get_contents(your/api/url/getUser/15); // You should normally use curl, but it simpler for the example
// So this function to this specifique url will call the api, and trigger the getUserNameById(user_id), whom give you the user name.
    <html>
    <body>
    <p>hello <?php echo $username ?> </p>
    </body>
    </html>

因此,客户端永远不会直接访问数据库(即api的角色)。

这样清楚吗?


+1。还要注意,API应该为响应设置正确的内容类型。对于JSON,看到stackoverflow.com/questions/477816/the-right-json-content-type

所以我应该在服务器上有一个php API页面来管理所有请求?
沙龙海姆·普尔

不,等等,我不明白。“ php API页面”是什么意思?
西蒙·马克

我的问题是应该将API请求指向何处?服务器上的哪个文件?
沙龙海姆·普尔

所需的文件与创建网站的文件完全相同,只不过您是从客户端而不是从浏览器调用api。但是对于api来说,没有任何变化。当您收到伺服器上的网址时,由于get和post参数,您可以决定使用该网址。您已经建立了网站吗?您是否使用过cake,symfony或zend之类的框架?
西蒙·马克

6

(1)如何...建立那些URI?我需要在该URI上编写PHP代码吗?

没有关于如何设置API URI方案的标准,但是使用斜杠分隔的值是很常见的。为此,您可以使用...

$apiArgArray = explode("/", substr(@$_SERVER['PATH_INFO'], 1));

...以在文件名的URI中获取以斜杠分隔的值的数组。

示例:假设您api.php的应用程序中某处有一个API文件,并且您对进行了请求api.php/members/3,那么$apiArgArray它将是一个包含的数组['members', '3']。然后,您可以使用这些值来查询数据库或进行其他处理。

(2)如何构建要作为响应返回的JSON对象?

您可以使用任何PHP对象,并使用json_encode将其转换为JSON 。您还需要设置适当的标题。

header('Content-Type: application/json');
$myObject = (object) array( 'property' => 'value' ); // example
echo json_encode($myObject); // outputs JSON text

所有这些对于返回JSON的API都有好处,但是您应该问的下一个问题是:

(3)如何使我的API RESTful?

为此,我们将使用$_SERVER['REQUEST_METHOD']来获取要使用的方法,然后根据该方法执行不同的操作。所以最终结果是...

header('Content-Type: application/json');
$apiArgArray = explode("/", substr(@$_SERVER['PATH_INFO'], 1));
$returnObject = (object) array();
/* Based on the method, use the arguments to figure out
   whether you're working with an individual or a collection, 
   then do your processing, and ultimately set $returnObject */
switch ($_SERVER['REQUEST_METHOD']) {
  case 'GET':
    // List entire collection or retrieve individual member
    break;
  case 'PUT':       
    // Replace entire collection or member
    break;  
  case 'POST':      
    // Create new member
    break;
  case 'DELETE':    
    // Delete collection or member
    break;
}
echo json_encode($returnObject);

资料来源:https : //stackoverflow.com/a/897311/1766230http://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services



2

我知道这个问题已经被接受并且年龄有些长,但这对某些仍然认为它有意义的人可能会有帮助。尽管结果不是完整的RESTful API,但PHP的API Builder迷你库使您可以轻松地将MySQL数据库转换为可通过Web访问的JSON API。


0

正如simon marc所说,该过程与您或我浏览网站的过程几乎相同。如果您对使用Zend框架感到满意,那么可以使用一些易于遵循的教程,以轻松进行设置。建立一个宁静的api的最难的部分是它的设计,并使它真正宁静,请从数据库角度考虑CRUD。

可能是您确实想要xmlrpc接口或其他类似的东西。您希望此界面允许您做什么?

- 编辑

这是我开始使用Restful api和Zend Framework的地方。 Zend框架示例

简而言之,不要使用Zend rest服务器,它已经过时了。


如果您有兴趣,我将在我的博客上发布有关ZF和RESTful Web服务入门的完整示例。
詹姆斯·巴特勒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.