当前的互联网生态系统已被 API 彻底改变,这是有充分理由的。通过在产品或服务中使用第三方 API,您可以访问大量有用的功能——例如身份验证或存储服务——这些功能对您和您的用户都有利。通过公开您自己的 API,您的应用程序将成为“组合的一部分”,并以您从未想过的方式使用……当然,如果您以正确的方式这样做。在这个由两部分组成的系列文章中,我将向您展示如何使用一系列真实的最佳实践为您的 PHP 应用程序创建 RESTful API 层。本项目完整的源代码将在第 2 部分的结尾提供。
关键要点
REST:开发人员友好的 UI
首先,API 是开发人员的用户界面,因此它必须友好、简单、易于使用,当然也要令人愉快;否则,它最终将成为另一个数字垃圾。即使只是一个简单但写得很好的 README 文件,文档也是一个良好的开端。我们需要最少的信息是服务范围的摘要以及方法和访问点的列表。一个好的摘要可以是:> 我们的应用程序是一个简单的联系人列表服务,用于管理具有关联笔记的联系人。它有两种对象类型,联系人(contacts)和笔记(notes)。每个联系人都有基本属性,例如名字、姓氏和电子邮件地址。此外,每个联系人可以有多个与之关联的 Markdown 格式的笔记。
然后,最好列出我们将要实现的所有资源和操作。这可以被视为可视化应用程序线框图的等效项。遵循 REST 的关键原则,每个资源都由一个 URL 表示,其中操作是用于访问它的 HTTP 方法。例如,GET /api/contacts/12 将检索 ID 为 12 的联系人,而 PUT /api/contacts/12 将更新相同的联系人。完整的 method 列表如下所示:
<code>URL HTTP Method Operation /api/contacts GET 返回联系人数组 /api/contacts/:id GET 返回 ID 为 :id 的联系人 /api/contacts POST 添加一个新联系人并返回它(添加了 id 属性) /api/contacts/:id PUT 更新 ID 为 :id 的联系人 /api/contacts/:id PATCH 部分更新 ID 为 :id 的联系人 /api/contacts/:id DELETE 删除 ID 为 :id 的联系人 /api/contacts/:id/star PUT 将 ID 为 :id 的联系人添加到收藏夹 /api/contacts/:id/star DELETE 从收藏夹中删除 ID 为 :id 的联系人 /api/contacts/:id/notes GET 返回 ID 为 :id 的联系人的笔记 /api/contacts/:id/notes/:nid GET 返回 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes POST 为 ID 为 :id 的联系人添加新笔记 /api/contacts/:id/notes/:nid PUT 更新 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes/:nid PATCH 部分更新 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes/:nid DELETE 删除 ID 为 :id 的联系人的 ID 为 :nid 的笔记</code>
对于更完整和专业的文档,您可以考虑使用 Swagger、apiDoc 或 Google APIs Discovery Service 等工具:您的用户会喜欢您的!
工具和设置
我将用来构建 API 的主要工具是 Slim Framework。为什么?> [它] 帮助您快速编写简单而强大的 Web 应用程序和 API。
这是真的。其强大的路由功能使使用 GET 和 POST 以外的方法变得容易,它提供对 HTTP 方法覆盖的内置支持(通过 HTTP 标头和隐藏的 POST 字段),并且可以与中间件和额外功能挂钩,使应用程序和 API 开发真正变得容易。与 Slim 一起,我使用 Idiorm 访问数据库层,使用 Monolog 进行日志记录。因此,我们的 composer.json 文件将如下所示:
<code class="language-json">{ "name": "yourname/my-contacts", "description": "Simple RESTful API for contacts management", "license": "MIT", "authors": [ { "name": "Your Name", "email": "you@yourdomain.com" } ], "require": { "slim/slim": "*", "slim/extras": "*", "slim/middleware": "*", "monolog/monolog": "*", "j4mie/paris": "*", "flynsarmy/slim-monolog": "*" }, "archive": { "exclude": ["vendor", ".DS_Store", "*.log"] }, "autoload": { "psr-0": { "API": "lib/" } } }</code>
slim/extras 和 slim/middleware 包提供了诸如内容类型解析和基本身份验证之类的有用功能。我们的自定义类位于 API 命名空间下,位于 lib 目录中。此时,我们的工作目录结构如下所示:
<code>bootstrap.php composer.json README.md bin/ import install lib/ API/ public/ .htaccess index.php share/ config/ default.php db/ logs/ sql/ data/ contacts.sql users.sql tables/ contacts.sql notes.sql users.sql ssl/ mysitename.crt mysitename.key</code>
我们的应用程序的前端控制器是 public/index.php,所有非文件或目录流量都通过标准 URL 重写规则重定向到此处。然后,我将所有初始化代码放在 bootstrap.php 中,我们稍后会看到。share 目录包含数据,例如日志、配置文件、SQLite 数据库和转储文件以及 SSL 证书。bin 目录包含使用提供的 .sql 文件创建数据库和导入一些数据的实用程序脚本。
我们的 API 只能在 HTTPS 模式下访问,无需重定向。这简化了身份验证逻辑并防止配置不当的客户端访问未加密的端点。设置此方法最简单和最合乎逻辑的方法是直接作用于 Web 服务器或通过代理服务器。我使用旧的可靠的 Apache 来执行此操作,我的虚拟主机文件如下所示:
<code class="language-apache"><directory> # Required for mod_rewrite in .htaccess AllowOverride FileInfo Options All -Indexes DirectoryIndex index.php index.shtml index.html <ifmodule php5_module=""> # For Development only! php_flag display_errors On </ifmodule> # Enable gzip compression <ifmodule filter_module=""> AddOutputFilterByType DEFLATE application/json </ifmodule> Order deny,allow Deny from all Allow from 127.0.0.1 </directory> <virtualhost> ServerAdmin you@yourdomain.com DocumentRoot "/path/to/MyApp/public" ServerName myapp.dev <ifmodule rewrite_module=""> RewriteEngine on ## Throw a 403 (forbidden) status for non secure requests RewriteCond %{HTTPS} off RewriteRule ^.*$ - [L,R=403] </ifmodule> </virtualhost> <ifmodule ssl_module=""> NameVirtualHost *:443 Listen 443 SSLRandomSeed startup builtin SSLRandomSeed connect builtin <virtualhost> ServerAdmin you@yourdomain.com DocumentRoot "/path/to/MyApp/public" ServerName myapp.dev SSLEngine on SSLCertificateFile /path/to/MyApp/share/ssl/mysitename.crt SSLCertificateKeyFile /path/to/MyApp/share/ssl/mysitename.key SetEnv SLIM_MODE development </virtualhost> </ifmodule></code>
首先定义目录设置,以便它们与我们站点的 HTTP 和 HTTPS 版本通用。在非安全主机配置中,我使用 mod_rewrite 为任何非安全连接发出 403 禁止错误,然后在安全部分中,我使用我的自签名证书设置 SSL,以及告诉 Slim 当前应用程序模式的 SLIM_ENV 变量。有关如何在 Apache 上创建自签名证书并安装它的更多信息,请参阅 SSLShopper 上的这篇文章。现在我们有了明确的目标、基本目录结构和服务器设置,让我们运行 composer.phar install 并开始编写一些代码。
引导程序和前端控制器
如前所述,bootstrap.php 文件负责加载我们的应用程序设置和自动加载器设置。
<code>URL HTTP Method Operation /api/contacts GET 返回联系人数组 /api/contacts/:id GET 返回 ID 为 :id 的联系人 /api/contacts POST 添加一个新联系人并返回它(添加了 id 属性) /api/contacts/:id PUT 更新 ID 为 :id 的联系人 /api/contacts/:id PATCH 部分更新 ID 为 :id 的联系人 /api/contacts/:id DELETE 删除 ID 为 :id 的联系人 /api/contacts/:id/star PUT 将 ID 为 :id 的联系人添加到收藏夹 /api/contacts/:id/star DELETE 从收藏夹中删除 ID 为 :id 的联系人 /api/contacts/:id/notes GET 返回 ID 为 :id 的联系人的笔记 /api/contacts/:id/notes/:nid GET 返回 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes POST 为 ID 为 :id 的联系人添加新笔记 /api/contacts/:id/notes/:nid PUT 更新 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes/:nid PATCH 部分更新 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes/:nid DELETE 删除 ID 为 :id 的联系人的 ID 为 :nid 的笔记</code>
首先,我获取当前环境。如果存在名为
<code class="language-json">{ "name": "yourname/my-contacts", "description": "Simple RESTful API for contacts management", "license": "MIT", "authors": [ { "name": "Your Name", "email": "you@yourdomain.com" } ], "require": { "slim/slim": "*", "slim/extras": "*", "slim/middleware": "*", "monolog/monolog": "*", "j4mie/paris": "*", "flynsarmy/slim-monolog": "*" }, "archive": { "exclude": ["vendor", ".DS_Store", "*.log"] }, "autoload": { "psr-0": { "API": "lib/" } } }</code>
配置一个 Monolog 记录器,该记录器写入 app/path/share/logs/EnvName_YYYY-mm-dd.log 的文件。然后,在一些改进之后(您可以在源代码中看到它们),我获取生成的日志写入器并尝试连接到数据库:
<code>bootstrap.php composer.json README.md bin/ import install lib/ API/ public/ .htaccess index.php share/ config/ default.php db/ logs/ sql/ data/ contacts.sql users.sql tables/ contacts.sql notes.sql users.sql ssl/ mysitename.crt mysitename.key</code>
最后,我将所需的中间件添加到我的应用程序实例中。Slim 的中间件就像洋葱的层一样,您添加的第一个中间件将是最内层的,因此我们中间件的顺序很重要。我在我们的 API 中使用以下中间件:- 缓存(最内层);- ContentTypes:解析来自客户端的 JSON 格式的正文;- RateLimit:管理用户的 API 限制;- JSON:“仅 JSON 响应”和“JSON 编码正文”最佳实践的实用程序中间件;- 身份验证(最外层)。我们将编写所有这些,除了预先存在的 ContentTypes。在 bootstrap 文件的末尾,我定义了两个全局变量 $app(应用程序实例)和 $log(日志写入器)。该文件由我们的前端控制器 index.php 加载,在该文件中发生神奇的事情。
路由结构
Slim 有一个名为 Route Groups 的不错的功能。使用此功能,我们可以像这样定义我们的应用程序路由:
<code class="language-apache"><directory> # Required for mod_rewrite in .htaccess AllowOverride FileInfo Options All -Indexes DirectoryIndex index.php index.shtml index.html <ifmodule php5_module=""> # For Development only! php_flag display_errors On </ifmodule> # Enable gzip compression <ifmodule filter_module=""> AddOutputFilterByType DEFLATE application/json </ifmodule> Order deny,allow Deny from all Allow from 127.0.0.1 </directory> <virtualhost> ServerAdmin you@yourdomain.com DocumentRoot "/path/to/MyApp/public" ServerName myapp.dev <ifmodule rewrite_module=""> RewriteEngine on ## Throw a 403 (forbidden) status for non secure requests RewriteCond %{HTTPS} off RewriteRule ^.*$ - [L,R=403] </ifmodule> </virtualhost> <ifmodule ssl_module=""> NameVirtualHost *:443 Listen 443 SSLRandomSeed startup builtin SSLRandomSeed connect builtin <virtualhost> ServerAdmin you@yourdomain.com DocumentRoot "/path/to/MyApp/public" ServerName myapp.dev SSLEngine on SSLCertificateFile /path/to/MyApp/share/ssl/mysitename.crt SSLCertificateKeyFile /path/to/MyApp/share/ssl/mysitename.key SetEnv SLIM_MODE development </virtualhost> </ifmodule></code>
我创建了两个嵌套组 /api 和 /v1,因此我们可以轻松遵守“URL 中的版本控制”最佳实践。我还为 /api/ 创建了一些可选路由,其中可能包含用户可读的内容,以及一个通用的根 URL(/)URL,在现实世界中,该 URL 可能包含应用程序的公共用户界面。
我最初的方法是在 /v1 组内使用路由中间件(另一种 Slim 中间件),用于身份验证和 JSON 请求/响应,但我发现使用经典中间件更实用和简洁。如前所述,中间件是继承自 SlimMiddleware 的类的实例。Slim 中间件的 call() 方法是操作发生的地方,当中间件作为全局中间件链接时,它会自动执行,使用 $app->add() 方法。
<code class="language-php">// Init application mode if (empty($_ENV['SLIM_MODE'])) { $_ENV['SLIM_MODE'] = (getenv('SLIM_MODE')) ? getenv('SLIM_MODE') : 'development'; } // Init and load configuration $config = array(); $configFile = dirname(__FILE__) . '/share/config/' . $_ENV['SLIM_MODE'] . '.php'; if (is_readable($configFile)) { require_once $configFile; } else { require_once dirname(__FILE__) . '/share/config/default.php'; } // Create Application $app = new API\Application($config['app']);</code>
我们的 JSON 中间件实现了两个最佳实践:“仅 JSON 响应”和“JSON 编码正文”。方法如下:
<code>URL HTTP Method Operation /api/contacts GET 返回联系人数组 /api/contacts/:id GET 返回 ID 为 :id 的联系人 /api/contacts POST 添加一个新联系人并返回它(添加了 id 属性) /api/contacts/:id PUT 更新 ID 为 :id 的联系人 /api/contacts/:id PATCH 部分更新 ID 为 :id 的联系人 /api/contacts/:id DELETE 删除 ID 为 :id 的联系人 /api/contacts/:id/star PUT 将 ID 为 :id 的联系人添加到收藏夹 /api/contacts/:id/star DELETE 从收藏夹中删除 ID 为 :id 的联系人 /api/contacts/:id/notes GET 返回 ID 为 :id 的联系人的笔记 /api/contacts/:id/notes/:nid GET 返回 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes POST 为 ID 为 :id 的联系人添加新笔记 /api/contacts/:id/notes/:nid PUT 更新 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes/:nid PATCH 部分更新 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes/:nid DELETE 删除 ID 为 :id 的联系人的 ID 为 :nid 的笔记</code>
我们可以将根路径传递给中间件构造函数。在这种情况下,我传递 /api/v1,以便我们的中间件仅应用于我们站点的 API 部分。如果当前路径与响应内容类型标头匹配,则强制响应内容类型标头为 application/json,然后我检查请求方法。如果请求方法是启用写入的请求方法之一(PUT、POST、PATCH),则请求内容类型标头必须为 application/json,否则应用程序将退出并显示 415 Unsupported Media Type HTTP 状态代码。如果一切正常,语句 $this->next->call() 将运行链中的下一个中间件。
身份验证
由于我们的应用程序默认情况下将在 HTTPS 上运行,因此我决定使用令牌优先于基本身份验证的方法:API 密钥发送到基本 HTTP AUTH 标头的用户名字段中(不需要密码)。为此,我编写了一个名为 TokenOverBasicAuth 的 Slim 中间件类,方法是修改现有的 Slim HttpBasicAuth。此中间件首先在链中运行,因此它作为最后一个添加,并且它在构造函数中采用可选的根路径参数。
<code class="language-json">{ "name": "yourname/my-contacts", "description": "Simple RESTful API for contacts management", "license": "MIT", "authors": [ { "name": "Your Name", "email": "you@yourdomain.com" } ], "require": { "slim/slim": "*", "slim/extras": "*", "slim/middleware": "*", "monolog/monolog": "*", "j4mie/paris": "*", "flynsarmy/slim-monolog": "*" }, "archive": { "exclude": ["vendor", ".DS_Store", "*.log"] }, "autoload": { "psr-0": { "API": "lib/" } } }</code>
该方法在 PHP_AUTH_USER 请求标头中搜索 auth 令牌,如果它不存在或无效,则将 401 禁止状态和身份验证标头传递给客户端。verify() 方法是受保护的,因此可以由子类覆盖;我在这里的版本很简单:
<code>bootstrap.php composer.json README.md bin/ import install lib/ API/ public/ .htaccess index.php share/ config/ default.php db/ logs/ sql/ data/ contacts.sql users.sql tables/ contacts.sql notes.sql users.sql ssl/ mysitename.crt mysitename.key</code>
在这里,我只是检查 users 表中 API 密钥的存在,如果我找到一个有效的用户,则将其添加到应用程序上下文中,以便与下一层(RateLimit)一起使用。您可以修改或扩展此类以注入您自己的身份验证逻辑或使用 OAuth 模块。有关 OAuth 的更多信息,请参阅 Jamie Munro 的文章。
可使用的错误有效负载
如果可能的话,我们的 API 应该以可使用的格式显示有用的错误消息,最好以 JSON 表示形式。我们需要一个包含错误代码和消息的最小有效负载。此外,验证错误需要更多细分。使用 Slim,我们可以分别使用 $app->notFound() 和 $app->error() 方法重新定义 404 错误和服务器错误。
<code>URL HTTP Method Operation /api/contacts GET 返回联系人数组 /api/contacts/:id GET 返回 ID 为 :id 的联系人 /api/contacts POST 添加一个新联系人并返回它(添加了 id 属性) /api/contacts/:id PUT 更新 ID 为 :id 的联系人 /api/contacts/:id PATCH 部分更新 ID 为 :id 的联系人 /api/contacts/:id DELETE 删除 ID 为 :id 的联系人 /api/contacts/:id/star PUT 将 ID 为 :id 的联系人添加到收藏夹 /api/contacts/:id/star DELETE 从收藏夹中删除 ID 为 :id 的联系人 /api/contacts/:id/notes GET 返回 ID 为 :id 的联系人的笔记 /api/contacts/:id/notes/:nid GET 返回 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes POST 为 ID 为 :id 的联系人添加新笔记 /api/contacts/:id/notes/:nid PUT 更新 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes/:nid PATCH 部分更新 ID 为 :id 的联系人的 ID 为 :nid 的笔记 /api/contacts/:id/notes/:nid DELETE 删除 ID 为 :id 的联系人的 ID 为 :nid 的笔记</code>
找不到错误更简单:首先我获取请求的媒体类型,然后 $isAPI 标志告诉我当前 URL 是否位于 /api/v* 组下。如果客户端请求 API URL 或发送 JSON 内容类型标头,我将返回 JSON 输出,否则我可以呈现模板或简单地打印一些静态 HTML,如本例所示。其他错误有点棘手,当出现异常时会触发 $app->error() 方法,Slim 将标准 PHP 错误转换为 ErrorException 对象。我们需要一种方法向客户端提供有用的错误,而不会为了避免安全漏洞而暴露太多内部机制。为此应用程序,我创建了两个自定义异常,APIException 和 APIExceptionValidationException,它们向公众公开,所有其他异常类型都记录在日志中,并且仅在开发模式下显示。
<code class="language-json">{ "name": "yourname/my-contacts", "description": "Simple RESTful API for contacts management", "license": "MIT", "authors": [ { "name": "Your Name", "email": "you@yourdomain.com" } ], "require": { "slim/slim": "*", "slim/extras": "*", "slim/middleware": "*", "monolog/monolog": "*", "j4mie/paris": "*", "flynsarmy/slim-monolog": "*" }, "archive": { "exclude": ["vendor", ".DS_Store", "*.log"] }, "autoload": { "psr-0": { "API": "lib/" } } }</code>
$app->error() 方法接收抛出的异常作为参数。默认情况下,我获取所需的所有数据并填充 $error 数组,然后如果我在生产模式下,我将取消设置私有数据并使用通用数据重写消息。自定义 ValidationException 类具有自定义 getData() 方法,该方法返回添加到最终有效负载的验证错误数组。然后,根据请求以 JSON 或 HTML 显示错误。在 API 端,我们可以有一个简单的错误,如下所示:
<code>bootstrap.php composer.json README.md bin/ import install lib/ API/ public/ .htaccess index.php share/ config/ default.php db/ logs/ sql/ data/ contacts.sql users.sql tables/ contacts.sql notes.sql users.sql ssl/ mysitename.crt mysitename.key</code>
或完整的验证错误,如下所示:
<code class="language-apache"><directory> # Required for mod_rewrite in .htaccess AllowOverride FileInfo Options All -Indexes DirectoryIndex index.php index.shtml index.html <ifmodule php5_module=""> # For Development only! php_flag display_errors On </ifmodule> # Enable gzip compression <ifmodule filter_module=""> AddOutputFilterByType DEFLATE application/json </ifmodule> Order deny,allow Deny from all Allow from 127.0.0.1 </directory> <virtualhost> ServerAdmin you@yourdomain.com DocumentRoot "/path/to/MyApp/public" ServerName myapp.dev <ifmodule rewrite_module=""> RewriteEngine on ## Throw a 403 (forbidden) status for non secure requests RewriteCond %{HTTPS} off RewriteRule ^.*$ - [L,R=403] </ifmodule> </virtualhost> <ifmodule ssl_module=""> NameVirtualHost *:443 Listen 443 SSLRandomSeed startup builtin SSLRandomSeed connect builtin <virtualhost> ServerAdmin you@yourdomain.com DocumentRoot "/path/to/MyApp/public" ServerName myapp.dev SSLEngine on SSLCertificateFile /path/to/MyApp/share/ssl/mysitename.crt SSLCertificateKeyFile /path/to/MyApp/share/ssl/mysitename.key SetEnv SLIM_MODE development </virtualhost> </ifmodule></code>
结论
我们现在已经有了 API 的核心。在下一部分中,我们将添加一些内容,以便拥有一个功能齐全的服务。在此期间,请随时阅读本部分中链接的文章——它们是关于有用 API 设计原则的宝库。
关于从头开始构建 REST API 的常见问题解答 (FAQ)
REST API 由几个关键组件组成。首先是 HTTP 方法,它定义要执行的操作类型。这些包括 GET、POST、PUT、DELETE 等。第二个组件是 URL 或 URI,它是资源标识符。第三个组件是 HTTP 标头,它承载 HTTP 请求和响应的元数据。第四个组件是正文或有效负载,它承载要传输的实际数据。最后,状态代码指示 HTTP 请求的成功或失败。
保护您的 REST API 对于保护敏感数据至关重要。您可以使用各种方法,例如 API 密钥、OAuth 或 JWT 进行身份验证和授权。此外,始终使用 HTTPS 进行数据传输,以确保数据完整性和机密性。定期更新和修补您的 API 及其依赖项,以防范漏洞。
对您的 REST API 进行版本控制允许您引入非破坏性更改,而不会影响现有客户端。您可以通过在 URL 中包含版本号或使用自定义请求标头来对 API 进行版本控制。请记住记录所有更改并告知您的 API 使用者新版本及其功能。
REST API 中正确的错误处理提高了其可用性和可靠性。使用 HTTP 状态代码指示错误类型。在响应正文中包含错误消息,以获取有关错误的更多详细信息。这有助于客户端了解出了什么问题以及如何解决问题。
测试您的 REST API 可确保其按预期工作并可以处理各种场景。您可以使用 Postman 或 curl 等工具进行手动测试。对于自动化测试,请考虑使用单元测试、集成测试和端到端测试。使用模拟服务器来模拟 API 响应并测试您的 API 如何处理不同类型的响应。
良好的文档使您的 REST API 易于理解和使用。包括有关端点、请求方法、请求参数、请求示例、响应状态代码和响应示例的详细信息。您可以使用 Swagger 或 Postman 等工具来生成和托管您的 API 文档。
设计 RESTful API 涉及规划资源、端点和方法。对资源使用名词,对操作使用 HTTP 方法。保持 API 简单直观。使用状态代码指示请求的结果。使您的 API 无状态,这意味着每个请求都应包含处理请求所需的所有信息。
分页有助于限制单个响应中返回的数据量。您可以使用诸如“page”和“limit”之类的查询参数来实现分页。在响应标头或正文中包含元数据,以指示当前页、总页数、总项目数等。
速率限制可保护您的 REST API 免受滥用并确保公平使用。您可以根据 IP 地址、API 密钥或用户帐户限制请求数量。使用 HTTP 标头将速率限制状态传达给客户端。
您可以将您的 REST API 部署到服务器或云平台上。在选择部署选项时,请考虑成本、可扩展性和安全性等因素。使用持续集成和持续交付 (CI/CD) 工具来自动化部署过程。监控您的 API 性能和使用情况,以确保它满足用户的需求。
以上是从头开始构建REST API:简介的详细内容。更多信息请关注PHP中文网其他相关文章!