From music streaming monolith to service-oriented, Kubernetes backed loveliness
Laravel Codebase
API
Services
Website
CMS
Reporting
Web Traffic
Mobile Apps
Analytics
Cron Jobs
CMS Traffic
Audio Content
Reports
Insights
Emails
Notifications
composer require aws/aws-sdk-php "^3.0"
Your requirements could not be resolved to an installable set of packages
Core
Reporting
API
Website
CMS
CQRS Interface
Database
Analytics
Web Traffic
Mobile Apps
Analytics
Cron Jobs
CMS Traffic
Audio Content
Ingestion
Kubernetes
Stop bitching about technical debt.
Laravel's session based authentication mechanisms make use of a contract called UserProvider.
It's responsible for converting a set of credentials into a User object.
Luckily it's swappable in Laravel's config files.
The built in provider is called DatabaseUserProvider.
public function retrieveByCredentials(array $credentials)
{
$user = User::where('email', '=', $credentials['email'])
->where('password', '=', $credentials['password']);
return $user;
}
We just had to create our own version which talked to our core service:
public function retrieveByCredentials(array $credentials)
{
$core = app()->make('CoreCommunicationsContract');
$user = $core->call('swapCredsForUser', $credentials);
return $user;
}
Then all we had to do is register the new UserProvider
'providers' => [
'users' => [
'driver' => 'core'
],
],
And set it as the default in config/auth.php
Auth::provider('core', function ($app, array $config) {
return app()->make(CoreUserProvider::class);
});
And what about the API service?
We used Passport to handle API auth which uses the same UserProvider mechanism as session based auth.
Copy and paste implementation from the website codebase.
It was that easy?
No.
Passport is hard coded to store oAuth tokens in a database.
Guess they forgot to interface everything.
Ended up having to subclass a hierarchy of about 6 dependent classes just to inject a custom storage mechanism.
1. Interface Everything
"Always build to an interface"
Always wrap internal and external components with an interface
Things we can swap the implementation of on a whim:
Analytics, logging, Facebook, Stripe, iTunes, Google Play, Amazon API, audio delivery, dynamic playlist generation....
2. Extend Laravel's Config
Laravel's config system is great.
It can hold anything you like.
Values can be loaded from the environment which coincidentally is the best way to pass information into a docker container when it boots up.
'radio_playlist_algorithm' => env('RADIO_PLAYLIST_ALGORITHM', 'random-library-resources'),
config/app.php
docker-compose.yml
environment:
- "RADIO_PLAYLIST_ALGORITHM=analytics-backed"
AppServiceProvider.php
$radioAlgoClass = config('app.radio_playlist_algorithm') == 'random-library-resources'
? RandomRadioPlaylistAlgorithm::class : AnalyticsBackedAlgorithm::class;
3. Profit
Q's?
@mattgrayisok