Interfaces & Routes; The Project's frontline

Introduction

Interfaces are the frontline of the project and are written in pure PHP language. When the Server project receives a request, the Route Detection Unit which is implemented as a service called RouteService, decides what Interface to execute based on a file called routes.xrml. The Interface then returns a string as the response.

Structure

An Interface block has the following structure.
# Path\To\Interface\InterfaceName
 
# Description of this Interface, probably in markdown formatting
 
Interface [extends Path\To\Another\Interface\InterfaceName] {
  INTERFACE_BODY
}
Note that there is no name for the Interface. An Interface name is its file path. Each file can contain at most one block, and the block inherits its name from the file. It is a good practice to have a comment in the first line of the file describing where the file is located.

Hierarchy

Interfaces can come in a hierarchy, just like PHP classes. It is possible to call the parent Interface body in the child Interface since the Interface content is written in PHP. Just note that the method, when compiled to PHP, is called execute. So, to execute the parent Interface body, one must write parent::execute().

Xua's Route Minimal Language

The file routes.xrml is written in a specific language called XRML, with the following grammar.
An example of this file would be as following.
We use this file to explain all of the XRML features step-by-step.

Literal Routing & The Routes Tree

When the Server project receives a request, the main file asks the RouteService to find the desired Interface. The Route Service then explodes the requested URL into different pieces by the / character.
Assume the client sends a GET request to localhost:8000/media/post. The result of exploding this URL would be the list ['media', 'post']. The Route Service then looks into the routes.xrml as a tree, finds the node matching the list's first item, and gets the subtree. Then looks for the list's second item in the subtree and continues the process until it finishes the list. Then looks into the Interfaces provided for that line and chooses the one matching the request method, Post\GetAll. If it can't find such an Interface, it throws an Exception called RouteException, which the ExceptoinService will handle.
Note. The / route is only valid on the root tree, and no subtree can contain such a node. Violating this rule will result in a RouteDefinitionException.
There are two ways to define Interfaces. One is to define an Interface for each HTTP method, in which case if the request method is not defined, the Route Service will throw a Route Exception. However, if one wants to set an Interface for all methods without specifying them, they can just set the Interface without any methods provided, so the Route Service will divert all requests on that URL to the defined Interface regardless of the HTTP method.
In the example above, Route Service will divert all requests to localhost:8000/404 to the Xua\NotFoundInterface.

Variables & Priorities

Assume the client sends a GET request to localhost:8000/media/post/12/delete. The result of exploding this URL would be the list ['media', 'post', '12', 'delete']. The Route Service gets the subtree with post as root, and in that tree, it can't find any route equal to the literal string '12', but instead, there is the route {id} with opening and closing braces indicating a variable. This way, the Route Service knows it can match any string with that route, and it'll save the string '12' under the variable name, which is id. The Route Service will process further until it finds the Interface Post\RemoveOne. Now the variable is available in the body of that Interface as RouteService::$routeArgs['id'].
Note. If one of the siblings of a variable matches the desired route section, Route Service processes that node since literal route sections have a higher priority than the variable route sections; but if further processing the route would result in Route Exception, the Route Service would come back until the latest variable and processes the route in that direction, if it can't find the route in that direction either, it goes back and does the same procedure until possible.
Note. There can't be two variable route sections as siblings, as this will result in a RouteDefinitionException.