DEV Community

Rahimie Ahmad
Rahimie Ahmad

Posted on

Morphing a monolithic app to microservices oriented with Exedra

What is exedra

In short exedra is a PHP microframework that focuses on nested URI routing.

So down into the business

One of the hardest thing about going for a future-proof development is, you ain't gonna know at first how far the current design of your app can go, and how big your product can be in the future. Often you begin with something simple, and deep inside you want this the development/product to scale with ease at one point.

So first, let's visualize some app with this kind of routing.

GET   /
GET   /about-us
GET   /contact-us
GET   /careers
GET   /apis/users
POST  /apis/users
GET   /apis/users/:id
PATCH /apis/users/:id
GET   /apis/products
POST  /apis/products
GET   /apis/products/:id
PATCH /apis/products/:id
GET   /images/users/:id/avatar
GET   /images/products/:id

Now you have a simple app that serve some frontend page, have some user and products APIs, and some images processing routing. So it's all served/hosted through a single service let's say www.nexty.app.

So you have something like this with exedra :

$app->provider->add(RoutellerProvider::class);

$app->map['web']->any('/')->group(WebController::class);
$app->map['apis']->any('/apis')->group(ApisController::class);
$app->map['images']->any('/images')->group(ImagesController::class);

Many moons later. Your app grows to hundred of routes. It serves hundred of thousands of requests a day. And you realized it's bottlenecked by this single monolithic webservice. Yes, you can scale this service horizontally by increasing the cpu power and memory, but deep inside you know you want something much better. You want to break this big fat monolithic service.

You want break it into something like:

  • www.nexty.app to serve the frontend only
  • apis.nexty.app to serve the APIs
  • images.nexty.app to serve processed images alone

You want to break it fast without breaking your code.

You don't want to have different repos for difference services altogether, and a lot of people think that monorepo and monolithic are mutually the same. They think you need to break your repo, your development and everything you once knew into the services you want to have, and that includes breaking a shared codes/model that once depends on each other. Now you have one major problem.

But all you want is a multi-services that just work without breaking everything.

With Exedra, you can do it through a domain based routing through a complete URI.

$app->map['web']->uri('https://www.nexty.app')->group(WebController::class);
$app->map['apis']->uri('https://apis.nexty.app')->group(ApisController::class);
$app->map['images']->uri('https://images.nexty.app')->group(ImagesController::class);

Make sure you provide along with the URI scheme (http/https) so it recognizes the host information of the URI.

But at the same time, you don't want to complicate your local/dev environment. So how would you do this with exedra?

You can externalize the URIs through your environment variables.

// assuming that the `env` values is loaded from dotenv if we're using dotenv
$env = $app->config->get('env');

$app->map['web']->uri($env['WEB_URL'])->group(WebController::class);
$app->map['apis']->uri($env['APIS_URL'])->group(ApisController::class);
$app->map['images']->uri($env['IMAGES_URL'])->group(ImagesController::class);

Without complete URI (without scheme, and port number), it'll not register the host information. For example if you give it 'localhost' alone, it'll register as /localhost path instead. It utilizes the parse_url php function.

So you'll have some .ENV config like below for your development (assuming that you use dotenv)

WEB_URL=/
APIS_URL=/apis
IMAGES_URL=/images

So, that's it with Exedra! Then all you need to do is to have a config server and some proper deployment pipeline configured maybe. I am not sure, maybe you can share with me your solution on environment config deployment for microservices. ;)

I am not sure how other modern frameworks do this, maybe you can share with me if it's also possible to do a domain based routing without going through some URI rewrite.

Until then, thank you!

Top comments (0)