Major improvements and changes
This commit is contained in:
parent
38a5a1336b
commit
1c844f4f78
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024 CodeSpace.cz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
111
api.php
111
api.php
|
@ -1,111 +0,0 @@
|
|||
<?php
|
||||
|
||||
class API {
|
||||
|
||||
public $endpoints;
|
||||
public $datatypes;
|
||||
public $data;
|
||||
public $path;
|
||||
|
||||
function __construct() {
|
||||
|
||||
$this->endpoints = [];
|
||||
$this->datatypes = [
|
||||
"str" => function($input) {
|
||||
return $input;
|
||||
},
|
||||
"int" => function($input) {
|
||||
if($input === null || $input === "") return null;
|
||||
return intval($input);
|
||||
},
|
||||
"float" => function($input) {
|
||||
if($input === null) return null;
|
||||
return floatval($input);
|
||||
},
|
||||
"bool" => function($input) {
|
||||
if($input == null) return null;
|
||||
return !in_array($input, ["0", "false"]);
|
||||
}
|
||||
];
|
||||
$this->data = array_merge($_GET, $_POST);
|
||||
$this->path = [];
|
||||
if(isset($this->data["action"])) {
|
||||
$this->path = explode("/", $this->data["action"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function parse_params($endpoint, $data) {
|
||||
if(!isset($endpoint["params"])) return $data;
|
||||
$result = [];
|
||||
foreach ($endpoint["params"] as $param) {
|
||||
|
||||
$split1 = explode(":", $param);
|
||||
$name = trim($split1[0]);
|
||||
$required = true;
|
||||
if(substr($name, -1) == "?") {
|
||||
$required = false;
|
||||
$name = substr($name, 0, -1);
|
||||
}
|
||||
$split2 = explode("=", trim($split1[1]));
|
||||
$datatype = trim(array_shift($split2));
|
||||
$default = count($split2) ? trim(implode("=", $split2)) : null;
|
||||
|
||||
$result[$name] = isset($data[$name]) ? $data[$name] : null;
|
||||
|
||||
if($result[$name] === null && isset($default) && $default !== "") $result[$name] = $default;
|
||||
$result[$name] = $this->datatypes[$datatype]($result[$name]);
|
||||
if($result[$name] === null && $required) return false;
|
||||
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function add($endpoint) {
|
||||
array_push($this->endpoints, $endpoint);
|
||||
}
|
||||
|
||||
function is($paths) {
|
||||
if(!is_array($paths)) $paths = [$paths];
|
||||
$current = implode("/", $this->path);
|
||||
foreach($paths as $path) {
|
||||
if(str_starts_with($current, $path)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function execute($data) {
|
||||
if(!isset($data["action"])) return ["error" => "invalid_endpoint"];
|
||||
foreach($this->endpoints as $endpoint) {
|
||||
if($endpoint["action"] == $data["action"]) {
|
||||
|
||||
$params = $this->parse_params($endpoint, $data);
|
||||
if($params) {
|
||||
try {
|
||||
$res = $endpoint["function"]($params);
|
||||
} catch(exception $e) {
|
||||
$res = ["error" => "internal", "detailed_error" => $e->getMessage()];
|
||||
}
|
||||
} else {
|
||||
$res = ["error" => "missing_data"];
|
||||
}
|
||||
|
||||
if(!is_array($res)) {
|
||||
if($res == true) $res = ["success" => true];
|
||||
if($res == false) $res = ["success" => false];
|
||||
}
|
||||
if(!is_array($res)) $res = [];
|
||||
|
||||
}
|
||||
}
|
||||
if(!isset($res)) $res = ["error" => "invalid_endpoint"];
|
||||
return $res;
|
||||
}
|
||||
|
||||
function run() {
|
||||
header("Content-Type: application/json");
|
||||
$response = $this->execute($this->data);
|
||||
die(json_encode($response));
|
||||
}
|
||||
|
||||
}
|
10
composer.json
Normal file
10
composer.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "codespace/api",
|
||||
"description": "Simple framework for creating APIs",
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"CodeSpace\\API\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
72
src/API.php
Normal file
72
src/API.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php namespace CodeSpace\API;
|
||||
|
||||
class API {
|
||||
|
||||
public array $datatypes;
|
||||
public array $map;
|
||||
|
||||
function __construct() {
|
||||
|
||||
$this->map = [];
|
||||
|
||||
}
|
||||
|
||||
public function convertResponse(mixed $res): array {
|
||||
if (is_bool($res)) {
|
||||
$res = ["success" => $res];
|
||||
}
|
||||
if (!is_array($res)) $res = [];
|
||||
if (array_key_exists("error", $res)) $res["success"] = false;
|
||||
return $res;
|
||||
}
|
||||
|
||||
function add(array $path, string $class) {
|
||||
$root = &$this->map;
|
||||
foreach ($path as $part) {
|
||||
if (!array_key_exists($part, $root)) {
|
||||
$root[$part] = [];
|
||||
}
|
||||
$root = &$root[$part];
|
||||
}
|
||||
$root["__class"] = $class;
|
||||
}
|
||||
|
||||
function getClass(array $path): string | null {
|
||||
$root = &$this->map;
|
||||
foreach ($path as $part) {
|
||||
if (!array_key_exists($part, $root)) return null;
|
||||
$root = &$root[$part];
|
||||
}
|
||||
return array_key_exists("__class", $root) ? $root["__class"] : null;
|
||||
}
|
||||
|
||||
function getEndpoint(string $class): Endpoint {
|
||||
return new $class($this);
|
||||
}
|
||||
|
||||
function getAction(): array {
|
||||
$action = null;
|
||||
if (array_key_exists("action", $_REQUEST)) {
|
||||
$action = $_REQUEST["action"];
|
||||
}
|
||||
if ($action == null) {
|
||||
$action = substr(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), 1);
|
||||
}
|
||||
return explode("/", $action);
|
||||
}
|
||||
|
||||
function execute(array $path, array $data) {
|
||||
$class = $this->getClass($path);
|
||||
if ($class == null) return ["error" => "invalid_endpoint"];
|
||||
$endpoint = $this->getEndpoint($class);
|
||||
return $endpoint->get($data);
|
||||
}
|
||||
|
||||
function run() {
|
||||
header("Content-Type: application/json");
|
||||
$response = $this->execute($this->getAction(), $_REQUEST);
|
||||
echo json_encode($this->convertResponse($response));
|
||||
exit();
|
||||
}
|
||||
|
||||
}
|
31
src/Endpoint.php
Normal file
31
src/Endpoint.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php namespace CodeSpace\API;
|
||||
|
||||
use Exception;
|
||||
|
||||
abstract class Endpoint {
|
||||
|
||||
private API $api;
|
||||
|
||||
protected ?array $params = null;
|
||||
|
||||
public function __construct(API $api) {
|
||||
$this->api = $api;
|
||||
}
|
||||
|
||||
public function get(array $data): array {
|
||||
$params = Parser::parse($data, $this->params);
|
||||
if ($params !== null) {
|
||||
try {
|
||||
$res = $this->run($params);
|
||||
} catch(Exception $e) {
|
||||
$res = ["error" => "internal", "detailed_error" => $e->getMessage()];
|
||||
}
|
||||
} else {
|
||||
$res = ["error" => "missing_data"];
|
||||
}
|
||||
return $this->api->convertResponse($res);
|
||||
}
|
||||
|
||||
abstract public function run(array $params);
|
||||
|
||||
}
|
54
src/Parser.php
Normal file
54
src/Parser.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php namespace CodeSpace\API;
|
||||
|
||||
class Parser {
|
||||
|
||||
private static ?array $datatypes = null;
|
||||
|
||||
private static function init() {
|
||||
self::$datatypes = [
|
||||
"str" => function ($input) {
|
||||
return $input;
|
||||
},
|
||||
"int" => function ($input) {
|
||||
if ($input === null || $input === "") return null;
|
||||
return intval($input);
|
||||
},
|
||||
"float" => function ($input) {
|
||||
if ($input === null) return null;
|
||||
return floatval($input);
|
||||
},
|
||||
"bool" => function ($input) {
|
||||
if ($input == null) return null;
|
||||
return !in_array($input, ["0", "false"]);
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
public static function parse(array $data, ?array $params): ?array {
|
||||
if ($params == null) return $data;
|
||||
if (self::$datatypes == null) self::init();
|
||||
$result = [];
|
||||
foreach ($params as $param) {
|
||||
|
||||
$split1 = explode(":", $param);
|
||||
$name = trim($split1[0]);
|
||||
$required = true;
|
||||
if (substr($name, -1) == "?") {
|
||||
$required = false;
|
||||
$name = substr($name, 0, -1);
|
||||
}
|
||||
$split2 = explode("=", trim($split1[1]));
|
||||
$datatype = trim(array_shift($split2));
|
||||
$default = count($split2) ? trim(implode("=", $split2)) : null;
|
||||
|
||||
$result[$name] = isset($data[$name]) ? $data[$name] : null;
|
||||
|
||||
if ($result[$name] === null && isset($default) && $default !== "") $result[$name] = $default;
|
||||
$result[$name] = self::$datatypes[$datatype]($result[$name]);
|
||||
if ($result[$name] === null && $required) return null;
|
||||
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue