Laravel Validation Request & API route POST parameter
up vote
0
down vote
favorite
I'm facing a little issue with Form Request Validation and how to handle it with one API route.
The resource that I need to create depends on an other resource.
(Here an EmailSettings belongs to a Tenant)
So the look of my route should be something like : /api/tenants/id/email_settings
And my request validation expects several fields including the tenantId :
public function rules() required
And I send the request like this :
try
const response = await this.tenantForm.post('/api/tenants')
let newTenant = helpers.getNewResourceFromResponseHeaderLocation(response)
let tenantId = parseInt(newTenant.id);
try
await this.emailSettingsForm.post('/api/tenants/' + tenantId + '/email_settings')
this.requestAllTenants()
catch (response)
$('.second.modal').modal(blurring: true, closable: false).modal('show');
catch (response)
$('.first.modal').modal(blurring: true).modal('show');
So the tenantId is passed as a parameter and not in the request body to respect the REST convention.
But the problem is in my Controller, when I merge the data to create the resource, the validation has already took place only on body data before the merge.
public function store(EmailSettingValidation $request, $tenant_id)
$emailSetting = $this->emailSettingService->create(
array_merge($request->all(), compact($tenant_id))
);
return $this->response->created($emailSetting);
So what is the best way to handle it properly ?
- Pass the id in the body ? Seems messy
- Use Validator to validate manually ? I would prefer to keep Form Validation
- Remove the tenantId rule and check it manually ?
Any suggestions ?
Thank you
laravel rest api validation
add a comment |
up vote
0
down vote
favorite
I'm facing a little issue with Form Request Validation and how to handle it with one API route.
The resource that I need to create depends on an other resource.
(Here an EmailSettings belongs to a Tenant)
So the look of my route should be something like : /api/tenants/id/email_settings
And my request validation expects several fields including the tenantId :
public function rules() required
And I send the request like this :
try
const response = await this.tenantForm.post('/api/tenants')
let newTenant = helpers.getNewResourceFromResponseHeaderLocation(response)
let tenantId = parseInt(newTenant.id);
try
await this.emailSettingsForm.post('/api/tenants/' + tenantId + '/email_settings')
this.requestAllTenants()
catch (response)
$('.second.modal').modal(blurring: true, closable: false).modal('show');
catch (response)
$('.first.modal').modal(blurring: true).modal('show');
So the tenantId is passed as a parameter and not in the request body to respect the REST convention.
But the problem is in my Controller, when I merge the data to create the resource, the validation has already took place only on body data before the merge.
public function store(EmailSettingValidation $request, $tenant_id)
$emailSetting = $this->emailSettingService->create(
array_merge($request->all(), compact($tenant_id))
);
return $this->response->created($emailSetting);
So what is the best way to handle it properly ?
- Pass the id in the body ? Seems messy
- Use Validator to validate manually ? I would prefer to keep Form Validation
- Remove the tenantId rule and check it manually ?
Any suggestions ?
Thank you
laravel rest api validation
Do you have a model for your tenant table?
– Travis Britz
Nov 9 at 13:57
@TravisBritz Yes, but why is it important?
– guillaumehanotel
Nov 9 at 14:01
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I'm facing a little issue with Form Request Validation and how to handle it with one API route.
The resource that I need to create depends on an other resource.
(Here an EmailSettings belongs to a Tenant)
So the look of my route should be something like : /api/tenants/id/email_settings
And my request validation expects several fields including the tenantId :
public function rules() required
And I send the request like this :
try
const response = await this.tenantForm.post('/api/tenants')
let newTenant = helpers.getNewResourceFromResponseHeaderLocation(response)
let tenantId = parseInt(newTenant.id);
try
await this.emailSettingsForm.post('/api/tenants/' + tenantId + '/email_settings')
this.requestAllTenants()
catch (response)
$('.second.modal').modal(blurring: true, closable: false).modal('show');
catch (response)
$('.first.modal').modal(blurring: true).modal('show');
So the tenantId is passed as a parameter and not in the request body to respect the REST convention.
But the problem is in my Controller, when I merge the data to create the resource, the validation has already took place only on body data before the merge.
public function store(EmailSettingValidation $request, $tenant_id)
$emailSetting = $this->emailSettingService->create(
array_merge($request->all(), compact($tenant_id))
);
return $this->response->created($emailSetting);
So what is the best way to handle it properly ?
- Pass the id in the body ? Seems messy
- Use Validator to validate manually ? I would prefer to keep Form Validation
- Remove the tenantId rule and check it manually ?
Any suggestions ?
Thank you
laravel rest api validation
I'm facing a little issue with Form Request Validation and how to handle it with one API route.
The resource that I need to create depends on an other resource.
(Here an EmailSettings belongs to a Tenant)
So the look of my route should be something like : /api/tenants/id/email_settings
And my request validation expects several fields including the tenantId :
public function rules() required
And I send the request like this :
try
const response = await this.tenantForm.post('/api/tenants')
let newTenant = helpers.getNewResourceFromResponseHeaderLocation(response)
let tenantId = parseInt(newTenant.id);
try
await this.emailSettingsForm.post('/api/tenants/' + tenantId + '/email_settings')
this.requestAllTenants()
catch (response)
$('.second.modal').modal(blurring: true, closable: false).modal('show');
catch (response)
$('.first.modal').modal(blurring: true).modal('show');
So the tenantId is passed as a parameter and not in the request body to respect the REST convention.
But the problem is in my Controller, when I merge the data to create the resource, the validation has already took place only on body data before the merge.
public function store(EmailSettingValidation $request, $tenant_id)
$emailSetting = $this->emailSettingService->create(
array_merge($request->all(), compact($tenant_id))
);
return $this->response->created($emailSetting);
So what is the best way to handle it properly ?
- Pass the id in the body ? Seems messy
- Use Validator to validate manually ? I would prefer to keep Form Validation
- Remove the tenantId rule and check it manually ?
Any suggestions ?
Thank you
laravel rest api validation
laravel rest api validation
edited Nov 9 at 14:05
asked Nov 9 at 13:48
guillaumehanotel
14
14
Do you have a model for your tenant table?
– Travis Britz
Nov 9 at 13:57
@TravisBritz Yes, but why is it important?
– guillaumehanotel
Nov 9 at 14:01
add a comment |
Do you have a model for your tenant table?
– Travis Britz
Nov 9 at 13:57
@TravisBritz Yes, but why is it important?
– guillaumehanotel
Nov 9 at 14:01
Do you have a model for your tenant table?
– Travis Britz
Nov 9 at 13:57
Do you have a model for your tenant table?
– Travis Britz
Nov 9 at 13:57
@TravisBritz Yes, but why is it important?
– guillaumehanotel
Nov 9 at 14:01
@TravisBritz Yes, but why is it important?
– guillaumehanotel
Nov 9 at 14:01
add a comment |
3 Answers
3
active
oldest
votes
up vote
0
down vote
If you define your api route like this:
Roue::post('tenants/tenant/emails_settings', 'Controller@store');
and modify your controller method to type-hint the model with a matching variable name:
public function store(EmailSettingValidation $request, Tenant $tenant)
Laravel will automatically find the Tenant by ID and inject it into the controller, throwing a ModelNotFoundException (404) if it doesn't exist. That should take care of validating the id.
Authorization is another matter.
Your solution works well (if we add the middleware 'bindings' to the route) but when the Tenant doesn't exist, it returns "500 : No query results for model [AppTenant]" and not 404 and I don't know why :/
– guillaumehanotel
Nov 9 at 14:44
@guillaumehanotel what version of Laravel is this?
– Travis Britz
Nov 9 at 14:47
This is version 5.5
– guillaumehanotel
Nov 9 at 14:48
@guillaumehanotel does yourweb
middleware group include theIlluminateRoutingMiddlewareSubstituteBindings::class,
?
– Travis Britz
Nov 9 at 14:50
Yes but I defined my routes in the api.php so the web group doesn't apply
– guillaumehanotel
Nov 9 at 14:53
|
show 5 more comments
up vote
0
down vote
accepted
So the solution I found to trigger 404 is the following :
- Remove the tenantId from EmailSettings Validation
- Add a provider to add a custom error when the exception 'ModelNotFoundException' occurs like here
No query results for model in Laravel with Dingo - how to make a RESTful response on failure? Try to throw this Exception with the findOrFail method if invalid ID :
public function store(EmailSettingValidation $request, $tenant_id)
Tenant::findOrFail($tenant_id);
$emailSetting = $this->emailSettingService->create(
array_merge($request->all(), ['tenantId' => $tenant_id])
);
return $this->response->created($emailSetting);
add a comment |
up vote
0
down vote
Travis Britz and Guillaumehanotel each have half of your answer, but you're still missing a detail.
From Travis Britz- Yes, include the tenant_id on the URI so it gets injected into the controller.
From Guillaumehanotel- Also used the Eloquent findOrFail in that Id in your Controller (or whatever class the Controller is leveraging to do this, like a Repository or Service class).
The last piece you're missing though is handling the error. You can do this in the Controller if you like, but I generally like making it a rule for my entire system that the IlluminateDatabaseEloquentModelNotFoundException
Exceptions that come out of findOrFail()
should always result in a 404.
Go to app/Exceptions/Handler.php
. I'm pretty sure Laravel auto-generates a meat and potatoes version of this file for you, but if you don't already have one, it should look something like this:
<?php
namespace AppExceptions;
use IlluminateFoundationExceptionsHandler as ExceptionHandler;
/**
* Class Handler
* @package AppExceptions
*/
class Handler extends ExceptionHandler
/**
* Render an exception into an HTTP response.
*
* For our API, we need to override the call
* to the parent.
*
* @param IlluminateHttpRequest $request
* @param Exception $e
* @return IlluminateHttpResponse
*/
public function render($request, Exception $error)
$exception = [
'title' => 'Internal Error',
'message' => $error->getMessage();
];
$statusCode = 500;
$headers = [
'Content-Type', 'application/json'
];
return response()->json($exception, $statusCode, $headers, JSON_PRETTY_PRINT);
Laravel basically has a system-wide try/catch
that sends all errors through here first. That's how errors get rendered into something the browser can actually interpret when you're in debug-mode, rather than just kill the process outright. This also gives you the opportunity to apply a few special rules.
So all you need to do is tell Handler::render()
to change the default error code that occurs when it sees the type of error that can only come from findOrFail()
. (This kind of thing is why it's always good to make your own 'named exceptions', even if they do absolutely nothing except inherit the base Exception
class.)
Just add this just before render()
returns anything:
if ($error instanceof IlluminateDatabaseEloquentModelNotFoundException)
$statusCode = 404;
This is already the default behavior of Laravel. The reason for the 500 status code is an external library they're using (dingo/api) that has its own exception handling.
– Travis Britz
Nov 10 at 4:45
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53226948%2flaravel-validation-request-api-route-post-parameter%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
If you define your api route like this:
Roue::post('tenants/tenant/emails_settings', 'Controller@store');
and modify your controller method to type-hint the model with a matching variable name:
public function store(EmailSettingValidation $request, Tenant $tenant)
Laravel will automatically find the Tenant by ID and inject it into the controller, throwing a ModelNotFoundException (404) if it doesn't exist. That should take care of validating the id.
Authorization is another matter.
Your solution works well (if we add the middleware 'bindings' to the route) but when the Tenant doesn't exist, it returns "500 : No query results for model [AppTenant]" and not 404 and I don't know why :/
– guillaumehanotel
Nov 9 at 14:44
@guillaumehanotel what version of Laravel is this?
– Travis Britz
Nov 9 at 14:47
This is version 5.5
– guillaumehanotel
Nov 9 at 14:48
@guillaumehanotel does yourweb
middleware group include theIlluminateRoutingMiddlewareSubstituteBindings::class,
?
– Travis Britz
Nov 9 at 14:50
Yes but I defined my routes in the api.php so the web group doesn't apply
– guillaumehanotel
Nov 9 at 14:53
|
show 5 more comments
up vote
0
down vote
If you define your api route like this:
Roue::post('tenants/tenant/emails_settings', 'Controller@store');
and modify your controller method to type-hint the model with a matching variable name:
public function store(EmailSettingValidation $request, Tenant $tenant)
Laravel will automatically find the Tenant by ID and inject it into the controller, throwing a ModelNotFoundException (404) if it doesn't exist. That should take care of validating the id.
Authorization is another matter.
Your solution works well (if we add the middleware 'bindings' to the route) but when the Tenant doesn't exist, it returns "500 : No query results for model [AppTenant]" and not 404 and I don't know why :/
– guillaumehanotel
Nov 9 at 14:44
@guillaumehanotel what version of Laravel is this?
– Travis Britz
Nov 9 at 14:47
This is version 5.5
– guillaumehanotel
Nov 9 at 14:48
@guillaumehanotel does yourweb
middleware group include theIlluminateRoutingMiddlewareSubstituteBindings::class,
?
– Travis Britz
Nov 9 at 14:50
Yes but I defined my routes in the api.php so the web group doesn't apply
– guillaumehanotel
Nov 9 at 14:53
|
show 5 more comments
up vote
0
down vote
up vote
0
down vote
If you define your api route like this:
Roue::post('tenants/tenant/emails_settings', 'Controller@store');
and modify your controller method to type-hint the model with a matching variable name:
public function store(EmailSettingValidation $request, Tenant $tenant)
Laravel will automatically find the Tenant by ID and inject it into the controller, throwing a ModelNotFoundException (404) if it doesn't exist. That should take care of validating the id.
Authorization is another matter.
If you define your api route like this:
Roue::post('tenants/tenant/emails_settings', 'Controller@store');
and modify your controller method to type-hint the model with a matching variable name:
public function store(EmailSettingValidation $request, Tenant $tenant)
Laravel will automatically find the Tenant by ID and inject it into the controller, throwing a ModelNotFoundException (404) if it doesn't exist. That should take care of validating the id.
Authorization is another matter.
answered Nov 9 at 14:11
Travis Britz
1,01946
1,01946
Your solution works well (if we add the middleware 'bindings' to the route) but when the Tenant doesn't exist, it returns "500 : No query results for model [AppTenant]" and not 404 and I don't know why :/
– guillaumehanotel
Nov 9 at 14:44
@guillaumehanotel what version of Laravel is this?
– Travis Britz
Nov 9 at 14:47
This is version 5.5
– guillaumehanotel
Nov 9 at 14:48
@guillaumehanotel does yourweb
middleware group include theIlluminateRoutingMiddlewareSubstituteBindings::class,
?
– Travis Britz
Nov 9 at 14:50
Yes but I defined my routes in the api.php so the web group doesn't apply
– guillaumehanotel
Nov 9 at 14:53
|
show 5 more comments
Your solution works well (if we add the middleware 'bindings' to the route) but when the Tenant doesn't exist, it returns "500 : No query results for model [AppTenant]" and not 404 and I don't know why :/
– guillaumehanotel
Nov 9 at 14:44
@guillaumehanotel what version of Laravel is this?
– Travis Britz
Nov 9 at 14:47
This is version 5.5
– guillaumehanotel
Nov 9 at 14:48
@guillaumehanotel does yourweb
middleware group include theIlluminateRoutingMiddlewareSubstituteBindings::class,
?
– Travis Britz
Nov 9 at 14:50
Yes but I defined my routes in the api.php so the web group doesn't apply
– guillaumehanotel
Nov 9 at 14:53
Your solution works well (if we add the middleware 'bindings' to the route) but when the Tenant doesn't exist, it returns "500 : No query results for model [AppTenant]" and not 404 and I don't know why :/
– guillaumehanotel
Nov 9 at 14:44
Your solution works well (if we add the middleware 'bindings' to the route) but when the Tenant doesn't exist, it returns "500 : No query results for model [AppTenant]" and not 404 and I don't know why :/
– guillaumehanotel
Nov 9 at 14:44
@guillaumehanotel what version of Laravel is this?
– Travis Britz
Nov 9 at 14:47
@guillaumehanotel what version of Laravel is this?
– Travis Britz
Nov 9 at 14:47
This is version 5.5
– guillaumehanotel
Nov 9 at 14:48
This is version 5.5
– guillaumehanotel
Nov 9 at 14:48
@guillaumehanotel does your
web
middleware group include the IlluminateRoutingMiddlewareSubstituteBindings::class,
?– Travis Britz
Nov 9 at 14:50
@guillaumehanotel does your
web
middleware group include the IlluminateRoutingMiddlewareSubstituteBindings::class,
?– Travis Britz
Nov 9 at 14:50
Yes but I defined my routes in the api.php so the web group doesn't apply
– guillaumehanotel
Nov 9 at 14:53
Yes but I defined my routes in the api.php so the web group doesn't apply
– guillaumehanotel
Nov 9 at 14:53
|
show 5 more comments
up vote
0
down vote
accepted
So the solution I found to trigger 404 is the following :
- Remove the tenantId from EmailSettings Validation
- Add a provider to add a custom error when the exception 'ModelNotFoundException' occurs like here
No query results for model in Laravel with Dingo - how to make a RESTful response on failure? Try to throw this Exception with the findOrFail method if invalid ID :
public function store(EmailSettingValidation $request, $tenant_id)
Tenant::findOrFail($tenant_id);
$emailSetting = $this->emailSettingService->create(
array_merge($request->all(), ['tenantId' => $tenant_id])
);
return $this->response->created($emailSetting);
add a comment |
up vote
0
down vote
accepted
So the solution I found to trigger 404 is the following :
- Remove the tenantId from EmailSettings Validation
- Add a provider to add a custom error when the exception 'ModelNotFoundException' occurs like here
No query results for model in Laravel with Dingo - how to make a RESTful response on failure? Try to throw this Exception with the findOrFail method if invalid ID :
public function store(EmailSettingValidation $request, $tenant_id)
Tenant::findOrFail($tenant_id);
$emailSetting = $this->emailSettingService->create(
array_merge($request->all(), ['tenantId' => $tenant_id])
);
return $this->response->created($emailSetting);
add a comment |
up vote
0
down vote
accepted
up vote
0
down vote
accepted
So the solution I found to trigger 404 is the following :
- Remove the tenantId from EmailSettings Validation
- Add a provider to add a custom error when the exception 'ModelNotFoundException' occurs like here
No query results for model in Laravel with Dingo - how to make a RESTful response on failure? Try to throw this Exception with the findOrFail method if invalid ID :
public function store(EmailSettingValidation $request, $tenant_id)
Tenant::findOrFail($tenant_id);
$emailSetting = $this->emailSettingService->create(
array_merge($request->all(), ['tenantId' => $tenant_id])
);
return $this->response->created($emailSetting);
So the solution I found to trigger 404 is the following :
- Remove the tenantId from EmailSettings Validation
- Add a provider to add a custom error when the exception 'ModelNotFoundException' occurs like here
No query results for model in Laravel with Dingo - how to make a RESTful response on failure? Try to throw this Exception with the findOrFail method if invalid ID :
public function store(EmailSettingValidation $request, $tenant_id)
Tenant::findOrFail($tenant_id);
$emailSetting = $this->emailSettingService->create(
array_merge($request->all(), ['tenantId' => $tenant_id])
);
return $this->response->created($emailSetting);
answered Nov 9 at 16:51
guillaumehanotel
14
14
add a comment |
add a comment |
up vote
0
down vote
Travis Britz and Guillaumehanotel each have half of your answer, but you're still missing a detail.
From Travis Britz- Yes, include the tenant_id on the URI so it gets injected into the controller.
From Guillaumehanotel- Also used the Eloquent findOrFail in that Id in your Controller (or whatever class the Controller is leveraging to do this, like a Repository or Service class).
The last piece you're missing though is handling the error. You can do this in the Controller if you like, but I generally like making it a rule for my entire system that the IlluminateDatabaseEloquentModelNotFoundException
Exceptions that come out of findOrFail()
should always result in a 404.
Go to app/Exceptions/Handler.php
. I'm pretty sure Laravel auto-generates a meat and potatoes version of this file for you, but if you don't already have one, it should look something like this:
<?php
namespace AppExceptions;
use IlluminateFoundationExceptionsHandler as ExceptionHandler;
/**
* Class Handler
* @package AppExceptions
*/
class Handler extends ExceptionHandler
/**
* Render an exception into an HTTP response.
*
* For our API, we need to override the call
* to the parent.
*
* @param IlluminateHttpRequest $request
* @param Exception $e
* @return IlluminateHttpResponse
*/
public function render($request, Exception $error)
$exception = [
'title' => 'Internal Error',
'message' => $error->getMessage();
];
$statusCode = 500;
$headers = [
'Content-Type', 'application/json'
];
return response()->json($exception, $statusCode, $headers, JSON_PRETTY_PRINT);
Laravel basically has a system-wide try/catch
that sends all errors through here first. That's how errors get rendered into something the browser can actually interpret when you're in debug-mode, rather than just kill the process outright. This also gives you the opportunity to apply a few special rules.
So all you need to do is tell Handler::render()
to change the default error code that occurs when it sees the type of error that can only come from findOrFail()
. (This kind of thing is why it's always good to make your own 'named exceptions', even if they do absolutely nothing except inherit the base Exception
class.)
Just add this just before render()
returns anything:
if ($error instanceof IlluminateDatabaseEloquentModelNotFoundException)
$statusCode = 404;
This is already the default behavior of Laravel. The reason for the 500 status code is an external library they're using (dingo/api) that has its own exception handling.
– Travis Britz
Nov 10 at 4:45
add a comment |
up vote
0
down vote
Travis Britz and Guillaumehanotel each have half of your answer, but you're still missing a detail.
From Travis Britz- Yes, include the tenant_id on the URI so it gets injected into the controller.
From Guillaumehanotel- Also used the Eloquent findOrFail in that Id in your Controller (or whatever class the Controller is leveraging to do this, like a Repository or Service class).
The last piece you're missing though is handling the error. You can do this in the Controller if you like, but I generally like making it a rule for my entire system that the IlluminateDatabaseEloquentModelNotFoundException
Exceptions that come out of findOrFail()
should always result in a 404.
Go to app/Exceptions/Handler.php
. I'm pretty sure Laravel auto-generates a meat and potatoes version of this file for you, but if you don't already have one, it should look something like this:
<?php
namespace AppExceptions;
use IlluminateFoundationExceptionsHandler as ExceptionHandler;
/**
* Class Handler
* @package AppExceptions
*/
class Handler extends ExceptionHandler
/**
* Render an exception into an HTTP response.
*
* For our API, we need to override the call
* to the parent.
*
* @param IlluminateHttpRequest $request
* @param Exception $e
* @return IlluminateHttpResponse
*/
public function render($request, Exception $error)
$exception = [
'title' => 'Internal Error',
'message' => $error->getMessage();
];
$statusCode = 500;
$headers = [
'Content-Type', 'application/json'
];
return response()->json($exception, $statusCode, $headers, JSON_PRETTY_PRINT);
Laravel basically has a system-wide try/catch
that sends all errors through here first. That's how errors get rendered into something the browser can actually interpret when you're in debug-mode, rather than just kill the process outright. This also gives you the opportunity to apply a few special rules.
So all you need to do is tell Handler::render()
to change the default error code that occurs when it sees the type of error that can only come from findOrFail()
. (This kind of thing is why it's always good to make your own 'named exceptions', even if they do absolutely nothing except inherit the base Exception
class.)
Just add this just before render()
returns anything:
if ($error instanceof IlluminateDatabaseEloquentModelNotFoundException)
$statusCode = 404;
This is already the default behavior of Laravel. The reason for the 500 status code is an external library they're using (dingo/api) that has its own exception handling.
– Travis Britz
Nov 10 at 4:45
add a comment |
up vote
0
down vote
up vote
0
down vote
Travis Britz and Guillaumehanotel each have half of your answer, but you're still missing a detail.
From Travis Britz- Yes, include the tenant_id on the URI so it gets injected into the controller.
From Guillaumehanotel- Also used the Eloquent findOrFail in that Id in your Controller (or whatever class the Controller is leveraging to do this, like a Repository or Service class).
The last piece you're missing though is handling the error. You can do this in the Controller if you like, but I generally like making it a rule for my entire system that the IlluminateDatabaseEloquentModelNotFoundException
Exceptions that come out of findOrFail()
should always result in a 404.
Go to app/Exceptions/Handler.php
. I'm pretty sure Laravel auto-generates a meat and potatoes version of this file for you, but if you don't already have one, it should look something like this:
<?php
namespace AppExceptions;
use IlluminateFoundationExceptionsHandler as ExceptionHandler;
/**
* Class Handler
* @package AppExceptions
*/
class Handler extends ExceptionHandler
/**
* Render an exception into an HTTP response.
*
* For our API, we need to override the call
* to the parent.
*
* @param IlluminateHttpRequest $request
* @param Exception $e
* @return IlluminateHttpResponse
*/
public function render($request, Exception $error)
$exception = [
'title' => 'Internal Error',
'message' => $error->getMessage();
];
$statusCode = 500;
$headers = [
'Content-Type', 'application/json'
];
return response()->json($exception, $statusCode, $headers, JSON_PRETTY_PRINT);
Laravel basically has a system-wide try/catch
that sends all errors through here first. That's how errors get rendered into something the browser can actually interpret when you're in debug-mode, rather than just kill the process outright. This also gives you the opportunity to apply a few special rules.
So all you need to do is tell Handler::render()
to change the default error code that occurs when it sees the type of error that can only come from findOrFail()
. (This kind of thing is why it's always good to make your own 'named exceptions', even if they do absolutely nothing except inherit the base Exception
class.)
Just add this just before render()
returns anything:
if ($error instanceof IlluminateDatabaseEloquentModelNotFoundException)
$statusCode = 404;
Travis Britz and Guillaumehanotel each have half of your answer, but you're still missing a detail.
From Travis Britz- Yes, include the tenant_id on the URI so it gets injected into the controller.
From Guillaumehanotel- Also used the Eloquent findOrFail in that Id in your Controller (or whatever class the Controller is leveraging to do this, like a Repository or Service class).
The last piece you're missing though is handling the error. You can do this in the Controller if you like, but I generally like making it a rule for my entire system that the IlluminateDatabaseEloquentModelNotFoundException
Exceptions that come out of findOrFail()
should always result in a 404.
Go to app/Exceptions/Handler.php
. I'm pretty sure Laravel auto-generates a meat and potatoes version of this file for you, but if you don't already have one, it should look something like this:
<?php
namespace AppExceptions;
use IlluminateFoundationExceptionsHandler as ExceptionHandler;
/**
* Class Handler
* @package AppExceptions
*/
class Handler extends ExceptionHandler
/**
* Render an exception into an HTTP response.
*
* For our API, we need to override the call
* to the parent.
*
* @param IlluminateHttpRequest $request
* @param Exception $e
* @return IlluminateHttpResponse
*/
public function render($request, Exception $error)
$exception = [
'title' => 'Internal Error',
'message' => $error->getMessage();
];
$statusCode = 500;
$headers = [
'Content-Type', 'application/json'
];
return response()->json($exception, $statusCode, $headers, JSON_PRETTY_PRINT);
Laravel basically has a system-wide try/catch
that sends all errors through here first. That's how errors get rendered into something the browser can actually interpret when you're in debug-mode, rather than just kill the process outright. This also gives you the opportunity to apply a few special rules.
So all you need to do is tell Handler::render()
to change the default error code that occurs when it sees the type of error that can only come from findOrFail()
. (This kind of thing is why it's always good to make your own 'named exceptions', even if they do absolutely nothing except inherit the base Exception
class.)
Just add this just before render()
returns anything:
if ($error instanceof IlluminateDatabaseEloquentModelNotFoundException)
$statusCode = 404;
answered Nov 9 at 17:56
Claymore
885714
885714
This is already the default behavior of Laravel. The reason for the 500 status code is an external library they're using (dingo/api) that has its own exception handling.
– Travis Britz
Nov 10 at 4:45
add a comment |
This is already the default behavior of Laravel. The reason for the 500 status code is an external library they're using (dingo/api) that has its own exception handling.
– Travis Britz
Nov 10 at 4:45
This is already the default behavior of Laravel. The reason for the 500 status code is an external library they're using (dingo/api) that has its own exception handling.
– Travis Britz
Nov 10 at 4:45
This is already the default behavior of Laravel. The reason for the 500 status code is an external library they're using (dingo/api) that has its own exception handling.
– Travis Britz
Nov 10 at 4:45
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53226948%2flaravel-validation-request-api-route-post-parameter%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Do you have a model for your tenant table?
– Travis Britz
Nov 9 at 13:57
@TravisBritz Yes, but why is it important?
– guillaumehanotel
Nov 9 at 14:01