Routing
We have decided to use this framework for 2 purposes, first for terminal usage, second is to generate endpoints for REST.
Terminal usage
Sometimes all I need is to run a piece of code to do a simple job for my daily usage. For example I want to access a remote blog daily, read it, check for certain phrases and store the result (whatever result I want) into the database. I will run this on the server, and won’t even bother to create a web service for it. If my router understands where the request is coming from, then I can bypass all the authentication/authorization work and focus on the job itself.
I also may want to test my code during the development. Dealing with access tokens is a lot of work and creates another workload. Running your tests via the terminal just speeds things up.
I should be able to go to my root directory and run:
php index.php my_module my_method [arguments]
And the code simply should run and parse the result (if there is anything to print).
The first part of the code handles the terminal requests. Please see the routing.php file for the details.
REST requests
If I create a web service, my request should be checked for authentication and authorization first, then run if permitted. The second part of the code handles this. In the beginning, we tell the server that this should return json data and set the necessary header information. Later we check all the routing.json files under each module to see if the upcoming request and request method are matching with anything we have. If there is a match, we check for the access token to make sure that the user is authenticated and then for the authorization to make sure that the user is authorized to execute the request.
- User makes a request to an endpoint with a method such as
POST /articles/1
- Router checks for the Bearer information in the header. Collects the
access token
value and tries to load the user. If there is a user defined with the Bearer information, it continues to run, otherwise returns with the header403 Forbidden
- If the user is trying to authenticate, the system checks for the existing user credentials and returns with the
access_token
. Users can use this information for future requests. If the 1 hour access token lifetime is finished, the user can always use therefresh_token
provided with the access_token to generate a new access_token. - The system checks for the endpoints defined under each module, if there is a match, it checks if the user has permission to access to this endpoint by looking at the permissions that they have. See here for more information on users/roles/permissions.
- If the user has the permissions to access that endpoint, the router finally directs the request to the responsible method under the defined module.
That might be a lot to digest, so let’s talk about the user/roles/permissions.
users/roles/permissions
A user is an entity and its information is stored in the database. We use the user credentials to authenticate the user.
A user role is an umbrella term to categorize a certain number of users. An authenticated user, an admin, a moderator are all user roles. Instead of giving permissions to each individual user, we simply categorize them by assigning a role to them and manage the permissions of the role.
A permission is used to limit the access of a user to an endpoint. Every method under a module should have a permission.
routing.json
We define the routes in the routing.json file under a module directory. An example will be:
{
"routes": [
{
"name": "List system variables",
"path": "/system/list_system_variables",
"method": "GET",
"actor": "modules\\system\\system",
"handler": "list_system_variables",
"permissions": [
{
"type": "standart",
"name": "access site"
},
{
"type": "custom",
"actor": "modules\\system\\system",
"handler": "list_system_variables_permissions"
}
]
}
]
}
We defined the endpoint path, REST method (GET, POST, PUT, DELETE), which module is responsible to handle the request and handler as the method of this module. Permissions are also defined in this file. There are two types of permissions, one is the standard permission which will simply check the permissions table in the database and see if the user has that permission or not, the other type is the custom permission which a method should decide after running a piece of code under the handler. If this method returns true, permissions will pass, fail on false.