I would like to build a call API laravel project, separate the front-end and back-end, but how?
All the API are writing in the routes/api.php, but the job that return a view still live in routes/web.php ,
is that normal ? if not, what should I do ?
The code like ...
routes/web.php:
Route::get('/book/{id}',function(){ return view('book.show')->with('id',$id) ;});
show.blade.php:
...
$(function(){
$.ajax{
url: 'api/book/{{ $id }}',
....
}
});
...
routes/api.php:
//return the book data that id = {id}
Route::get('/book/{id}','BookController#show');
You are using it correctly.
One of the benefits of separating web and api routes is you have more granular control over applying middlewares.
Take a look at app/Kernel.php file:
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
As #angad-dubey mentioned its good practise to separate them out so that the web deals with the front end and the api routes for ... Api calls.
I tend to separate mine further by adding an admin.php within the routes folder, so that my backend routes are also separated, Thus you don't have one file with a long list of routes to search through, and this way as shown above you can append different middleware to them and not to the others, which could cause issues in the long term
Related
hello i am new at laravel and i build an eCommerce platform (details aren't important)
anyway my problem is i created a route that can catch all event from paypal webhook but when i directly access to it it's working but when i try from paypal webhook Simulator or even if did a sandbox payment didn't go through
i know the problem is from csrf verification and i tried excluding the route but didn't work and also tried creating a new RouteServiceProvider
here is my code in the Controller so i can catch anything from the request
$headers = getallheaders();
file_put_contents("/home/username/public_html/test.txt", json_encode($headers));
here is my route
Route::domain(env("APP_DOMAIN"))->group(function () {
Route::get('/paypal/n', 'HomeController#notifications');
});
i used domain(env("APP_DOMAIN")) because everyone can add his own domain and i want this to work just in the main domain .
the code in the RouteServiceProvider
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
$this->mapPaymentRoutes();
//
}
protected function mapPaymentRoutes()
{
Route::middleware('payment')
->namespace($this->namespace)
->group(base_path('routes/payment.php'));
}
and of course i did define the payment middleware in the file Kernel.php and comment the VerifyCsrfToken class
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'payment' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
// \App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
and even with all this and like a lot of test i couldn't get it to work
if i send a request to a pure php file it's working fine.
can you please help me with this i tried to find a solution in my own but it takes me like 15 days without any luck
i use laravel 6 .
in case someone else is struggling with this problem i had to do a work a round by creating a pure php file in public and send webhook request to that file url/file.php and the file catch data and send it to a command i created inside laravel to process it, so that everything that has anything to do with database is inside laravel and the file.php is just like a pipe .
i know it's not the best idea but it's not the worst either
and thanks for everyone who tried to help me .
I have a simple application and I want to be able to change language.
In my main controller I have:
session(['applocale' => 'en']);
$request->session()->put('applocale','en');
I know that these two lines are the same but I want to be sure that they both does not work.
Then I have API method:
public function switchLang(Request $request, $lang)
{
error_log("Current language is: " . session('applocale'));
error_log("Current language is: " . $request->session()->get('applocale'));
}
And here error_log shows nothing.
I'm following this thread: Laravel 5.3 - How to add Sessions to API without CSRF?
And in Debugbar I can see that my API function has hit middleware 'sessions' but session variables are not there.
That's how it's look like my 'seasons' middleware:
'sessions' => [
\Illuminate\Session\Middleware\StartSession::class,
]
It actually hits both 'api' and 'sessions' middleware.
Any ideas what I'm doing wrong?
This works for me (Laravel-5.7 ).
Firstly change the api middleware group to -
'api' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
'throttle:60,1',
'bindings',
],
in App\http\kernel.php .
Reference here.
everybody.
I made a middleware. I made a global one putting it into Kernel.php, which is called to every request and which verify if user is loged in.
The point was I needed to use the session for that. But the session was empty. Probably because it is populated later in script.
So I fix it using a global middleware called '\Illuminate\Session\Middleware\StartSession::class'. It was great because after that I could see, in my middleware, what session contains.
But another bug showed up. Since I puted the '\Illuminate\Session\Middleware\StartSession::class' middleware, my redirects doesn't put on session the variable anymore.
Till now code below worked perfectly and redirect created the arsh variable on session:
return redirect('/admin')->with('arsh', $arsh);
But now doesn't put anymore the arsh variable on session on redirect.
I researched a lot on internet, but nothing. I saw a lot of advices but no one worked.
I just don't know what I can do. If you know something would be awesome.
You also can think about using another solving method for reading session in my middleware, and probably this won't need anymore thinking about last bug.
I hope you understood what I wrote and sorry for my english.
Edit:
I did what Hamoud said:
I moved my middleware (\App\Http\Middleware\RedirectIfNotAuthenticated::class,) from $middleware to $middlewareGroups:
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrimStrings::class,
];
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\RedirectIfNotAuthenticated::class, // my middleware
],
'api' => [
'throttle:60,1',
'bindings',
],
];
And now redirect works well and can sets variables on session. But my middleware doesn't work anymore:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use Session;
use Request;
class RedirectIfNotAuthenticated
{
/**
* handle
*/
public function handle($request, Closure $next, $guard = null)
{
if ($request->is('admin/*') && !$request->is('admin') && !$request->is('admin/login') && (!Session::has(_DB_PREFIX_.'id_admin') || !Session::has(_DB_PREFIX_.'name_admin'))) {
return redirect('/admin');
}
return $next($request);
}
}
If statement is never true...
That because $middleware is called before verifying the route, while $middlewareGroups is called after. So I am redirect to 404 when my url is something like domain.com/admin/fgtsdr.
What my middleware does is if route is admin/* and I am not loged in, it redirects me to /admin. The point is it has to do that even if route exists or not...
You did not post your Kernel.php file, and it's not clear what do mean by global middleware. Do you add it the $middleware array or $middlewareGroups array?
The order of these middleware matters. In the Kernel.php file there are three arrays in which you can register your middleware.
$middleware. To be triggered with every request.
$middlewareGroups. You register group of middleware to assign to specific route. It has two main groups: web and api. The web group is assigned to all routes registered in the routes/web.php file.
$routeMiddleware. Individual middleware to assign to specific route.
I assume you started by putting your custom middleware in the $middleware to make it global, and when this did not work you added Laravel's StartSession middleware to the same array. However, StartSession is already registered in the $middlewareGroups array within the web group. So, you have two sessions one of them is destroying the other.
The correct way to add a middleware to all routes, when they need a session (web routes), is to add it in the web group if the $middlewareGroups after the StartSession middleware.
For example,
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class, <---- Laravel session middleware
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\CustomMiddleware::class, <--- Your global middleware.
],
I have a route group in my routes.php file with the middleware specified like so:
Route::group(['prefix' => 'api', 'middleware' => 'api'], function() {
Route::post('oauth/access_token', function() {
return Response::json(Authorizer::issueAccessToken());
});
}
I am using the Lucadegasperi Oauth2 Server addon. For its setup, I had to enter the following LucaDegasperi item in the $middleware array of the Kernel.php file (Kernel class):
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\LucaDegasperi\OAuth2Server\Middleware\OAuthExceptionHandlerMiddleware::class,
];
The $middlewareGroups array of the same class is as follows:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
What the OAuthExceptionHandlerMiddleware does is that it formats exceptions to JSON responses. Now when I apply the 'middleware' => 'api' in the route group as shown, the global middlewares dont work. I can say this because the HTML error page shows when exceptions occur. However, when I omit the 'middleware' => 'api' in the route group, the global middlewares work and I get JSON responses for the errors.
How do I get past this?
The reason for this is due to changes with how Laravel handles exceptions in Middleware from 5.2.7 onwards, as documented in this ticket I raised. To fix this you need to alter your Exception handler (as explained in the issue) or await the latest patch from the package.
I've commmitted a fix to the repository which fixes the issue of the changes made to Laravel 5.2, however this has not yet been merged.
Did you remember to add Authorizer to aliases array?
'Authorizer' => LucaDegasperi\OAuth2Server\Facades\Authorizer::class,
Because you're using it in:
Route::post('oauth/access_token', function() {
return Response::json(Authorizer::issueAccessToken());
});
I've a payment system, where data is submitted to 3rd party site and than hauled back...
When data returns it hits specific url lets say /ok route. $_REQUEST['transaction'].
But because of laravel middleware I'm getting token mismatch. There is no way 3rd party payment API can generate token, so how I disable it? only for this route?
or is there a better option?
Route::get('/payment/ok', 'TransactionsController#Ok');
Route::get('/payment/fail', 'TransactionsController#Fail');
public function Ok( Request $request )
{
$transId = $request->get('trans_id');
if ( isset( $transId ) )
{
return $transId;
}
}
Since version 5.1 Laravel's VerifyCsrfToken middleware allows to specify routes, that are excluded from CSRF validation. In order to achieve that, you need to add the routes to $except array in your App\Http\Middleware\VerifyCsrfToken.php class:
<?php namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
protected $except = [
'payment/*',
];
}
See the docs for more information.
Since Laravel 7.7 you can use method withoutMiddleware eg:
Route::get('/payment/ok', 'TransactionsController#Ok')
->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);
Route::get('/payment/fail', 'TransactionsController#Fail')
->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);
The technique described by #jedrzej.kurylo works well for excluding one or two pages.
Here's a different technique if you need to exclude lots of pages from CSRF validation, with more future-proofing.
You can segment your routes, and apply different middleware to each. So you can put your payment routes into a separate route groups, and not apply VerifyCsrfToken to them. Here's how.
1. Create a routes file
You'll notice in your routes directory, you have the following tree:
routes/
routes/api.php
routes/web.php
Create a new file here, routes/payment.php, and add your routes above to it:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/payment/ok', 'TransactionsController#Ok');
Route::get('/payment/fail', 'TransactionsController#Fail');
2. Process the route with the RouteServiceProvider
In Laravel, Routes are processed by app\Providers\RouteServiceProvider.php. You'll notice these functions: map() and mapWebRoutes(). Add to this file accordingly (I've excluded the stock comments for brevity).
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
$this->mapPaymentRoutes(); // <---- add this line
}
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
protected function mapPaymentRoutes() // <--- Add this method
{
Route::middleware('payment') // <--- this line is important
->namespace($this->namespace)
->group(base_path('routes/payment.php'));
}
Notice we've added a new middleware layer. This is important for the next step.
3. Add a new middleware layer
Your middleware for your route groups are defined in App\Http\Kernel.php.
Update the $middlewareGroups property, and add a middle entry for 'payment'. It can be exactly the same as web, but without the VerifyCsrfToken line.
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\NoClickjack::class,
\App\Http\Middleware\SecureReferrerPolicy::class,
\App\Http\Middleware\NoXssScripting::class,
],
// ********** Add this *******************
'payment' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
// This is the line you want to comment-out / remove
// \App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\NoClickjack::class,
\App\Http\Middleware\SecureReferrerPolicy::class,
\App\Http\Middleware\NoXssScripting::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
🎉
Now whenever you add new routes that need to be excluded from the CSRF Token check, add them to the routes/payment.php file.