如何建立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.php和api.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年,您应该使用Silex或Slim之类的东西

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/1766230和http://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.