Should I Nest Routes to Resources in Laravel?

99封情书 提交于 2019-12-04 05:20:47

This is an interesting question - as you mentioned, it may be a little subjective, but worth the discussion.

You touch on a few points, so I will attempt to address them separately.

Nesting vs Not nesting

First thing to clear up in my opinion is browser routes versus API routes. If you are providing an API - either internally to your app or externally to the public, I would avoid nested routes for a few reasons:

  • resource/id format is quite standard and expressive for API's
  • this makes it easier to document
  • this makes it easier for the consumer app to dynamically construct API requests

However, your question does seem to focus on the browser routes. In my opinion browser routes can and should be whatever reads nicely - the url, especially these days, can be considered as part of the UI. For example, you may go to settings (and I would expect to see /settings), from the settings page, if I were to go into the notifications settings section, I would expect to see /settings/notifications.

The routes act and assist with UX - they are almost a breadcrumb and should look as such.

So, I would definitely nest for browser routes, and would definitely not for APIs.

Route integrity

The real heart of your question I think is about the route integrity. I think regardless if you choose to nest or not you need to be checking your permissions with the assumption that someone is tampering with the urls - the same way you assume that the user has tampered with the form input.

Essentially your routes (nested or not) act as input, and you will need to validate that. Route level middleware is one approach, but is often too generic to solve anything complex so you may find it easier to tackle it with controller middleware (https://laravel.com/docs/5.7/controllers#controller-middleware).

So you may do something like:

public function __construct()
{
    $this->middleware('auth');

    $this->middleware('canViewProject')->only('show');

    $this->middleware('canEditProject')->except('store');
}

Whether you use Gates, Policies or just plain old middleware will probably depend on the complexity of the project - but the above applies regardless - treat the urls as input and validate accordingly

This always has been a discussion between developers even the creators of Laravel have this argument, so what is the good practice?

Lately I've seen a tweet from Taylor Otwell saying that he has deprecated the nested routes section from Laravel docs because he didn't prefer it, while when you open Laracasts you see Jeffrey is implementing this concept like /series/php-testing/episodes/hello-world.

As I told it's a quiet argument and when it comes to choices like that I always do what it feels good for me. So if I were you I wouldn't nest neither teams or projects but maybe I would nest projects/documents, I don't go for nesting always.

This might be a bit of a deviation from the original question, but I feel that Adam Wathan's Laracon US 2017 talk might be a useful resource for this discussion. (https://www.youtube.com/watch?v=MF0jFKvS4SI)

I am relatively new to development and therefore explore a lot of code bases on github. I always struggle to understand nested routes. So as a best practice I would prefer no-nesting to nesting.

Keeping stuff "CRUDY by design" as Adam calls it, one thing you achieve, imo, is simplification of route names. If I were to work in a group, that is a pattern I would prefer.

However, referring to the penultimate paragraph on your question, I struggle to understand why an integrity check is not needed.

I've spent the last year looking at this and refining it, and stumbled upon an elegant solution recently. Nesting can be done nicely, I'm sticking to resource controllers and dot-syntax for nested route resources.

In order to enforce the route validation, I am using something like the following. There is a good answer here, which suggests explicitly binding the models in question.

So with

Route::resource('posts.comments', 'CommentsController');

You'd use

Route::bind('comment', function ($comment, $route) {
    return Comment::where('post_id', $route->parameter('post'))->findOrFail($comment);
});

This will automatically work everywhere. If required, you could test for the upstream parameter to be found, and only perform the test in those cases (e.g. to cater for routes where only a comment is specified).

I think you should makes use of Role concepts, Route grouping , Middleware concepts to build this app

For Role related things check https://github.com/spatie/laravel-permission , a good package

Eg:

Route::group(['middleware' => ['role:super-admin']], function () {
    //
});

You can almost do any role, permission related things using above package.

Assume roles like project manager, developer.

Group your Routes based on roles & assign proper Middleware as you need.

For URL : /teams/team-a/projects/project-b/documents/doc-c

Check the Authenticated user has a role in team-a & project-b (You can check this in Middleware, Controller or custom Service provider anywhere as your need).

Also just check https://laravelvoyager.com/

Thanks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!