PHP klein config for a basic API routing
Last active
February 9, 2017 00:32
-
-
Save gubi/5de08a2fe256d4929ba3eeafc344a84a to your computer and use it in GitHub Desktop.
Basic API routing with klein. For HTTP Status Codes see https://github.com/gubi/HTTP-Error-Codes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "<OWNER>/<PROJECT>", | |
"description": "The API service for the <PROJECT>", | |
"authors": [ | |
{ | |
"name": "Alessandro Gubitosi", | |
"email": "[email protected]" | |
} | |
], | |
"minimum-stability": "dev", | |
"require": { | |
"klein/klein": "^2.1", | |
"misd/linkify": "^1.1" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
header("Content-type: text/plain; charset=utf-8"); | |
require_once("vendor/autoload.php"); | |
/** | |
* Class Routing | |
* | |
* @author Alessandro Gubitosi <[email protected]> | |
* @version 1.0.0 | |
* @uses yaml_parse_file http://php.net/manual/en/book.yaml.php | |
*/ | |
class Routing { | |
static $klein; | |
// The base url prefix | |
static $prefix = "/path/api"; | |
// The API version | |
static $version = "v1"; | |
static $mapped_url = ["menu", "posts"]; | |
// The response | |
static $j = []; | |
/** | |
* The main method | |
*/ | |
public static function run() { | |
self::$klein = new \Klein\Klein(); | |
self::$j["id"] = ""; | |
self::$j["date"] = self::getDate(); | |
self::$j["status"] = new stdClass(); | |
self::$j["errors"] = new stdClass(); | |
self::$j["response"] = new stdClass(); | |
self::$j["request"] = new stdClass(); | |
self::showError(200); | |
self::route_checkVersion(); | |
self::route_getGeneralRoute(); | |
self::route_getMenu(); | |
self::route_getPosts(); | |
self::$klein->dispatch(); | |
} | |
/** | |
* Load current error data | |
* and generate the errors object data in the response object | |
* @see errors.yml | |
* @uses yaml_parse_file | |
* @link http://php.net/manual/en/book.yaml.php | |
* | |
* @param int $error The error code to load | |
* @return object The error data | |
*/ | |
private static function showError($error, $request = "") { | |
$errors = json_decode(json_encode(yaml_parse_file("errors.yml"))); | |
if(is_object($errors->$error)) { | |
self::$j = array_merge(self::$j, (array)$errors->$error); | |
} | |
self::$j["id"] = self::generateID($request); | |
self::$j["request"] = self::generateRequest($request); | |
return self::$j; | |
} | |
/** | |
* Extract current date in multiple formats | |
* @return object The generated date object | |
*/ | |
private static function getDate() { | |
$d = new stdClass(); | |
$d->UTC = gmdate("Y-m-d\TH:i:s\Z"); | |
$d->readable = date("l, F j, Y"); | |
$date = new DateTime(); | |
$d->timestamp = $date->getTimestamp(); | |
return $d; | |
} | |
/** | |
* Generate an ID from the request | |
* @param string $request The GET request | |
* @return string The generated data | |
*/ | |
private static function generateID($request) { | |
return sha1($request); | |
} | |
/** | |
* Generate a request summary object from the request | |
* @param string $request The GET request | |
* @return object The generated data | |
*/ | |
private static function generateRequest($request) { | |
$req = new stdClass(); | |
$req->hash = md5($request); | |
$req->length = strlen($request); | |
$req->text = $request; | |
return $req; | |
} | |
/* ------------------------------------------------------------------------- | |
ROUTING | |
------------------------------------------------------------------------- */ | |
/** | |
* If not in the "$version" path redirect to the correct url | |
*/ | |
public static function route_checkVersion() { | |
$klein = self::$klein; | |
/** | |
* If not in the "$version" path return an error | |
*/ | |
$klein->respond("GET", "!@^/" . self::$version . "/", function($request, $response) use($klein) { | |
$right_url = preg_replace('/[^a-zA-Z0-9\/]+/', "", str_replace(self::$prefix, "", self::$version . $request->uri())); | |
$info = explode("/", trim($request->uri(), "/")); | |
if("/" . $info[0] . "/" . $info[1] == self::$prefix && (!isset($info[2]) || isset($info[2]) && $info[2] !== self::$version)) { | |
// Redirect to correct url | |
$klein->response()->redirect(self::$prefix . "/" . $right_url); | |
} | |
}); | |
} | |
/** | |
* Intercept general routes | |
*/ | |
public static function route_getGeneralRoute() { | |
$klein = self::$klein; | |
$klein->with(self::$prefix . "/" . self::$version, function() use ($klein) { | |
$klein->respond("GET", "/?", function($request, $response) { | |
return $response->json(self::showError(411)); | |
}); | |
$klein->respond("GET", "/[*:action]", function($request, $response) use($klein) { | |
$dirname = pathinfo($request->action)["dirname"]; | |
$basename = pathinfo($request->action)["basename"]; | |
$filename = pathinfo($request->action)["filename"]; | |
$root = ($dirname == ".") ? $basename : $dirname; | |
if(strlen(trim(preg_replace('/[^a-zA-Z0-9\/]+/', "", $request->action))) > 0) { | |
// Handle non-mapped requests | |
if(in_array($root, self::$mapped_url) === false) { | |
return $response->json(self::showError(400, $request->action)); | |
} | |
} else { | |
// $right_url = preg_replace('/[^a-zA-Z0-9\/]+/', "", $request->uri()); | |
// $klein->response()->redirect($right_url); | |
} | |
}); | |
}); | |
} | |
/** | |
* Get the menu | |
* @uses yaml_parse_file | |
* @link http://php.net/manual/en/book.yaml.php | |
*/ | |
public static function route_getMenu() { | |
$klein = self::$klein; | |
$klein->with(self::$prefix . "/" . self::$version, function() use ($klein) { | |
$klein->with("/menu", function() use($klein) { | |
$klein->respond("GET", "/?", function($request, $response) { | |
// Parse YAML file | |
$menu = json_decode(json_encode(yaml_parse_file(YML_DIR . "menu.yml"))); | |
self::$j["response"]->id = 1; | |
self::$j["response"]->type = "menu"; | |
self::$j["response"]->data = $menu; | |
self::$j["request"] = self::generateRequest("/menu"); | |
return $response->json(self::$j); | |
}); | |
$klein->respond("GET", "/[:action]", function($request, $response, $service) use($klein) { | |
$klein->response()->redirect("./"); | |
}); | |
}); | |
}); | |
} | |
/** | |
* Get posts | |
*/ | |
public static function route_getPosts() { | |
$klein = self::$klein; | |
$klein->with(self::$prefix . "/" . self::$version, function() use ($klein) { | |
$klein->with("/posts", function() use($klein) { | |
/** | |
* All posts | |
*/ | |
$klein->respond("GET", "/?", function($request, $response) { | |
// return "select * from `table`"; | |
self::$j["response"]->id = "*"; | |
self::$j["response"]->type = "posts"; | |
self::$j["response"]->data = ""; // Database query response | |
return $response->json(self::$j); | |
}); | |
/** | |
* Single post | |
*/ | |
$klein->respond("GET", "/[:id]", function($request, $response, $service) use($klein) { | |
$klein->onError(function($klein, $err_msg) { | |
$klein->response()->redirect("./" . preg_replace('/[^0-9]+/', "", $klein->request()->id)); | |
}); | |
$service->validateParam("id", "Please enter a valid id")->isChars("0-9"); | |
// return "select * from `table` where `id` = '" . $request->id . "'"; | |
$query = ""; // Database query response | |
if(!is_null($query)) { | |
self::$j["response"]->id = $request->id; | |
self::$j["response"]->type = "posts"; | |
self::$j["response"]->data = $query; | |
header("Content-type: application/json"); | |
return json_encode(self::$j, JSON_NUMERIC_CHECK); | |
} else { | |
return $response->json(self::showError(404)); | |
} | |
}); | |
}); | |
}); | |
} | |
} | |
Routing::run(); | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment