Laravel API to returns json response - php

I'm developing and College project, It should be a platform that serve and Web and Mobile Front-En. I decided to use Laravel 5.1, my idea was to use laravel as an excelent hardcore php backend to serve this platform, I wanted to develope APIsRest with laravel and comsume the services on both web and mobile front-end. My point is: I don't wanna use blade templating engine, because returning "views, instance objects, etc" my mobile front won't understand responses, that's why I want to orientated my APIs to return JSONs messanges, so I can handle them on each front.
1) First at all I wanna ask you guys if is it a good idea?
2) how can I retrieve the error php messages send by laravel to send them back to views (mobile-web front) as JSONs?
Example: Right now I'm trying to finish the "Login-Register" module of my project. I'm trying to use the advantages of Authentication Laravel Module, and now I am stack on postLogin, because i don't know how to handle the error and send it back to front as JSON.
public function postIngresar(Request $request)
{
$throttles = $this->isUsingThrottlesLoginsTrait();
if ($throttles && $this->hasTooManyLoginAttempts($request)) {
return response()->json(*$this->sendLockoutResponse($request));
}
$credentials = $this->getCredentials($request);
if (Auth::attempt($credentials, $request->has('remember'))) {
return response()->json([
'success' => 'true',
'message' => 'Logeo logrado exitosamente'
]);
}
if ($throttles) {
$this->incrementLoginAttempts($request);
}
return response()->json($this->getFailedLoginMessage());
}
is there any way to handle all error and exception as JSON messages? It'll will help me A LOT.
thank you so much by reading.

You can read about Exception Handling section of the Laravel docs, but to save you the time, here is the name of the method that will be responsible for returning json representation of your errors:
All exceptions are handled by the App\Exceptions\Handler class. This class contains two methods: report and render. The render method is responsible for converting a given exception into an HTTP response that should be sent back to the browser. By default, the exception is passed to the base class which generates a response for you. However, you are free to check the exception type or return your own custom response

The LoginController uses the AuthenticatesUsers trait which has a method sendFailedLoginResponse which is responsible for the error message redirect upon authentication failure as follows:
protected function sendFailedLoginResponse(Request $request)
{
if ( ! User::where('email', $request->email)->first() ) {
return response()->json([
$this->username() => Lang::get('auth.email')
]);
}
if ( ! User::where('email', $request->email)->where('password', bcrypt($request->password))->first() ) {
return response()->json([
'password' => Lang::get('auth.email')
]);
}
}

Related

Sending session data to React frontend using Larvel backend

I have a somewhat simple authentication system using ReactTS as a frontend and Laravel as a backend. What I am looking to do is send errors from the backend to the frontend when I redirect a user. This is the code I currently have:
return redirect('/account')->withErrors('Error here');
I have also tried:
return redirect('/account')->with('message', 'Error here');
But in my React frontend I use a flash manager to handle errors. However I do not know how to get this error or session data in the frontend. Code:
addFlash({ key: 'account', message: 'error here' });
This function just takes a message and shows it to the user with a coloured bar. My issue is I do not know how to get these errors I am redirecting with in the frontend.
As I understand your question you have separated backend and frontend and probably have an API that handles your requests. If this is the case and I understood it correctly then I'll tell you how I handled it and maybe it will help you as well.
In my case, I'm returning an HTTP response no matter if it is for errors or for success and I think that you should do the same, let me show you a simple example to explain it better for you.
Here's my controller (simplified for your concern):
class CreateEventRegistrationController
{
public function __invoke(Request $request)
{
/**
Here you validate your fields or something
specific logic for your project.
*/
$validator = Validator::make($request->all(), [
'firstName' => 'required',
'lastName' => 'required'
]);
/**
If your validation fails then throw an HttpResponseException
*/
if ($validator->fails()) {
throw new HttpResponseException(response()->json([
'errors' => $validator->errors()
]));
}
/**
Store something in database or whatever you need to do in your app
*/
/**
And at last return a successful response
after everything is working as expected.
*/
return response('Created successfully', Response::HTTP_CREATED);
}
And with this logic then I have the messages on my frontend part where I handle there the error messages or success ones.
Hope this helps you, if I couldn't understand your issue properly you can comment it more specifically so I can help you more.

Standardizing API error responses in Laravel (API Resources)

Working on a new repo. After doing some research, I've decided to use API Resources to standardize my API responses, according to jsonapi.org best practices.
I am not able to get a good answer on the best way to return consistent user-readable error messages (not exceptions). These are messages that can potentially be returned directly from the controller. Using Laravel's API Resources, I've been able to create something like this, but it feels hacky.
$error = (object) (['errorCode' => 422, "messageDetail" => ["First name must contain at least three characters."]]);
return new ErrorResource($error);
ErrorResource is used to format the JSON in this case. The thinking is that whenever a developer wants to code up an error message, that they would use ErrorResource.
Is there is a better way?
inside App/Exceptions/Handler.php you can change render function as per your requirement and return the Resource from this function. Here is an example
public function render($request, Exception $exception)
{
if ($request->is('api/*') || $request->expectsJson() || $request->is('webhook/*')) {
$error = (object) (['errorCode' => 422, "messageDetail" => ["First name must contain at least three characters."]]);
return new ErrorResource($error);
}
return parent::render($request, $exception);
}
For me better do error formatting in app/Exceptions/Handler.php:render.
This is a more flexible approach and helps to do it in one place.

Notification endpoint validation not working with Laravel Endpoint

I am using the Microsoft Graph and I need to set up a webhook to receive changes to email and calendar events. I was able to get it working with my PHP Laravel application, but now that I am trying to subscribe to notifications, I am running into issues with validating the notificationUrl, which is pointing to a public server of mine.
The script for creating the webhook is returning the following error:
Client error: POST https://graph.microsoft.com/v1.0/subscriptions resulted in a 400 Bad Request response:
{
"error": {
"code": "InvalidRequest",
"message": "Subscription validation request failed. Response must ex (truncated...)
The truncated part I believe is
Subscription validation request failed. Must respond with 200 OK to this request.
Here is my code for creating the subscription:
$data = [
"changeType" => "created",
"notificationUrl" => "https://anatbanielmethod.successengine.net/office365/webhooks/events",
"resource" => "me/events",
"expirationDateTime" => "2018-12-20T18:23:45.9356913Z",
"clientState" => "secret",
];
$result = $graph->createRequest('POST', '/subscriptions')
->attachBody($data)
->execute();
and here is my method for my notificationUrl:
public function events()
{
//if validationToken exists return that to validate notificationUrl
if(isset($_REQUEST['validationToken'])){
return response($_REQUEST['validationToken'], 200)
->header('Content-Type', 'text/plain');
}
//process event normally for those that have already been validated
}
Once again this URL is public and live and I have tested it by using Postman to send it test posts and it is working fine. Also, I added this route to my VerifyCsrfToken middleware to allow a third party post to hit this URL.
Originally I set up a simple single page PHP script to test validating the notificationUrl and that simple script worked fine. It successfully validates Webhooks created that point to it. Here is that one page script code:
<?php
if(isset($_REQUEST['validationToken'])){
echo $_REQUEST['validationToken']; // needed only once when subscribing
} else {
//process like normal not a validation Token request...
}
}
So I would expect that the Laravel endpoint would work like the simple one page PHP script, and it is when I test both URLs in Postman, but the Laravel endpoint is not validating when Office365 attempts to validate it when creating a new webhook.
I have searched all over for help on this and read through all of the Microsoft developer documentation I can find on webhooks and these are some of the more helpful parts of the documentation but I am still not finding an answer to this issue:
https://learn.microsoft.com/en-us/graph/api/subscription-post-subscriptions?view=graph-rest-1.0
https://learn.microsoft.com/en-us/graph/webhooks#notification-endpoint-validation
Any ideas of this?
Thanks Marc! You were correct about the linefeed being the issue, I am still not sure where the line feed is coming from, some how Laravel appears to be adding it. Needless to say I found a solution by adding an "ob_clean();" right before returning the response. Below is my updated notificationUrl method:
public function events()
{
//if validationToken exists return that to validate notificationUrl
if(isset($_REQUEST['validationToken'])){
ob_clean();//this line is cleaning out that previously added linefeed
return response($_REQUEST['validationToken'], 200)
->header('Content-Type', 'text/plain');
}
//process event normally for those that have already been validated
}
It's odd that JakeD's answer requires the use of ob_clean(). here is my webhook controller method in my Laravel 5.7.x app:
use Illuminate\Http\Request;
public function webhook (Request $request) {
if (filled($request->input('validationToken'))) {
return response($request->input('validationToken'))
->header('Content-Type', 'text/plain');
}
// code to process the webhook after validation is complete
}
I don't see an extra linefeed character and the Microsoft Graph API subscription is validated and created.

How to return/terminate symfony2 response in function other than the requested action?

I'm building a RESTful API using Symfony2, FOSRestBundle and an OAuth 2 server library.
For any given request, there are a number of possible responses and status codes that I can return to the client.
Take for example the process of getting a user:
<?php
class UserController extends CustomBaseController {
/**
* Get a user
* #Get("/users", name="users_get")
*/
public function getAction(Request $request) {
// Ensure a valid access token is present
$this->validAccessTokenOrExit();
$user = $this->getUser();
return $this->handleView($this->view($user, 200));
}
}
Ideally I would like to have the validAccessTokenOrExit() function terminate the request and return the 401 status code with an appropriate message. This means I can handle authentication in this function and reuse it in several actions across the API.
However I can't seem to find a way of terminating the response from another function, and I always have to return a Response from the action called.
Are there any clean solutions to accomplish this or something similar?
If you throw an exception that has the interface Symfony\Component\HttpKernel\Exception\HttpExceptionInterface (Symfony\Component\HttpKernel\Exception\HttpException for example) with the status code set (first parameter as 401 for HttpException) it will be handled by the HttpKernel in the way that you are expecting.
For example..
throw new HttpException(401, 'Something went wrong');
.. will be turned into a response with 401 as the status code.
You can use $this->createAccessDeniedException('message') within a controller.
This will create AccessDeniedException, terminate the current request and return a 403 with your message.
I did faced this situation and for time being I call the terminating function with return. Return false from function when valid.
if($r=$this->validAccessTokenOrExit()){
return $r;
}
Alternatively I use following two methods for redirecting or rendering a view form another function and terminating flow.
Redirection:
header('location:'. $this->generateUrl('deals_product_view', array('id' => 1)));
exit;
Rendering a view:
$response = new Response();
$response->setContent($this->renderView($view_file, $params ));
$response->send();
exit;

How to catch laravel controller exceptions

I'm new to Laravel (we're using 5.0 at work). Right now, when we respond to an API request in a Controller, we are rewriting the same code over and over to respond to unauthorized actions. For example,
public function getUsers(){
if (Entrust::can('users.view')){
$users = Users::get();
return response()->done($users, 200);
} else {
return response()->unauthorized('users.view');
}
}
It gets more and more complicated if we have different permissions that can allow an API request to succeed.
I'd like to simply throw an exception of some sort if the user cannot perform the API request. For example,
public function getUsers(){
require('users.view'); // throws an UnauthorizedException if current user doesn't have 'users.view' permission
$users = User::get();
return response()->done($users, 200);
}
public function someOtherMethod(){
if (!Entrust::can('permission1') && !Entrust::can('permission2')){
throw new UnauthorizedException(['permission1', 'permission2']);
}
// some other stuff
}
But I don't know what code calls the API function, nor where to wrap that call in a try/catch. It's easy enough to code the UnauthorizedException, and easy to transform it into json, but where do I put the handler? As I said, I'm new to Laravel, and I don't know how it handles these exceptions.
Ideally, whatever solution I find, I'd like to extend it to other exceptions so we can have consistent json responses based on common exceptions.
Instead of repeating your code, take a look at implementing the authorization check with Middleware.

Categories