Stato74's avatar

Laravel Routes, which is better ?

I have a project with users and orders.

https://myendpoint/customer/{customer_id}/order/{order_id}

After walking through my design a few developers suggested changing my route as below

https://myendpoint/order/{order_id}

and include the customer_id in the JSON.

I've been developing for a number of years and have always used the first method but I'd like to hear further options from those in laravel community.

0 likes
12 replies
LaryAI's avatar
Level 58

Both approaches have their own advantages and it ultimately depends on your specific use case and requirements.

The first approach, using the route /user/{user_id}/order/{order_id}, provides a more hierarchical and descriptive URL structure. This can be beneficial for readability and understanding the relationship between users and orders. It also allows for easy expansion if you need to add more nested resources in the future. However, it may result in longer URLs and can be more complex to handle in your code.

The second approach, using the route /order/{order_id} and including the user_id in the JSON, simplifies the URL structure and makes it more concise. This can be advantageous if you have a large number of users and want to avoid long URLs. It also reduces the complexity of handling nested resources in your code. However, it may sacrifice some readability and understanding of the relationship between users and orders.

Ultimately, you should consider factors such as the size and complexity of your project, the expected number of users and orders, and the preferences of your development team. It may be helpful to discuss with your team and consider the trade-offs before making a decision.

Here's an example of how you can implement the first approach in Laravel:

Route::get('/user/{user_id}/order/{order_id}', function ($user_id, $order_id) {
    // Retrieve the user and order based on the IDs
    $user = User::find($user_id);
    $order = Order::find($order_id);

    // Do something with the user and order

    return view('order', compact('user', 'order'));
});

And here's an example of how you can implement the second approach:

Route::get('/order/{order_id}', function ($order_id) {
    // Retrieve the order based on the ID
    $order = Order::find($order_id);

    // Retrieve the user based on the user_id in the JSON
    $user = User::find($order->user_id);

    // Do something with the user and order

    return view('order', compact('user', 'order'));
});

Remember to adjust the code according to your specific application logic and database structure.

1 like
Stato74's avatar

@tisuchi Cheers for the link. I actually remember watching that a few years back.

3 likes
automica's avatar

are you building an api or creating a web front end?

if its the former, you should look at defining your endpoints based on CRUD actions.

  • GET /order - lists all orders
  • POST /order - create an order
  • GET /order/{order_id} - gets an existing order
  • PATCH /order/{order_id} - updates an order with {order_id}
  • DELETE /order/{order_id} - deletes an order

as these should be authenticated endpoints, you shouldn't need to pass in a {user_id} as that is inferred as they will be authenticated user.

for the latter, I still might use CRUD actions, at least for a single user who has logged in. If you are admin and you want to display orders for a specific user you might do:

  • GET /user/{user_id}/order - lists all orders

The problem with

  • /user/{user_id}/order/{order_id}
   $user = User::find($user_id);
   $order = Order::find($order_id);

is that you could potentially expose an order that belongs to a different user:

  • /user/USER1/order/ORDER1

and

  • /user/USER1/order/ORDER1

will return 2 different users but the same order.

what you should do is

   $user = User::find($user_id);
   $order = $user->orders->find($order_id);

so filter the orders belonging to that user for the $order_id

2 likes
Stato74's avatar

@automica Thanks for the reply. Its an API and user_id could be swapped with customer_id as this is who they are.

automica's avatar

@Stato74 so customer is authenticated? you shouldn't need or care about customer_id as that will come from your auth()->customer_id

Stato74's avatar

@automica it's an api to api that's authenticated and the customer and order data are passed, the information is recorded and then used by other processes. This isn't that important to my question, as my question was about the design of my routes and endpoints.

automica's avatar

@Stato74 if its api to api then you shouldn't need to worry about passing user/ customer details as you can get it from the order relationship.

what other info are you after?

1 like
Snapey's avatar

if you pass user and order id's in the URL, what are you going to use the user id for?

The order that is already created (by virtue of having an order id) already belongs to a user so specifying the user is at best redundant, at worse, potentially confusing when someone tries to access an order with the wrong user id (maliciously)

Also, if you pass user with the order, then you always need to pass the user, eg when an operator needs to access the order or some other scenario where the user is not the one initiating the request. So, you end up finding the user details just so you can pass the correct user with the request

1 like
Stato74's avatar

Apologies for any confusion I was asking for other developer's thoughts on which of these two routes should be used, but this had lead to a deeper conversation in parts around where / why they are being used.

Route A: https://myendpoint/customer/{customer_id}/order/{order_id}

Route B: https://myendpoint/order/{order_id}

Route A is the way I have always developed my code but as mentioned above Route B simplifies the URL structure and your further comments have given me food for thought and I thank you for that.

Please or to participate in this conversation.