编程

Laravel 中的 API 版本控制:正确操作的完整指南

374 2023-12-26 02:15:00

确保 API 保持一致性和可靠性类似于在风暴期间保持船只稳定。随着应用的增长和变化,你需要管理 API 的不同版本。Laravel 是一个流行的 PHP 框架,它提供了大量的工具来帮助您在这些波涛汹涌的水域中导航。但有这么多路要走,你如何确保自己走在正确的道路上?请进入 API 版本控制。

您可以通过多种方式对 Laravel API 进行版本控制,但最直接的方法是使用 URI 进行版本控制。URI 路径将包含 /v*/ ,其中 * 是版本号。在这里,您通常不会完全使用 API 版本控制来进行语义版本控制,因为这可能会给那些与 API 集成的人带来痛苦的问题。相反,您将重点放在主要版本约束上,并尽量远离这些版本中的更改。

通常,Laravel 应用的 routes 目录中会有一些路由文件。我们在这里关心的主要是 web.phpapi.php,我们在其中注册 Laravel 的所有web 和 api 路由。这是通过 app/Providers/RouteServiceProvider.php 加载的,至少在编写时是这样,其中Laravel 10 是我们考虑的主要版本。当 Laravel 11 发布时,随着其新的轻量级框架,我们可能不得不重新思考某些事情。

RouteServiceProvider 中,我们有以下代码,这些代码加载到应用的路由文件中。

public function boot(): void  
{  
	// Rate Limiter 
  
	$this->routes(function (): void {  
		Route::middleware('api')->prefix('api')->group(  
			base_path('routes/api.php'),  
		);  
  
		Route::middleware('web')->group(  
			base_path('routes/web.php'),  
		);  
	});  
}  

这告诉我 Laravel 应用加载 web 和 API 路由,一个带有 api 前缀,另一个没有。它还指定了要加载的路由应该遵循哪些中间件组。

如果您正在构建一个同时具有 Web 和 API 接口的应用,请保持原样——这是完全可以的。如果删除 web 接口并使用 API 应用,则删除前缀和 web 路由定义,因为您不需要它。

Laravel API 版本控制的秘籍

如果应用同时使用 web 和 API 接口,我喜欢做的是在 routes 目录中创建额外的目录,因此我最终使用以下设置:

  • routes/web/routes.php
  • routes/api/routes.php

这使我能够将它们完全分离,并且可以随心所欲地拆分路由分组,而无需担心 web 和 API 路由文件之间的文件命名冲突。

让我们以一家销售公司 swag 的电子商务商店为例。如果这是一个只用 API 的平台,我们将提供产品、订单和类别等路由,以便人们可以搜索、订购他们可能想要的东西。我们可以将所有这些保存在一个中央 routes.php 文件中。然而,随着应用程序越来越大,管理这样的大文件变得越来越困难。让我们看看一个这样的例子,特别是如果您也要在 API 中实现版本控制。

Route::prefix('v1')->as('v1:')->group(static function (): void {
	Route::prefix('orders')->as('orders:')->group(static function (): void {
		Route::get('/', Orders\V1\ListHandler::class)->name('list');
	});

	Route::prefix('products')->as('products:')->group(static function (): void {
		Route::get('/', Products\V1\ListHandler::class)->name('list');
	});
});

Route::prefix('v2')->as('v2:')->group(static function (): void {
	Route::prefix('orders')->as('orders:')->group(static function (): void {
		Route::get('/', Orders\V2\ListHandler::class)->name('list');
	});

	Route::prefix('products')->as('products:')->group(static function (): void {
		Route::get('/', Products\V2\ListHandler::class)->name('list');
	});
});

这只是两个端点,都相对简单。然而,从视觉上看,这可能有很多需要考虑的地方。在构建 Laravel 应用时,我们需要考虑使用该应用的认知负担。如果你必须在应用中寻找和搜索一个简单的路线定义,那么当你得到你需要处理的实际代码时,你会如何?

此处我想做电商是,以以下方式构建主入口路由文件:

Route::prefix('v1')->as('v1:')->group(
	base_path('routes/v1/routes.php'),
);

Route::prefix('v2')->as('v2:')->group(
	base_path('routes/v2/routes.php'),
);

这使得入口点变得简单明了,只需指向不同的位置即可。如果您关心 v1 路由,请检查该文件。这是可以预测的。您知道,只要打开带有一个文件的路由目录和以 API 版本命名的目录,您就立即知道该在哪里查找。您可以从这里轻松导航,从而减少管理应用程序的认知负荷。让我们看看routes/v1/routes.php 内部,了解如何将其拆分。

Route::prefix('orders')->as('orders:')->group(
	base_path('routes/v1/orders.php'),
);

Route::prefix('products')->as('orders:')->group(
	base_path('routes/v1/products.php'),
);

我们通过将分组的路由分离成单独的文件来进一步划分路由,从而进一步减少认知负担。因此,当我们打开 routes/v1 时,我们可以一眼看到应用中的所有路由组,并直接转到我们知道需要查看的组。此外,这不会因为包含多个文件而影响应用的性能,因为您通常会在生产中缓存路由——这会将所有路由合并为一个易于框架读取的文件。

为了反映这一点,我们的控制器或 handler 也在相应的命名空间中进行管理,从而允许在应用中轻松遍历。我见过一些人会为路由组和加载覆盖 RouteServiceProvider。我也曾经是那种人。然而,与直接访问路由文件本身相比,我发现查看路由服务提供商来理解分组是不直观的。

对您的 Laravel API 进行版本控制很容易,但需要仔细规划和考虑。最好考虑明天将要使用的 API,而不是今天必须满足的要求。