PHP Microservices — Organizing Access To Multiple Services

Devin Dixon
Jan 4 · 7 min read

When venturing out to build an architecture using microservices, how you construct the services will be pivotal in the way you are able to manage, scale and secure your application. Building up from our other tutorials, we are now going to learn how to structure access your microservices.

Our Journey Thus Far with Microservices

With Microservices we covered a few topics and still have a few more to go. Before diving into this tutorial, it is suggested that you understand the past topics:

These short prior examples are important for understanding this part of the series. After this tutorial, we will get into security, deployment and creating fault tolerance.

What Are We Building Now

We are building an abstraction layer that allows any device to easily connect with a multitude microservices. We are also setting up an architecture that we can maintain and scale.

Important Considerations

When architecture a solution, we have to take a lot into consideration as our choices will affect how robust our design is and how it will perform in the future.

Devices That Will Access Our Services

A service will be accessed by a variety of devices that can include mobile phones, smart TVs, web browsers, bots, other services and more. It is important to choose standards that are widely implemented and accepted by a variety of devices.

For example, what if we design our solution to accept UDP calls? A PhoneGap mobile app is going to have an uphill battle with finding solutions that are vetted, up-to-date, and have community support to connect with our service. Libraries that address the problem like PhoneGap Datagram and chrome.sockets.tcp Plugin have not been updated in years.

Easy For Developers To Implement

If the services you are building will have external connections to the world, consider following the standards everyone else is using. Using SOAP is a painful experience for many developers and creating a service with SOAP can hurt adoption. There is a reason why people do not rave about WSDLs.

Ease of Organization and Management

No developer is going to build a large amount of microservice and be the only person to access and maintain them. The services has to be clear in how it's organized to the point where it is intuitive, easy to teach others, and easy to manage when you have to make changes.

Think of if we had a bunch of sockets, each with IP address of 198.x.x.x. It is not an easy nor intuitive way to remember what IP routes where. Even we rename them with domain names, ie video.example.com, organizing actions against the domain can be quite cumbersome. For the video domain, how do we tell it to upload a video vs stream a video? You would have to create your own standards and teach them to others.

The Winner Is…..REST with JSON

There have been many options for communicating with microservices including SOAP, XML, and RPC. REST has become the goto defacto because:

  1. Utilizes HTTP/HTTPS, which many devices natively support.
  2. Easy to learn with CRUD (POST, PUT, DELETE, GET).
  3. Easy to group functions with endpoints. Example a video server can have the endpoint /videos and with urls that intuitively describe the action. ie /video/create, /video/find, etc.
  4. JSON has become a universally accepted format that is easy to create and parse

RESTFUL CRUD APIs in this tutorial approach are NOT microservices but act as abstraction layers for easily accessing microservices. Below we are going to build out a solution that leverages multiple microservices.

Follow Along With The Code

Ready to put the above into a working model?! This tutorial goes in depth, and we encourage you to follow along and play with code examples at:

https://github.com/ProdigyView-Toolkit/Microservices-Examples-PHP

Look in the folder labeledmultiple.

Creating An Easy To Use Client API

Let’s begin with the client how clients connect. Regardless of the device (SmartTV, Website, Phone, another service, etc) or developer accessing your microservices, we want to make how to utilize our API as easy as possible. So we assign human readable HTTP routes with understandable options. Two examples:

How To Send A Push Notification To Our Service

  • Send a PUT request to localhost:8080/notifications
  • Pass along in the request the variables device_token and payload as an array
//Attempts To Send Push Notification
$curl = new Curl($notifications_route);
$curl->send('put', array(
'payload' => array('type'=>'pop_up', 'message'=> 'Hello World')
'device_token' => 'abc123',
));

How To Upload A Video To Our Service

  • Send a POST request to localhost:8080/media
  • Pass along in the request the url of where the video can be downloaded, and a format to convert the file too in convert_to option.
//Send Video To Be Processed
$curl = new Curl($media_route);
$curl->send('post', array(
'url' => 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4',
'convert_to' => 'mov',
));

That’s it! By making the API simple to understand and easy to use, we increase the ability for developers to successfully connect. Underneath the hood, they do not need to know the complexities or that it is being processed by a totally different service. Full code below of the client:

client.php

Getting Started With Our Endpoints

In our example, we are going to have 3 endpoints:

  • /notifications for emails and push notifications
  • /media for video and image files
  • /articles for manipulating article data

Each endpoint must process the request sent by the client above. We are going to recieve GET, POST, PUT and DELETE request over HTTP. Begin each endpoint with the below code:

//Process The Current HTTP Request
$request = new Request();
//Get The Request Method(GET, POST, PUT, DELETE)
$method = strtolower($request->getRequestMethod());
//RETRIEVE Data From The Request
$data = $request->getRequestData('array');

With the request method and data gathered, we can now set routing, to pass along information to the correct functions:

//Route The Requests
if ($method === 'post') {
post($data, $channel);
} else if ($method === 'put') {
parse_str($data,$data);
put($data, $channel);
} else {
sendResponse(json_encode(array('status' => 'No Service Found')));
}

Next, we can connect to the appropriate microservices based on route and request method. Behind the scenes, we are about to use multiple technologies. One endpoint uses Sockets and the other RabbitMQ. These details are completely abstracted from the client. Full code below.

/media endpoint + RabbitMQ

Take notice that we are using two different queues of ‘image_processing’ and ‘video_processing’ for RabbitMQ. All PUT requests will go the image queue and all POST requests to the video queue. The final step is then sending it to RabbitMQ as an AMQ Message. Below is our a notification endpoint that is going to Sockets.

/notifications endpoint + Sockets

Take note again, the API is responsible for setting the type based on a PUT or POST as we hide complexity away from the developer. Afterward, it uses a socket to send the information to a Socket Server.

Now that we have our API endpoints setup, we can move onto the servers that will process the requests sent from the endpoints.

The Servers

Our servers have to now recieve and process the requests. In the client examples above, we use both socket programming and RabbitMQ. Our servers will do the same.

RabbitMQ And Media Processing

Our server has 2 queues it is listening for, image_processing and video_processing. The queues are processing what the API endpoint sent. Each queue responds first by downloading the file from a URL and saving it locally.

Afterward, the media file is processed from the local file system.

Videos go through ProdigyView’s Video::convertVideo function which is an abstraction of FFmpeg. Images go through watermarkImageWithText method which is an abstraction Imagick. The last step is to upload the processes video to an s3 bucket. Full code below:

Socket Server with Email + Push Notifications

Our notification server is processing information received from the /notification endpoint via sockets. Similar to our previous example with Socket Programming, we first decrypt the message and check the token.

//Decrypt our encrypted message
$message = Security::decrypt($message);
//Turn the data into an array
$data = json_decode($message, true);
if ($data['token'] == 'ABC123-NotRealToken') {
//...

What is different this time is checking the type of message. Our REST API above responsible for setting the message type.

if ($data['type'] == 'email') {
$email = new Emailer();
$response = $email->send($data);
} else if ($data['type'] == 'push_notification') {
$notification = new PushNotification();
$response = $notification->send($data);
}

If we required developers to set the type manually, we would have to take into account other issues that might occur such as:

  • The type not existing
  • The type spelled wrong by accident
  • Managing new types

By not exposing this functionality, make can make both our lives and the lives of the developers calling the microservice easier. Finally, depending on the type, we pass the data to either an email class or a push notification class for processing. Full code below:

Wrap Up

To better understand the code, please play with the examples here.

We have now structured our RESTFUL API to organize and manage communication with microservices.The API then sends the requests received from outside developers to different microservices that each handles their communication in a different way.

We can scale out the API by adding new services and requiring that each service use the APIs to talk to each other. With good naming conventions, you can keep the code organized as you grow.

A very important point to consider with this tutorial. We have one API that exists at 127.0.0.1:8080. A question you will have to answer as a developer is do you want one API or would you want each service to have their own API as an abstraction layer. Each comes with its pros and cons that we will discuss next with fault tolerance and scaling

Helium MVC

The blog of the Helium MVC and ProdigyView Toolkit

Devin Dixon

Written by

Entrepreneur, Technologist, Runner.

Helium MVC

The blog of the Helium MVC and ProdigyView Toolkit

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade