Is it possible to create an custom response in laravel on methodNotAllowed - php

I've been searching a solution in Google but couldn't find anything similar tho this.
I'm basically trying to create a custom response upon the error methodNotAllowed in the framework Laravel 8.x
So I have this route:
Route::get('/test', function(Request $request){
return response([
'status' => 200,
'data' => 'Test'
]);
});
On requesting GET:/api/test I'm getting the expected response:
{
"status": 200,
"data": "Test"
}
But when requesting POST:/api/test or any other method it obviously throws an error 405 Method Not Allowed because I haven't setup any router for this.
Is there a "cleen way" to change the error response from 405 Method Not Allowed to
{
"status": 405,
"data": "Method Not Allowed"
}
By a "cleen way" I mean not creating aditional 100 routes just for catching the right method.

The Solution was adding the custom Response to App\Exceptions\Handler by doing this:
Add this to the top:
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
And add the custom response to the method register:
public function register()
{
$this->renderable(function (MethodNotAllowedHttpException $e, $request) {
return response()->json([
'status' => 405,
'message' => 'Method Not Allowed'
], 405);
});
}
Source: https://laravel.com/docs/8.x/errors

Related

Laravel API not returning validation messages properly

I am using Laravel as an API base, but I am struggling to show meaningful validator messages in my JSON response. I am using Laravel 8.
This is the response when my validator fails:
{
"message": "The given data was invalid.",
"errors": {
"image": [
"validation.mimes"
]
}
}
But instead of the validation.mimes i want an actual meaningful message, like The :attribute must be a file of type: :values..
I've tried overriding the exception in Exceptions\Handler.php but I still can't seem to access actual error messages?
protected function invalidJson($request, ValidationException $exception) {
return response()->json([
'success' => false,
'message' => $exception->getMessage(),
'errors' => $exception->errors()
], $exception->status);
}
Any help is appreciated.
Thanks

Laravel Custom Wrapper for API Responses

I am trying to structure my project in Laravel just created to use it as a back-end API. I want all my responses from Laravel to be returned in the JSON:API format defined on the official site: https://jsonapi.org/format/
For example:
I have created the following 2 resource files:
1- php artisan make:resource User
2- php artisan make:resource UserCollection --collection
Two simple resource files, one to return a resource and one to return a collection.
Now, I would like to return in all my responses the following format:
In case of success
1- The status return code can be 200, 201 or 202.
2- The returned response should be similar to the following:
{
"data": [
{
"id": 1,
"email": "collins.elody#example.org"
}
],
"message": null,
"success": true
}
You may be wondering what is the point of passing the message key, in this case it is null because it would be returning a collection of records, that is, reading, but in case you needed to add a new record, update or delete one, you would need to pass a message to my front-end, in this case I would use that key for that.
Example, adding record, response status code 201:
{
"data": [],
"message": "Record created succesfully",
"success": true
}
In case of failure
As said here: https://jsonapi.org/format/#document-top-level : The members data and errors MUST NOT coexist in the same document.
So, in case of error, I need change data key by errors key, for example, suppose I am trying to authenticate myself, and the validation fails, in this case, it should turn out like this:
{
"errors": {
"email": "E-Mail is required",
"password": "Password is required"
},
"message": null,
"success": false
}
or I just want to return an error message, expected output should by:
{
"errors": [],
"message": "Something is Wrong!",
"success": false
}
So in essence what I need is a global wrapper for all the responses I make from Laravel. I would like to call return in an elegant way as follows:
return $this->success($collection);
or
return $this->success('Done!', 201);
So the first thing that came to mind was creating a trait and defining the methods you need to then call them from anywhere in Laravel
My Trait
<?php
namespace App\Traits;
trait APIResponse
{
public function success($data, $status = 200) {
return [
'data' => $data,
'success' => in_array($status, [200, 201, 202]) ? true : false,
'message' => null
];
}
public function failure($data, $status = 500) {
// TODO
}
}
My Controller
class ExampleController extends Controller
{
public function index() {
$collection = new UserCollection(User::all());
return $this->success($collection);
}
}
But I am not sure it is the right way to do it, please, someone skilled in the field who can help me. Thank you very much in advance.
You are on the right path, there is two main solutions i would consider best approaches, to handling your exact problem. Fractal and Eloquent Resources, i prefer Fractal due to some design decisions and experience.
I will show an example in fractal, using the wrapper by Spatie. Firstly create an serializer that will wrap the data as expected.
class YourCustomSerializer extends SerializerAbstract
{
public function collection($resourceKey, array $data)
{
return [
$resourceKey ?: 'data' => $data,
'message': null,
'success': true,
];
}
public function item($resourceKey, array $data)
{
return [
$resourceKey ?: 'data' => $data,
'message': null,
'success': true,
];
}
This should be added to your fractal.php config, there is published through the spatie wrapper.
Transforming your data you need a transformer.
class UserTransformer extends TransformerAbstract
{
public function transform(User $user)
{
return [
'name' => $user->name,
'email' => $user->email,
];
}
}
Now you can transform your data into the expected format.
public function response($data, int $statusCode = Response::HTTP_OK)
{
return fractal($data, $this->transformer)->respond($statusCode);
}
For error codes, you should go to the Handler.php and add something similar to this. This is very naive way of doing it, but for know should get you going on error handling, you need to do something with validation exception, status code etc.
if ($request->wantsJson()) {
return response()->json([
'success' => false,
'message' => $exception->getMessage(),
], Response::HTTP_BAD_REQUEST);
}

Laravel API receive JSON 404 not found

I'm developing a Laravel 5.6 API and I'm using Resources and Collections, Route Model Binding.
To show an item, I currently use following code in my controller:
public function show(Todo $todo)
{
TodoResource::withoutWrapping();
return new TodoResource($todo);
}
In the Exceptions > Handler.php I have the following:
public function render($request, Exception $exception)
{
// This will replace our 404 response with
// a JSON response.
if ($exception instanceof ModelNotFoundException) {
return response()->json([
'error' => 'Resource not found'
], 404);
}
return parent::render($request, $exception);
}
This works perfectly when the item is found in the database. If the item is not in the database I get a (when using a browser):
"Sorry, the page you are looking for could not be found"
When using POSTMAN rest client, I'm getting
{
"message": "No query results for model [App\\Todo].",
"exception": "Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException",
....
....
I would like to simply retrieve a 404 error with text "Resource not found", using both a browser or POSTMAN.
* Update with Routing info *
In my api.php, I have the following:
Route::apiResource('todos', 'TodoController');
Route::fallback(function () {
return response()->json(['message' => 'Not Found!'], 404);
});
In web.php, I have:
Route::Resource('todos', 'TodoController');
What is the best way to achieve this?
Make sure to alias the exception class you are checking for.
use Illuminate\Database\Eloquent\ModelNotFoundException;
Without this you are checking for an instance of App\Exceptions\ModelNotFoundException.

laravel Guzzle post array of data

Good Day Can someone help me in posting array of data using guzzle, i've followed the documentation guzzle documentation and i dont know what am missing.
Routes: sync.php
$api->version('v1', [
'prefix' => 'api/v1',
],
$api->group([
'prefix' => 'sync'
], function ($api) {
$api->post('/accounts', 'App\Http\Controllers\SyncController#sync_accounts');
$api->get('/updateaccount', 'App\Http\Controllers\SyncController#updateaccounts');
});
]);
Controller: SyncController
use GuzzleHttp\Client;
use Illuminate\Http\Request;
public function updateaccounts()
{
$data = array('listid' => 'ListID',
'Name'=> 'Name',
'parentname'=> 'ParentRefFullName',
'fullname'=> 'FullName');
$http_call = new Client(['base_uri' => URL_CLOUD]);
$res = $http_call->post('sync/accounts/', [json_encode($data)]);
dd($res);
}
public function sync_accounts(Request $patch, $id)
{
$data = $patch->getContent();
return $data;
}
my problem here is
"error": {
"message": "Client error: POST http://.../api/v1/sync/accounts/ resulted in a 405 Method Not Allowed response:\n{\"error\":{\"message\":\"405 Method Not Allowed\",\"status_code\":405}}\n",
"code": 405,
"status_code": 500
}
Http 405 means that you are firing the wrong request to that endpoint get -> post or posting to get.
Your url seems to have a v1 which is not defined as prefix so if u try this url instead:
baseURL/sync/accounts

Customize Laravel API validation responses

I'm building a REST API with Laravel and wondering if there is a way to customize the API responses when validating.
For example, I have a validation rule in a Laravel request, saying a specific field is required.
public function rules() {
return [
'title'=>'required|min:4|max:100',
];
}
So, for this validation I get the error message in Postman like this
{
"title": [
"Please enter Ad Title"
]
}
What I want is to customize that response like this..
{
"success": false,
"message": "Validation Error"
"title": [
"Please enter Ad Title"
]
}
So, that the error is more specific and clear.
So, how to achieve this ?
Thanks!
I got a solution for your REST-API Validation Laravel FormRequest Validation Response are change by just write a few lines of code.
enter code here
Please add this two-line into your App\Http\Requests\PostRequest.php
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
after that add this function in your file.
you can change $response variable into your specific manner.
protected function failedValidation(Validator $validator) {
$response = [
'status' => false,
'message' => $validator->errors()->first(),
'data' => $validator->errors()
];
throw new HttpResponseException(response()->json($response, 200));
}
Provide a custom function to the FormRequest class called messages and return an array of validation messages mapped using dot notation for specific messages on specific rules:
public function messages()
{
return [
'title.required' => 'Please enter an Ad title',
'title.min' => 'Your title must be at least 4 character'
]
}
Returning a success message is futile as if it fails a 422 error code will be thrown when performing an ajax request anyway.
As for the message property, you will receive that as part of the payload, wherein the actual validation errors will be contained in the object.
You can customize errors, check the documentation. also you can validate in this way
$validator = Validator::make($request->all(), [
'title'=>'required|min:4|max:100'
]);
if ($validator->fails()) {
// get first error message
$error = $validator->errors()->first();
// get all errors
$errors = $validator->errors()->all();
}
then add them to your response, for example
return response()->json([
"success" => false,
"message" => "Validation Error"
"title" => $error // or $errors
]);

Categories