Je ne reçois pas la réponse que j'attends.
C'est le code du contrôleur pour une demande de service Web Location:
<?php
namespace App\Http\Controllers;
use App\Location;
use Illuminate\Http\Request;
class LocationController extends Controller
{
/**
* Action method to add a location with the supplied Data
*
* @param \Illuminate\Http\Request $p_oRequest Request
*
* @return JSON
*/
public function add(Request $p_oRequest)
{
try {
$p_oRequest->validate(
array(
'name' => 'required|alpha_num',
'user_id' => 'required|integer',
),
array(
'name.required' => 'Name is required',
'name.string' => 'Name must be alphanumeric',
'user_id.required' => 'Curator User Id is required',
'user_id.required' => 'Curator User Id must be an integer',
)
);
} catch (\Exception $ex) {
$arrResponse = array(
'result' => 0,
'reason' => $ex->getMessage(),
'data' => array(),
'statusCode' => 404
);
} finally {
return response()->json($arrResponse);
}
}
}
La requête est http: //mydomain/index.php/api/v1/location/add? Name = @ ! ^
La raison de la réponse que j'attends est la suivante: {"résultat": 0, "raison": "Le nom doit être alphanumérique", "données": [], "code d'état": 404}
A la place, la réponse que je reçois est la suivante: {"résultat": 0, "raison": "Les données fournies étaient invalides.", "Données": [], "code d'état": 404}
S'il vous plaît aider. Ceci me dérange.
Le problème est probablement que le gestionnaire d'exception par défaut de Laravel n'est pas prêt à renvoyer des informations de validation détaillées à l'utilisateur. Au lieu de cela, il cache les détails des exceptions à l'utilisateur, ce qui est normalement la bonne chose à faire car cela pourrait constituer un risque de sécurité pour les autres exceptions que celles de validation.
En d'autres termes; Si la fonction render
du gestionnaire d'exception (implémentée dans /app/Exceptions/Handler.php
) intercepte vos erreurs de validation, elles seront interprétées comme une exception d'application générale et le message d'erreur général renvoyé à l'utilisateur indiquera toujours "Les données fournies étaient invalides".
Assurez-vous que la méthode render
ignore les instances de \Illuminate\Validation\ValidationException
et vous devriez obtenir la réponse attendue:
public function render($request, Exception $exception) {
if (! $exception instanceof \Illuminate\Validation\ValidationException)) {
// ... render code for other Exceptions here
}
}
Une autre façon de rendre les détails de ValidationException du relais du gestionnaire d'exception avec la réponse est de faire quelque chose comme ceci dans la méthode render
:
if ($exception instanceof ValidationException && $request->expectsJson()) {
return response()->json(['message' => 'The given data was invalid.', 'errors' => $exception->validator->getMessageBag()], 422);
}
Laravel utilise essentiellement (ab) les exceptions ici. Normalement, une exception indique un problème (d'exécution) dans le code, mais Laravel les utilise comme mécanisme pour faciliter la validation de la demande et fournir un retour à l'utilisateur. C'est pourquoi, dans ce cas, il serait incorrect de laisser votre gestionnaire d'exception gérer l'exception - ce n'est pas une application, c'est une information destinée à l'utilisateur.
Le code dans la réponse fournie par OP fonctionne, car il intercepte la ValidationException lui-même, l'empêchant ainsi d'être intercepté par le gestionnaire d'exception de l'application. Je ne pense pas que ce serait souhaitable, car il s’agit d’un mélange clair de préoccupations et d’un code horriblement long et illisible. Ignorer simplement les ValidationExceptions ou les traiter différemment dans le gestionnaire d'exceptions, comme je l'ai montré ci-dessus, devrait suffire.
J'ai enfin découvert pourquoi cela ne fonctionne pas. Ce n'est pas un problème d'erreurs dans le code d'implémentation ou dans Laravel, mais dans l'un des cas suivants: (i). écrire du bon code PHP pour gérer le résultat évident, ce que je n'ai clairement pas fait; (ii). documentation insuffisante dans Laravel sur la manière d'utiliser réellement la réponse d'erreur de validation. Faites votre choix.
La validation de Laravel génère une requête Illuminate\Validation\ValidationError. Croyez-le ou non, le message d'erreur par défaut est "Les données fournies sont invalides.", Donc lorsque vous attrapez une\Exception et récupérez sa $ e-> getMessage (), ce message d'erreur par défaut est ce que vous (correctement) obtenir.
Ce que vous devez faire, c'est capturer\Illuminate\Validation\ValidationError - ce que j'aurais dû faire à l'origine, duh! - puis utilisez ses méthodes pour vous aider à en extraire les messages d'erreur.
Voici la solution que j'ai trouvée:
<?php
namespace App\Http\Controllers;
use App\Location;
use Illuminate\Http\Request;
class LocationController extends Controller
{
/**
* Action method to add a location with the supplied Data
*
* @param \Illuminate\Http\Request $p_oRequest Request
*
* @return JSON
*/
public function add(Request $p_oRequest)
{
try {
$arrValid = array(
'name' => 'required|alpha_num',
'user_id' => 'required|integer',
);
$p_oRequest->validate(
$arrValid,
array(
'name.required' => 'Name is missing',
'name.alpha_num' => 'Name must be alphanumeric',
'user_id.required' => 'User Id is missing',
'user_id.integer' => 'User Id must be an integer',
)
);
} catch (\Illuminate\Validate\ValidationException $e ) {
/**
* Validation failed
* Tell the end-user why
*/
$arrError = $e->errors(); // Useful method - thank you Laravel
/**
* Compile a string of error-messages
*/
foreach ($arrValid as $key=>$value ) {
$arrImplode[] = implode( ', ', $arrError[$key] );
}
$message = implode(', ', $arrImplode);
/**
* Populate the respose array for the JSON
*/
$arrResponse = array(
'result' => 0,
'reason' => $message,
'data' => array(),
'statusCode' => $e->status,
);
} catch (\Exception $ex) {
$arrResponse = array(
'result' => 0,
'reason' => $ex->getMessage(),
'data' => array(),
'statusCode' => 404
);
} finally {
return response()->json($arrResponse);
}
}
}
Donc, en effet, Laravel fournissait la bonne réponse et a fait ce qu'il dit du côté de la boîte, mais je ne l'ai pas appliquée correctement. Quoi qu'il en soit, je propose la solution à mes futurs navigateurs PHP et moi-mêmes ainsi qu'à d'autres marins perdus de PHP.
En outre, merci à Marcin d'avoir signalé mon codage en buggy, ce qui aurait posé problème même si j'avais implémenté la solution ci-dessus.
Vos messages doivent être des règles de validation, donc au lieu de:
'name.required' => 'Name is required',
'name.string' => 'Name must be alphanumeric',
'user_id.required' => 'Curator User Id is required',
'user_id.required' => 'Curator User Id must be an integer',
tu aurais dû:
'name.required' => 'Name is required',
'name.alpha_num' => 'Name must be alphanumeric',
'user_id.required' => 'Curator User Id is required',
'user_id.integer' => 'Curator User Id must be an integer',
Je viens juste de voir cela, mais tout ce que vous avez à faire est de déplacer l'appel de validation avant le try/catch
$p_oRequest->validate(
[
'name' => 'required|alpha_num',
'user_id' => 'required|integer',
],
[
'name.required' => 'Name is required',
'name.string' => 'Name must be alphanumeric',
'user_id.required' => 'Curator User Id is required',
'user_id.required' => 'Curator User Id must be an integer',
]
);
try {
...
} catch(\Exception $e) {
return back()->withErrors($e->getMessage())->withInput();
}
Parce que Laravel intercepte l’exception de validation automatiquement et vous renvoie l’ancienne entrée et un tableau d’erreurs que vous pouvez générer comme
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif