New PHP framework for creating microservices
Tags: php, microservices, architecture
Published: 2020-02-10 20:39:07

Hello everybody, my name is Alex. And I want to present you my PHP framework for creating micro services. It is based on my experiments in this area, then it has become a pet project, and then I have created several projects, wich are based on this framework.

When I have started developing it, I what to make solution wich:

* can be easily used in the existing projects and legacy code;
* have ability to create simple things fast;
* be neat and expressive;
* use abilities of the modern PHP.

What will be the first step? Sources of course ) [It can be found on github](https://github.com/alexdodonov/mezon)

And to start fast lets create the first hello world application.

First of all, we need to understand how our endpoints will be called.

If you are using Apache, then you can create .htaccess file, with the following content:

```# use mod_rewrite for pretty URL support
RewriteEngine on
RewriteRule ^([a-z0-9A-Z_\/\.\-\@%\ :,]+)/?(.*)$ index.php?r=$1&%{QUERY_STRING} [L]
RewriteRule ^/?(.*)$ index.php?r=index&%{QUERY_STRING} [L]```

It will allow you to call endpoints like this https://localhost/hello-world/

But if you are using nginx or don’t want to use .htaccess then you can call endpoints in this way: https://localhost/?r=hello-world

And now we’re ready to create our first micro service. It will consists of one endpoint, wich will handle GET requests and return information that he is OK ) A sort of health check.

First of all, we need to add our framework to the project:

```
composer require mezon/mezon
```

Then include autoload.php

```php
require_once (autoload.php');
```

And the first class will look like this:

```php
class TodoService extends \Mezon\Service\ServiceBase implements \Mezon\Service\ServiceBaseLogicInterface
{ /* class body */ }
```

More details about it:

**ServiceBase** – base class for all micro services with the most common functionality;

**ServiceBaseLogicInterface** – this interface must be implemented by class if it contains endpoint handlers. It does not yet force you to implement methods, it is just made for more strict typization.

And now we are ready to implement the first endpoint handler:

```php
public function actionPing()
{
return ('I am alive!');
}
```

And then launch it:

```php
\Mezon\Service\Service::start(TodoService::class);
```

Let’s combine all lines of code and look at the whole picture:

```php
/**
 * Service class
 */
class TodoService extends \Mezon\Service\ServiceBase implements \Mezon\Service\ServiceBaseLogicInterface
{
    /**
     * First endpoint
     */
    public function actionPing()
    {
        return ('I am alive!');
    }
}

\Mezon\Service\Service::start(TodoService::class);
```

You may want to ask me – wich URL should we call? The truth is that if you have method with  the name action<Name-part> it means that framework will automatically create handler for the URL <name-part> In our case it will look like this https://localhost/ping/

By the way: capital letters will be replaced on lower case letters prefixed with ‘-’. For example the method actionHelloWorld will become handler for the next URL: https://localhost/hello-world/

Let’s dig deeper.

All of you know good practices for applilcations. For example, MVC (or any other pattern of the same kind). We have the same story in the world of micro services. I mean that all things wich must be isolated better keep isolated.

In our case service’s class should do one thing – combine parts of this puzzle and logic should be in another class. To do this let’s modify our code as shown below:

```php
class TodoLogic extends \Mezon\Service\ServiceBaseLogic
{

    /**
     * First endpoint
     */
    public function actionPing()
    {
        return ('I am alive!');
    }
}

class TodoService extends \Mezon\Service\ServiceBase
{
}

\Mezon\Service\Service::start(TodoService::class, TodoLogic::class);
```

You may notice that we have created separate class with our logic:

```php
class TodoLogic extends \Mezon\Service\ServiceBaseLogic
```

It is derived from the class **ServiceBaseLogic** (it provides some functions wich will be described further).

The class **TodoService** is no longer implements the interface **ServiceBaseLogicInterface**, but now the class **ServiceBaseLogic** implements it.

After the logic was excluded from the service class and moved to the logic class we have got quite empty class. And it can be completely removed:

```php
class TodoLogic extends \Mezon\Service\ServiceBaseLogic
{

    /**
     * First endpoint
     */
    public function actionPing()
    {
        return ('I am alive!');
    }
}

\Mezon\Service\Service::start(\Mezon\Service\ServiceBase::class, TodoLogic::class);
```

In this example the service is launched by default class **ServiceBase**, not our custom one.

Let’s dig even more deeper.

After I have used this framework in several projects I have got quite huge classes with tons of busyness logic. From one side it was hurting my eyes, and from the other side Sonar Cube have raised lots of errors, and finally it was not clear how implement strategy of separating read- and write methods (i.e. CQRS).

That’s why I have implemented the feature wich allows group handlers within separate classes with logic. And it allows to use them within on service or in separate ones.

For example, you can implement the whole CRUD logic in one service. But you can also split methods in two groups:

* group of methods for reading data (R in CRUD);
* and group of methods for changing data (CUD in CRUD).

And as an illustration let’s add several new methods:

```php
class TodoSystemLogic extends (\Mezon\Service\ServiceBaseLogic
{
    public function actionPing()
    {
        return ('I am alive!');
    }
}

/**
 * Read logic implementation
 */
class TodoReadLogic extends (\Mezon\Service\ServiceBaseLogic
{
    public function actionList()
    {
        return ('List!');
    }
}

/**
 * Write logic implementation
 */
class TodoWriteLogic extends (\Mezon\Service\ServiceBaseLogic
{
    public function actionCreate()
    {
        return ('Done!');
    }
}

\Mezon\Service\Service::start(\Mezon\Service\ServiceBase::class, [
    TodoSystemLogic::class,
    TodoReadLogic::class,
    TodoWriteLogic::class
]);
```

Let’a review main changes:

* we have created classes with logic **TodoSystemLogic** (system methods), **TodoReadLogic** (read methods), **TodoWriteLogic** (data change methods);
* when the service is launched we pass several classes with logics as parameters, not one like in the previous examples.

Well that’s all for today. Other abilities of the framework will be described in the next article. There are a lot of thigs to be shown. And for now visit [repository of the project](https://github.com/alexdodonov/mezon)

# Learn more

More information can be found here:

[Twitter](https://twitter.com/mezonphp)
[Mezon Framework](https://github.com/alexdodonov/mezon)

# It will be great if you will contribute something to this project. Documentation, sharing the project in your social media, bug fixing, refactoring, or even **[submitting issue with question or feature request](https://github.com/alexdodonov/mezon/issues)**. Thanks anyway )