I have just written an API framework which I am hoping to implement into one of my large sites very soon. However, before I do so, I want to be sure that the script is well written and there are no obvious mistakes that I have missed.
As with most projects, the key here is automation and speed... I have tried to automate as much as possible whilst also keeping expensive code to a minimum.
These are a few sample requests that one could fire at this API:
// Return the logged in users details
http://api.example.net/user/
// Return the registered companies for the logged in user
http://api.example.net/user/companies/
Where user is the $object
on both and 'default' is the $request
on the first and 'companies' is the $request
on the second...
The data is then retrieved based on the $request
on the $object
... Make sense? :-) I hope so, here is my code:
<?php
// +------------------------------------------------------------------------+
// | api.php |
// +------------------------------------------------------------------------+
// | Copyright (c) Example Ltd 2012. All rights reserved. |
// | Version 1.0 |
// | Last modified 14/05/2013 |
// | Email [email protected] |
// | Web https://api.example.net |
// +------------------------------------------------------------------------+
/*
* Example API
*
* @version 1.0
* @author Ben Carey <[email protected]>
* @copyright Example Ltd
*
*/
// Guidelines for creating and adding a working method
// 1. All functions must have $parameters=array() as their only parameter
// 2. All must return some sort of data
// 3. Set the $example->json_constants if you need to specify anything about the JSON output
// 4. Any errors place into $example->error (string) and return
// Once the method has been created, you can proceed to adding it to the API
// 1. Work out what address you want e.g. api.example.net/user/companies
// -> This example will translate to the domain api.example.net/api.php?object=user&request=companies
// 2. If the object has a corresponding class and the class does not already exist in the defined list then add it
// 3. If the object does not have a corresponding class, it is an alias so add it (if not already there), to the alias array
// and map it to the correct class
// 4. Now you need to map the request to the method. If there is no request set (e.g. /user instead of /user/companies) then the request
// is treated as 'default'. You can then specify in the $api_methods array $object -> $request -> $method
// Define the allowed domains,
// this will prevent other sites from being able to
// access the API via AJAX
$allowed_domains = array('http://beta.example.net','https://beta.example.net');
// Test if the domain is allowed to connect
if(isset($_SERVER['HTTP_ORIGIN'])&&in_array($_SERVER['HTTP_ORIGIN'],$allowed_domains)){
// Allow access to the current domain
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
}
// Include the site configuration
include('C:\Inetpub\vhosts\example.net\subdomains\beta\httpdocs\_snippets\_system\config.php');
// Define the Example Classes
// All of these paths link to the class initiation file,
// in other words, by including them it will include all
// necessary files and create an instance of the class
$classes = array(
'authorized' => $_PATHS['EXAMPLE'].'\_snippets\_classes\class.authorized.php',
'documents' => $_PATHS['EXAMPLE'].'\_snippets\_classes\class.documents.php',
'reports' => $_PATHS['EXAMPLE'].'\_snippets\_classes\class.reports.php',
'settings' => $_PATHS['EXAMPLE'].'\_snippets\_classes\class.settings.php',
);
// Create a map of aliases to classes
// This will allow objects that do not have a matching class but
// but do have a corresponding method in another class
// specified here
$class_aliases = array(
'user' => 'authorized',
'company' => 'authorized'
);
// Gather the relevant methods for the supplied
// request method
switch($_SERVER['REQUEST_METHOD']){
case 'GET':
// Create an array that maps the objects to the
// relevant request and method within the class
$api_methods = array(
'authorized' => array(
'default' => 'get_authorized'
),
'documents' => array(
'sessions' => 'get_active_sessions'
),
'masterfiles' => array(
'items' => 'get_master_file_items',
'properties' => 'get_master_file_properties',
'reference' => 'get_master_file_reference'
),
'user' => array(
'companies' => 'get_registered_companies_for_user'
)
);
// Set the parameters to be passed to the corresponding
// method, this is set depending on the page request method
$parameters = $_GET;
break;
case 'POST':
// Create an array that maps the objects to the
// relevant request and method within the class
$api_methods = array(
'settings' => array(
'user' => 'update_user'
)
);
// Set the parameters to be passed to the corresponding
// method, this is set depending on the page request method
$parameters = $_POST;
break;
}
// The object and request are always supplied via GET
$object = strtolower($_GET['object']);
$request = strtolower($_GET['request']);
// Set the class to include based on the object supplied
if(isset($classes[$object])){
$class = $classes[$object];
}elseif(isset($class_aliases[$object])){
$class = $classes[$class_aliases[$object]];
}else{
$data = array('error' => 'Specified object does not exist');
}
// Set the method to execute based on the request supplied
if(!empty($request)&&isset($api_methods[$object][$request])){
$method = $api_methods[$object][$request];
}elseif(isset($api_methods[$object]['default'])){
$method = $api_methods[$object]['default'];
}else{
$data = array('error' => 'Specified request does not exist');
}
// Only proceed if there are no errors
if(empty($data)){
// If the request is via AJAX then prevent all redirects
if(isset($_SERVER['HTTP_X_REQUESTED_WITH'])&&strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])=='xmlhttprequest'){
$prevent_redirect = true;
}
// Include the relevant class
include($class);
// Remove the request and method values from the parameters
unset($parameters['object'],$parameters['request']);
// Execute the relevant method
$data = call_user_func(array($example,$method));
// If there was an error then replace the data variable
$data = !empty($example->error) ? array('error' => $example->error) : $data;
}
echo json_encode($data,$example->json_constants);
?>