Laravel vs Lumen

owlmanatt

Programmer
I've seen some mention of Laravel around these parts. I'm doing something with Lumen, which is Laravel's micro-framework edition, so I thought I'd post some thoughts on the two.

As I said, Lumen is a micro-framework. The primary use-case is for building REST APIs, so everything to do with templates has been pulled out of Lumen. Out of the box, Lumen doesn't have a bunch of the libs you find in Laravel either -- Eloquent is disabled, mail is disabled, and there's no config/ dir. However, all of this can be re-enabled if you need it.

What I'm doing with the framework is building the backend for a pet game. Separately, I'll have the UI as a single-page javascript app, and 3rd party forum software. I thought Lumen would be ideal for this, but I ran into a few problems:

1. My API is the authentication source for the UI & forums. I wanted to implement an OAuth provider, which is trivial in full-on Laravel -- they have Passport, which integrates the very-good League OAuth provider code into the framework. Lumen, however, strips this out!

The challenge isn't insurmountable, though. I took a look at the Passport code and started thinking about what it would take to make it play nice with Lumen. It has some things that aren't part of the API authentication flow -- mainly, views for authorizing other apps. Fortunately, I typed some words into the googles machine at this point, and discovered that somebody had already solved the problem: https://github.com/dusterio/lumen-passport

This is working fine for me, so far. In the future, if I want to enable other apps to get API keys for a user's data, I might need to extract the OAuth provider from the main game API and deploy a small Laravel site that just runs passport.

2. The ReCaptcha lib for Laravel has some views in it, boo. I wrote a quick wrapper for the PHP ReCaptcha lib. This might actually be useful to somebody else, so splitting this off into a standalone package is on my todo list.

The site worked, but my unit test started failing. I don't really want to test the ReCaptcha code from google, so I had to mock the library. Initially, when I had written my wrapper, it was just a class. In order to get it to play nice with Mockery, I had to turn my class into a facade. This took a bit to figure out -- strangely, there wasn't that much up-to-date documentation on how to add your own facade to the framework.

3. There was no config/ dir. Because Lumen's focus is on being small and simple, I guess they decided not to have that out-of-the-box anymore. That's all well and good until you enable something that expects to find a config...

Fortunately, all they did was not create the folder by default. If you make the directory and drop files in, they'll get picked up by both the framework and any 3rd party plugins.

4. Lumen was missing major bits of illuminate (the supporting libs for Laravel & Lumen) that I wanted to use. The biggest one was Eloquent, but turning that on is trivial; there's a line commented out in the bootstrap.php file. Turn it back on and your ORM is in business.

My API is handling user signup and forgot password requests. Unfortunately, Lumen doesn't come with Illuminate/Mail. That one is a little trickier to re-enable: you've got to add it to install it with composer, register the MailServiceProvider, create a config file, and load the config in bootstrap.php.

The mail thing is another reason I'm thinking about cutting the OAuth provider out of my API and moving it to a dedicated auth provider laravel project.

Anyways, that's about it for my braindump. Aside from all the missing stuff, the final difference between Laravel & Lumen is that Lumen controllers expect you'll be spitting out JSON instead of rendering views. It's quite pleasant, assuming that's what you want to do!

So yeah. I'm happy to field questions about Lumen. You can check out my code if you're so inclined.

 
This is a wonderful write up on the differences between the two. Normally, I have always used Laravel as the source, and just ran the single page app through a view, which means I get the best of both worlds, and some of the bulk too. I have only messed with Lumen slightly, so I am happy that you wrote this up.

 
Here's another thing that had been vexxing me for awhile: Passport keeps some encryption keys in the storage/ dir. It requires the permissions be set to 600 on the files so only the owner can read the keys. I'm running Apache instead of the built-in dev server, so these key files are owned by my apache user so authentication will work.

The problem is when I'm running unit tests, a bunch of test cases would fail because Lumen would try to verify the bearer token as a valid session. Since these are running as me and not Apache, Passport would get an access denied for the keys and throw an exception.

The solution is actually pretty easy --  generate a new keypair for unit testing and stick the keys in a new dir under storage. Then, in your base class for your unit tests:

public function setUp()
{
parent::setUp();

// If you're using this as a dev env, you might have Apache as the owner on the files for the default location.
Passport::loadKeysFrom(storage_path('phpunit_passport_tokens'));
}


I think this is just for signing the tokens, so it has no relationship to the client secrets that get stored in the DB. I, uh, am not entirely sure if that gets created when running the unit tests...? But with actingAs(), all the authenticated requests are just using a mocked guard provided by Passport, so no big deal I guess?

 
Hey @owlmanatt, great to see you're back :)

I am wondering though, isn't it a bit 'under' kill to use lumen for creating APIs (depending on the API's size/functionality of course).

I know Taylor initially used it himself for webhooks (e.g. the online status checker on forge), where a full-on installation of Laravel would use too much resources for a simple DB update.

However, if you're creating an API for an app or a website, in't it handier to have eloquent, mail, config bootstrapped and functional?

 
@HappyDemon

I've recently been using this setup (Laravel application; Lumen API) for a project I'm working on. Lumen is setup to easily allow you to use Facades and Eloquent right from the get-go simply by uncommenting a couple of lines.

The only problem I had was using Passport for authentication and integrating it with my application and my API: such as having authentication persist even on page refresh, setting the Authorization header, using Pusher in my application which requires the user to be authenticated through the auth facade.

But as an overall framework, Lumen works great.

 
Last edited by a moderator:
I have to agree with @HappyDemon's assessment -- it's underkill for my purpose. I saw it was labeled as the microservice edition of Laravel, but what I'm doing stretches the definition of microservice considerably.

With that said, getting Facades and Eloquent turned on is easy and supported out of the box. Regaining the other bits of Illuminate is fairly simple too, but perhaps not a good idea long-term -- making it easy to turn Lumen back into Laravel is probably not something Otwell is concerned with, so I expect it will cause at least some pain down the road.

The immediate problem is the Passport shim. I want a full-blown OAuth provider, but right now I'm missing the authorization / scope management stuff because Lumen doesn't do views.

In the spirit of ~servicing all the things~, I'm probably going to split the OAuth provider into its own stand-alone Laravel app at some point, as well as cutting auth data and separating it from my main `users` table to preserve sanity (auth site manages auth data, game API manages all the other bits of user).

In retrospect, I probably should have just gone with Laravel. It's not really that hard for me to swap over, but I think I have all the Illuminate functionality I need now, so I'll keep on trucking and see what happens.

Lumen really shines for actual microservices -- I started working on a stand-alone imagicking service (which is, at the moment, perhaps the most over-engineered compositeImage call ever) -- and it was frictionless.

 
Back
Top