trOnGAtE

Custom API Endpoints
Throughout this chapter, everything we've been doing has involved using Trongate's built-in API endpoints - all of which invoke code that's inside Api.php, which is inside the engine folder. Even with before hooks, after hooks and authorization rules in place, we're still ultimately falling back upon endpoints that have been pre-built into the framework.
However, there may be situations when you'd like to build your own API endpoints. That is, API endpoints that do not call upon or use any of Trongate's built-in endpoints.
The Most Basic Custom Endpoint That's Possible
Strictly speaking, an API endpoint is just a URL that has been designed to issue responses to HTTP requests. So, the PHP code below could produce an acceptable and perfectly valid API endpoint:
function hello() {
echo 'hello';
}
Even without declaring the hello() method on an api.json file and even without actively declaring an HTTP response status code, the method above would still behave like a valid endpoint. In fact, PHP would automatically issue an HTTP response status code of 200 for us, whenever a method like hello() is invoked.
Therefore, to be clear, we do not need to declare any of our custom endpoints inside any api.json file. We can simply write our own methods and forget about everything covered in this chapter! However, declaring a method - like the one shown above - inside an api.json file has two benefits:
- We can test our method inside the Trongate API Explorer
- We can easily apply advanced authorization rules to our endpoint
Declaring A Custom Endpoint
The process for declaring a custom API endpoint, within an api.json file, is fundamentally the same as before. The only key difference is the 'url_segments' property. For custom API endpoints, the first URL segment (as defined by 'url_segments') should represent the module to be loaded and the second segment should represent the method to be invoked.
For example, suppose you had a method called hello(), inside a 'members' module. Such a method could be declared inside an api.json file with the following syntax:
"Hello": {
"url_segments": "members/hello",
"request_type": "GET",
"description": "Say hello",
"authorization": "*"
}
Applying Security Rules
Trongate's token based API authorization system can be applied to a custom endpoint by adding the following line of code onto the start of a given method:
api_auth();
Let's Test This!
Let's create a method inside a controller file called hello(). We'll use precisely the same code as above, only this time, we'll add API authorization. This gives us:
​function hello() {
api_auth();
echo 'hello';
}​
Now, if you open your browser and navigate to your custom endpoint, you'll find that API authorization is now being enforced. As a matter of fact, if you don't have authorization rules declared - for your custom endpoint - then you'll see a warning on your screen, telling you why the endpoint has not been activated!

Practical Example
Let's assume that we have an app that contains a module named 'members'. On our Members.php controller file, we could have a method that loads information relating to the members' account records. In a real-world situation, this kind of information might be private and we may wish to refuse access to everyone except:
- users who have a role of 'admin'
- users who can be matched with the particular record being queried
To make this as simple as possible, let's start with a basic PHP method that attempts to read a hypothetical 'member code' from a URL and then fetch a record, from the database, where a record is found to match our code:
function account($member_code) {
$member_obj = $this->model->get_one_where('code', $member_code, 'members');
if ($member_obj == false) {
http_response_status(400); //bad request!
echo 'Invalid member code';
die();
} else {
http_response_code(200);
echo json_encode($member_obj);
}
}
As things stand, our method above would successfully fetch a record and return a JSON object, provided all required table columns and correlating data were in place. However, this API endpoint would be wide open! So, anyone who happened to have a valid 'member code' could access private information relating to member accounts.
To solve this, we could combine Role Based Authorization with User Owned Segment Authorization. Our goals here would be:
- to use Role Based Authorization to check if the end user has a role of 'admin'
- to use User Owned Segment authorization to check if the record being fetched belongs to the end user.
Our two required authorization tests could be applied to an API endpoint setting with the following code:
"authorization": {
"roles": ["admin"],
"userOwnedSegment": {
"column": code,
"segmentNum": 3
}
}
ADDING API AUTHORIZATION TO OUR CUSTOM ENDPOINT METHOD
To add API Authorization to our custom endpoint, we have to add 'api_auth()' onto the start of our account() method. This leaves us with a method that has the following PHP code:
​function account($member_code) {
api_auth();
​ $member_obj = $this->model->get_one_where('code', $member_code, 'members');
​ if ($member_obj == false) {
​ http_response_status(400); //bad request!
​ echo 'Invalid member code';
​ die();
​ } else {
​ http_response_code(200);
​ echo json_encode($member_obj);
​ }
​}
DECLARING OUR CUSTOM API ENDPOINT SETTINGS
The code for declaring our custom API endpoint setting could take the following form:
"Fetch Account": {
​ "url_segments": "members/account",
​ "request_type": "GET",
​ "description": "Fetch account information",​
"authorization": {
​ "roles": ["admin"],
​ "userOwnedSegment": {
"column": code,
​ "segmentNum": 3
​ }
}
}
HELP & SUPPORT
If you have a question or a comment relating to anything you've see here, please goto the Help Bar.