May Sale! All accounts are 40% off this week.

El_Matella's avatar

Angular - Laravel API - How to organize URLs

Hello!

I would like to train me to make an e-commerce website using Laravel for Back-end and Angular JS for Front-end.

For the moment, my goal is to build a Laravel API communicating with an Angular JS front-end (I am not going to use Laravel views, I want the two technologies completely separate.)

But I don't know really how to organize URLs.

For example, I want my products URLs to follow this rule: my-ecommerce.com/category/product-slug .

But should my Laravel API follow the same rules as the front-end? In other words, should this front-end URL communication with api.mybackend.com/category/product-slug or api.mybackend.com/products/{id} ?

And if it is the second solution, how should I retrieve my product ID? This solution would imply a second Ajax request to retrieve the ID, am I wrong?

If someone knows about that or articles talking about the subject, I would love to see that :)

Have a good night, and thank you for your answers and advices!

0 likes
5 replies
martinbean's avatar

@El_Matella I’m not a fan of API-driven, single-page web applications as they’re always janky, but if you’re going to go down this route and not use any of Laravel’s views etc then use Lumen: it’s made to be blazing-fast for API-like applications.

El_Matella's avatar

Hi @martinbean , thank you for your answer and for the lumen tip, I am going to dive into that.

I am still wondering how could I organize my URLs tho, question still opened :)

mehany's avatar
mehany
Best Answer
Level 13

@El_Matella you can probably do a structure that is similar to the below. I am going to give you some file structure and some code as well so you can see the benefit of this structure. Inspired by this package

 // route.php
 
// add patterns to validate URL parameter. Ex. id
Route::pattern('id', '[0-9]+');
// Angular partials routes 
Route::get('/partials/index', function () {
    return view('partials.index');
});

Route::get('/partials/{category}/{action?}', function ($category, $action = 'index') {
    return view(join('.', ['partials', $category, $action]));
});
 
Route::get('/partials/{category}/{action}/{id}', function ($category, $action = 'index', $id) {
    return view(join('.', ['partials', $category, $action]));
});

// This will attempt to catch all urls 
Route::group(['middleware' => 'api'], function()
{
    Route::get('/{page}/{subpage?}', function ($page, $subpage) {
        return view(join('.', [$page, $subpage]));
    });
});

// 
//Catch all undefined routes. Always gotta stay at the bottom since order of routes matters.
Route::any('{undefinedRoute}', function ($undefinedRoute) {
  return view('layout');
})->where('undefinedRoute', '([A-z\d-\/_.]+)?');

Now you can put the partials folder inside the public folder, ignore the top Angular partials routes and keep all files in .html. Otherwise keep the partials folder inside the views folder and save all files as someTemplateName.blade.php or someTemplateName.php

// public
partials/angularViews

// or  views  - 
partials/angularViews
// everything else
.....

This api.mybackend.com/category/product-slug is fine to use. If in the future you want to use Blade views then you can simply check on the requested data type and return a view if it is not JSON.

// Example angular code to save the token provided by API middleware and intercept http requests made to the backend to bind that token to request headers

    angular.module('appRoutes', []).config(['$routeProvider', '$locationProvider', '$httpProvider',
    function ($routeProvider, $locationProvider, $httpProvider) {
        $routeProvider
            .when('/', {
                templateUrl: '/partials/index',
                controller: 'MainController'
            })
            .when('/:category/:action?/:id?', {
                templateUrl: function (params) {
                    var allowedParams = ['category', 'action', 'id'];
                    var paramVals = [];
                    for (var key in params) {
                        if (allowedParams.indexOf(key) !== -1) {
                            paramVals.push(params[key]);
                        }
                    }
                    return '/partials/' + paramVals.join('/');
                }
            })
            .otherwise({
                redirectTo: '/'
            });

        $locationProvider.html5Mode(true);

        $httpProvider.interceptors.push(['$rootScope', '$q', '$localStorage',
            function ($rootScope, $q, $localStorage) {
                return {
                    request: function (config) {
                        config.headers = config.headers || {};
                        if ($localStorage.token) {
                            config.headers.Authorization = 'Bearer ' + $localStorage.token;
                        }
                        return config;
                    },
                    response: function (res) {
                        if (res.status === 401) {
                            // Handle unauthenticated user.
                        }
                        return res || $q.when(res);
                    }
                };
            }
        ]);
    }
]);
El_Matella's avatar

Hi everyone, thank you for all your answers! @willvincent : Thank you for the links, I am going to read them all, this scotch.io website is full of great resources about this subject! @mehany : Thank you for the code, it helps a lot and I think that you have the best answer of this topic... However, I am not even going to use the same server to store the angular application and the laravel API so I don't even need to create this partials route, but I can now see the general organization. Thanks a lot!

Have a nice day everybody :)

Please or to participate in this conversation.