@joe008 What about it? 🤷♂️
Laravel The Full Stack Framework + Laravel The API Backend
This was posted 2 years ago and I am facing the exact same issue as in this thread- Please google for "Laravel The Full Stack Framework + Laravel The API Backend Laracast" as forum is not allowing to add links.
Now Laravel ships with Sanctum out of box. I selected Livewire with Breeze for frontend. Now I want to also expose REST APIs for mobile app in same application. "Just use Sanctum" is not enough as I am running into issues like -
how to handle requests to same route - /login for eg - coming from Browser vs rest API (as one expects login page HTML in response and other JSON)
Is there any official support for this use case? I couldn't find this being discussed anywhere. Everywhere it's either API only Backend or monolithic not both.
@martinbean sorry, just updated the post.
how to handle requests to same route - /login for eg - coming from Browser vs rest API (as one expects login page HTML in response and other JSON)
@joe008 If you’re expecting a JSON response then you need to tell the server you’re expecting a JSON response by sending an Accept: application/json header with API requests. Otherwise Laravel’s going to assume you just want a “regular” response and give you HTML or redirect responses.
However, you should have different routes for logging in versus obtaining an API token for authorising a user in an app.
I see what you are saying but I will rephrase my question after a bit more of research - So Laravel is basically supposed to be used as either Fullstack app or API only app.
But I also need to build an mobile app that will communicate with my backend via rest APIs, I am left with no option but to use Laravel as API only, right? Because if I use Livewire/Inertia for UI, I would anyway be required to write REST endpoints again for each route (such as product/:id) for returning JSON response to the mobile app. This is duplication of efforts and also need to be extra careful to update both routes whenever make any change.
Does this make sense of am missing something here?
I see what you are saying but I will rephrase my question after a bit more of research - So Laravel is basically supposed to be used as either Fullstack app or API only app.
@joe008 Why? You can use Laravel to serve both a web app and an API. It’s not either/or. There’s a reason the Laravel skeleton comes with both a routes/web.php file and a routes/api.php file.
But I also need to build an mobile app that will communicate with my backend via rest APIs, I am left with no option but to use Laravel as API only, right? Because if I use Livewire/Inertia for UI, I would anyway be required to write REST endpoints again for each route (such as product/:id) for returning JSON response to the mobile app. This is duplication of efforts and also need to be extra careful to update both routes whenever make any change. Does this make sense of am missing something here?
Yes, you would have two sets of routes, because your web front-end is never going to mirror your API, and your API is never going to perfectly mirror your API.
Your API will typically be organised around “resources” and will have endpoints for retrieving a collection of objects, or manipulating a single object.
Now compare that to a “home page” where you‘ve got lots of data being presented, or other web pages where you have regions like sidebars and footers and headers. These pages won’t map to a single resource. You’re not going to have a “home page” resource in your API.
So, create your API controllers that uses its the auth:api middleware to authorise requests. You can use Sanctum or Passport for this. You can then build your web front-end using separate controllers, that uses the regular auth guard for session-based authentication. Your Laravel application will then happily serve both web and API requests.
@martinbean Thank you for detailed reply. You make a great point on routes/web.php file and a routes/api.php file. Didn't think it that way. And your explanation gives me confidence that going this route (pun intended) of having both web front and API is not non-standard.
My only concern, and a big one, is that no where in document or anywhere on internet talks remotely about this approach. I did found couple of old posts but responses were just use Sanctum. So this naturally gave me the impression that Laravel is not supposed to be use that way, and surely I cannot expect any code/template/documentation etc. which have this kind of "two sets of route" as you explained, amiright?
But anyways I having been playing around with code and armed with this info, I will go ahead with this approach.
@martinbean and the "proof" that Laravel don't actively support this approach is that when you do breeze install you have to choose between livewire/blade/inerta and API only stack. I had to manually create separate project just to generate frontend files (tailwind, vite config etc.) and copied them to my API only breeze project.
@joe008 You can utilize it for both backend and API functionality. However, distinct controllers must be developed for each: backend controllers for rendering views, and API controllers for returning JSON responses.
@shariff Is that really a common/good practise? As I mentioned there are many issues with this approach -
- Redundancy. Maintain 2 Routes and 2 Controllers for each endpoint.
- If something changes on a particular route/controller it should be changed in both controller otherwise there will be inconsistency
@joe008 In controllers, we will solely handle returning the response. The actual logic can be implemented in either repositories or actions. There are many approaches to achieving this; one option is to encapsulate the logic within a dedicated class.
@joe008 You can use the same controller for each route.
But you need to send to a route in the API routes file or route in the web routes file so that the correct middlewares are run for the two types.
The controller can make the decision about whether to return a json response or a view based on what the client said it was expecting.
- Depends on the view point, having separate controllers gives you the option to change your API without worry of braking your front end.
- Not really, you should extract your business logic into classes that don't care if they are being called from the API or your front end.
all controllers will have this "check" what is the request type. But I am in better position now to make the decision.
@joe008 Which is why you shouldn’t use the same controller to handle “web” and API requests. Otherwise they’re just going to full of horrible conditionals like this:
if ($request->wantsJson()) {
$posts = Post::query()->paginate(15);
return PostResponse::collection($posts);
} else {
return view('posts.index')->with([
'posts' => Post::query()->with('comments')->paginate(30),
'popularPosts' => Post::query()->popular()->take(10)->get(),
]);
}
And then you’re going to have web routes that don’t have an API companion, and vice versa.
@martinbean Indeed! In fact I found similar analogy with using 2 authentication types that Sanctum support - SessionIDs (web interface) and token (Mobile app etc) I am not sure if both can be (or actually are) used together, documentation was not very specific about it.
@joe008 Sanctum is for simple API tokens, and SPAs. You can use Sanctum in conjunction with standard session-based authentication. You’d just apply different middleware to your different route groups:
// File: routes/api.php
Route::middleware('auth:sanctum')->group(function () {
// Put API routes here...
// Routes will check for a valid API token...
});
// File: routes/web.php
Route::middleware('auth')->group(function () {
// Put web routes here...
// Routes will use regular session-based authentication...
});
@martinbean umm.. I think sanctum take cares of standard session-based authentication also and we can simply use auth:sanctum in web.php route as well. Quoting directly from doc (laravel.com/docs/10.x/sanctum#protecting-routes) -
You may be wondering why we suggest that you authenticate the routes within your application's routes/web.php file using the sanctum guard. Remember, Sanctum will first attempt to authenticate incoming requests using Laravel's typical session authentication cookie. If that cookie is not present then Sanctum will attempt to authenticate the request using a token in the request's Authorization header.
I think sanctum take cares of standard session-based authentication also and we can simply use auth:sanctum in web.php route as well. Quoting directly from doc (laravel.com/docs/10.x/sanctum#protecting-routes) -
@joe008 It doesn’t. It adds cookie-based authentication for SPAs (JavaScript applications).
If you have a “traditional” server-rendered web application, where web controllers are returning Blade views, then you just want to use the standard auth middleware to add session-based authentication for your web routes.
Like I’ve said a few times now, you can use both Sanctum/Passport and regular session-based authentication in the same application. I have done many times. So do other people. I even gave you an example here
@martinbean yeah that's clear now, thanks!
Please or to participate in this conversation.