Technologies

Lumen in public catalog

lumen,laravel,php,public
lumen,laravel,php,public

Recently at HighSolutions we have had a small project from our client where we were asked to polish up the design and enhance the API for their React-based Calculator web application. We’re big fans of Laravel, so we decided to replace the poorly written API with fast and maintainable API in Lumen.

The only problem here was the fact that we did not have access reaching beyond public_html, so we were forced to insert Lumen in the public catalog.

Thus the structure of folders looks like this:

ReactProject

We also wanted to maintain all routes to API from the old system, so we were forced to put Lumen in api folder.

Specification of routes looks the following way:

GET	api/categories.php	Return JSON with list of categories and nested subcategories
POST	api/user.php		Return JSON with authentication result≤/code>≤/pre>


≤p>So to make it work, we had to:≤/p>
≤ol> ≤li>Firstly, direct all traffic going to ≤strong>http://react-project.dev/api/≤/strong> to ≤strong>/api/public/index.php≤/strong> file, which can be done by ≤strong>.htaccess≤/strong> in ≤strong>api≤/strong> folder.
≤pre class=" line-numbers language-apache">≤code class=" language-apache">≤IfModule mod_rewrite.c> RewriteEngine On RewriteBase /api/ RewriteCond %{THE_REQUEST} ^GET\ /public/ [NC] RewriteRule ^public/(.*)$ $1 [L,R=301,NE] RewriteRule ^((?!public/).*)$ public/$1 [L,NC] ≤/IfModule>≤/code>≤/pre> ≤ul> ≤li>First, we set RewriteBase to /api so, every request will be going there, not to main domain.≤/li>≤/ul> ≤/li> ≤ul> ≤li>Second rule is required to redirect every request to public/index.php.
≤/li>≤/ul> ≤ul> ≤li>Especially when we are doing this for the purpose of the last rule to redirect all traffic that is not getting to public catalog to this particular one.≤/li>≤/ul>
≤li>Secondly, once we have already redirected everything going to ≤strong>http://react-project.dev/api/index.php≤/strong>, we have to handle requests going there. So content of ≤strong>.htaccess≤/strong> file in≤strong> api/public/≤/strong> looks more conventionally:
≤pre class=" line-numbers language-apache">≤code class=" language-apache">≤IfModule mod_rewrite.c> Options -MultiViews RewriteEngine On RewriteBase /api RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule . index.php [L] ≤IfModule>≤/code>≤/pre> ≤ul> ≤li>≤strong>This is very similar to standard ≤/strong>.htaccess≤strong> for Laravel. The only difference is RewriteBase, once again set to ≤/strong>/api≤strong>, because we are in subfolder of main domain.≤/strong>≤/li>
≤/ul> ≤/li>≤/ol> ≤h2>What we should do when we want to use Lumen API inside Laravel app?≤/h2> ≤p>Sometimes we might need to have a dedicated API outside Laravel, but also in ≤strong>/api/≤/strong> folder. How to do this? With our ≤strong>.htaccess≤/strong> files it’s very simple.≤/p> ≤p>We need three ≤strong>.htaccess≤/strong> on three different levels:≤/p> ≤img src="https://static.highsolutions.pl/uploads/uploaded/blog/structure2.png" alt=".htaccess">

≤ol> ≤li>First basic ≤strong>.htaccess≤/strong> is for Laravel:
≤pre class=" line-numbers language-apache">≤code class=" language-apache">≤IfModule mod_rewrite.c> ≤ifmodule mod_negotiation.c> Options -MultiViews ≤/ifmodule> RewriteEngine On # Redirect Trailing Slashes If Not A Folder... RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)/$ /$1 [L,R=301] # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] # Handle Authorization Header RewriteCond %{HTTP:Authorization} . RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] ≤IfModule>≤/code>≤/pre> ≤ul> ≤li>This is standard Laravel’s 5.4 .htaccess and we don’t need to do anything here. We don’t need to redirect API neither, because this will be handled by next .htaccess files.≤/li>≤/ul> ≤strong>
≤/strong>≤/li> ≤li> Second ≤strong>.htaccess≤/strong> is for api catalog inside public catalog of Laravel

≤pre class=" line-numbers language-apache">≤code class=" language-apache">≤IfModule mod_rewrite.c> RewriteEngine On RewriteBase /api/ RewriteCond %{THE_REQUEST} ^GET\ /public/ [NC] RewriteRule ^public/(.*)$ $1 [L,R=301,NE] RewriteRule ^((?!public/).*)$ public/$1 [L,NC] ≤IfModule>≤/code>≤/pre> ≤ul> ≤li>It’s just as explained in the first part of the article.≤/li>≤/ul>
≤/li> ≤li>Last ≤strong>.htaccess≤/strong> is inside api/public and it’s the same as the first one:
≤pre class=" line-numbers language-apache">≤code class=" language-apache">≤IfModule mod_rewrite.c> ≤ifmodule mod_negotiation.c> Options -MultiViews ≤/ifmodule> RewriteEngine On # Redirect Trailing Slashes If Not A Folder... RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)/$ /$1 [L,R=301] # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] # Handle Authorization Header RewriteCond %{HTTP:Authorization} . RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] ≤IfModule>≤/code>≤/pre> ≤/li>≤/ol> ≤p>The last thing to do is to wrap all routes in ≤strong>Route::group≤/strong> with prefix="api":≤/p>≤pre class=" line-numbers language-php">≤code class=" language-php">≤!--?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It is a breeze. Simply tell Lumen the URIs it should respond to | and give it the Closure to call when that URI is requested. | */ $app->group(['prefix' => 'api'], function() use ($app) { $app->get('', function () use ($app) { return $app->version(); }); $app->get('hello', function () use ($app) { echo 'world'; }); });≤/code>≤/pre> ≤p>And it’s working.≤/p>
≤p>You just need to remember that in Laravel app you cannot specify routes in ≤strong>/api/≤/strong>. We recommend to write comment in ≤strong>api.php≤/strong> and to remember this:≤/p> ≤pre class=" line-numbers language-php">≤code class=" language-php">≤!--?php /* All API routes are stored in public/api/routes */

That’s all.


Of course you need to remember to restrict access to all vulnerable assets like .env files and config files. If you can hide applications files under public catalog, do it.

You can also have API under domain catalog, when you use subdomain e.g. https://api.react-project.dev. We recommend this option, but if it is not possible, you know what to do.

If you have better ideas, don’t hesitate to share it with us.

Adam Matysiak
Owner, former CTO and leader. Software developer with over 15 years of experience. Ethusiast of Laravel framework and chatbots. Teal blogger for "Turkusowy Prezes" and speaker on programming and teal management conferences. In his free time he loves running and cross-fit.

What do you need?

Website

IT system

Mobile app

Graphic design

Technical support

Chatbot

The preferred form of contact

Please provide contact details

The personal data administrator is HighSolutions sp. z o.o. (hereinafter the "Company") with headquarters in Tarnowo Podgórne, ul. Szkolna 21/1, 62-080 Tarnowo Podgórne, e-mail adress kontakt@highsolutions.pl. Detailed information on the processing of personal data can be found in the privacy policy.

Thank you!

We will get back to you soon