使用不同语言环境测试 API 验证错误
发表于 作者 Paul Redmond
您是否曾经想过如何在不同的语言环境下提供 API 验证错误和翻译?这篇初学者文章将向您展示如何在无状态的 Laravel API 中设置语言环境以及测试各种语言环境验证消息。
相关的是,如果您想快速将翻译拉入您的项目以进行验证,我们已经介绍了一个名为 Laravel-lang - Laravel 翻译 的软件包。Larvel-lang 包含 68 种语言的翻译,包括身份验证和验证(以及其他)的翻译。
现在,我们将跳过安装此软件包,并从 Laravel 提供的用于语言环境支持的内置功能开始。
入门
首先,我们将创建一个新的 Laravel 项目来开始。本教程不会利用任何语言环境软件包。
laravel new locale-apicd locale-api
接下来,让我们创建将用于演示无状态 API 中语言环境工作原理的文件。
php artisan make:middleware DetectLocalephp artisan make:controller ProfileControllerphp artisan make:test LocaleDetectionTest mkdir -p resources/lang/es/touch resources/lang/es/validation.php
我们将通过中间件设置 API 语言环境,该中间件将尝试设置首选语言环境。我们创建了一个控制器和测试,以便我们可以演示一些可以在 API 中执行的验证测试。
最后,我们正在为西班牙语创建一个新的验证文件,以演示 API 验证错误的本地化。
我们不会安装完整的 Laravel-lang 软件包,但对于本教程,请获取 es/validation.php 的内容并将其添加到我们上面创建的 resources/lang/es/validation.php
文件中。
中间件
虽然我通常使用 TDD,但我们将先创建中间件和控制器,然后创建一个测试作为使用中间件的一种方式。DetectLocale
中间件对于我们的目的很简单,因为 API 是无状态的;我们将依赖用户在请求中发送 Accept-Locale
标头。您也可以检查查询字符串参数以设置语言环境,但我们将保持简单。
<?php namespace App\Http\Middleware; use Closure; class DetectLocale{ /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param mixed ...$locales * @return mixed */ public function handle($request, Closure $next, ...$locales) { $locales = $locales ?: ['en']; if ($language = $request->getPreferredLanguage($locales)) { app()->setLocale($language); } return $next($request); }}
我们的中间件获取一个 $locales
配置,它是一个支持语言的数组。然后,我们调用 Symfony HTTP Foundation 组件提供的超级方便的 Request::getPreferredLanguage()
方法,该方法获取可用的语言环境的排序数组并返回首选语言环境。
如果该方法返回首选语言环境,我们通过 Laravel 的 App::setLocale()
方法设置它。
接下来,我们在 app/Http/Kernel.php
文件中配置中间件。
protected $routeMiddleware = [ // ... 'locale' => \App\Http\Middleware\DetectLocale::class,];
最后,在同一个文件中,我们将 locale
中间件添加到 api
组,并使用首选语言环境。
protected $middlewareGroups = [ // ... 'api' => [ 'throttle:60,1', 'bindings', 'locale:en,es', ],];
控制器
我们不会编写完整的控制器;我们只将创建一个简单的验证检查来触发一些验证规则。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class ProfileController extends Controller{ public function store(Request $request) { $request->validate([ 'name' => 'required', 'email' => 'required|email' ]); return response()->json(['status' => 'OK']); }}
此控制器将验证名称和电子邮件输入,如果验证失败,将抛出异常,返回 422 Unprocessable Entity
状态代码和 JSON 验证错误。
接下来,我们需要在 routes/api.php
中定义路由。
<?php Route::post('/profile', 'ProfileController@store');
接下来,我们将使用我们在 LocaleDetectionTest
中创建的功能测试中的示例测试用例。
<?php namespace Tests\Feature; use Illuminate\Http\Response;use Tests\TestCase; class LocaleDetectionTest extends TestCase{ /** * A basic feature test example. * * @return void */ public function testExample() { $response = $this ->withHeaders([ 'Accept-Language' => 'es', ]) ->postJson('/api/profile', [ 'email' => 'invalid.email', ]); $response ->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY) ->assertJsonPath('errors.email', ['correo electrónico no es un correo válido']) ->assertJsonPath('errors.name', ['El campo nombre es obligatorio.']); }}
我们的测试向我们的个人资料端点发送 JSON POST 请求,并使用 es
(西班牙语)发送 Accept-Language
标头。正如您在运行测试时所看到的,当我们使用在 Laravel 6.0.4 中添加的新的 assertJsonPath()
进行断言时,测试通过了。
如果将 JSON 作为数组转储出来,您可以看到消息是英文的。
dd($response->decodeResponseJson());..array:2 [ "message" => "The given data was invalid." "errors" => array:2 [ "name" => array:1 [ 0 => "El campo nombre es obligatorio." ] "email" => array:1 [ 0 => "correo electrónico no es un correo válido" ] ]]
我们不会在本教程中深入探讨解决这个问题,但也许我们会写一篇后续文章,更详细地介绍 API 其他部分的翻译。一个简单的解决方案可能是捕获 ValidationException
消息并使用消息的翻译。
另一件需要考虑的事情是尝试一下当您发送不支持的语言时会发生什么。我给您一个提示:Symonfy 的 getPreferredLanguage()
将返回您传递给它的第一个首选语言(在本例中为 en
,它是数组中的第一个)。尝试更改首选语言环境的顺序,并使用不支持的语言环境进行测试。
好了,这就是我们对在 Laravel API 中设置语言环境的简单方法的简要介绍。我要感谢 Yaz Jallad (@ninjaparade),他昨天在和我讨论这个话题。从我们的讨论中,我对如何在 API 中添加验证翻译感到好奇——我以前从未做过——并想在稍微研究之后写一篇简短的文章。
要了解有关 Laravel 中本地化的更多信息,请查看 本地化文档。