Created
January 3, 2017 02:17
-
-
Save naosim/848b4c5479dc875540f66c49c5437e8e to your computer and use it in GitHub Desktop.
簡易なAPIライブラリ
This file contains hidden or 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 | |
namespace com\naosim\apilib; | |
use \Exception; | |
/** | |
* APIライブラリ | |
* 前提: | |
* - 1ファイル, 1APIで作成する | |
* - レスポンスはJSONとする (callbackがあればjsonp) | |
*/ | |
class ApiUtil { | |
function send($map) { | |
$json = json_encode($map); | |
// JSONの場合 | |
if(!isset($_GET['callback'])){ | |
header("Content-type: application/json"); | |
echo $json; | |
return; | |
} | |
// JSONPの場合 | |
header("Content-type: application/javascript"); | |
$callback=$_GET['callback']; | |
print <<<END | |
$callback($json); | |
END; | |
} | |
/** | |
* Exception Handling | |
*/ | |
public function onException(Exception $e) { | |
$this->send($this->failedMap($e->getMessage())); | |
} | |
/** | |
* handle get call | |
* if $action throw exception, then return error response | |
* @var function $action | |
*/ | |
function get(Api $api) { | |
try { | |
$result = $api->invoke($this, new Request($_GET)); | |
if($result == null) return; | |
$this->send($result); | |
} catch(Exception $e) { | |
$this->onException($e); | |
} | |
} | |
/** | |
* handle post call | |
* if $action throw exception, then return error response | |
* @var function $action | |
*/ | |
function post(Api $api) { | |
try { | |
$result = $api->invoke($this, new Request($_POST)); | |
if($result == null) return; | |
$this->send($result); | |
} catch(Exception $e) { | |
$this->onException($e); | |
} | |
} | |
function successMap(array $map) { | |
return [ | |
'status' => 'success' , | |
'data' => $map | |
]; | |
} | |
function failedMap(string $message) { | |
return [ | |
'status' => 'failed', | |
'message' => $message | |
]; | |
} | |
function getParamOrThrow(array $ary, string $key, Exception $exception) { | |
if(isset($ary[$key])) { | |
return $ary[$key]; | |
} else { | |
throw $exception; | |
} | |
} | |
/** | |
* get value or throw | |
* @throws Exception | |
*/ | |
function required(array $ary, string $key) { | |
return $this->getParamOrThrow($ary, $key, new Exception('required ' . $key)); | |
} | |
/** | |
* get value or default | |
*/ | |
function option(array $ary, string $key, $default) { | |
return $ary[$key] ?? $default; | |
} | |
/** | |
* call getValue() in value object. | |
*/ | |
function ValuePicker($targetObject) { | |
/** | |
* if value is hoge, then called like $targetObject->getHoge()->getValue(). | |
* if value is isFoo, then called like $targetObject->getIsHoge()->getValue(). | |
* @var $targetObject value name | |
*/ | |
return function ($key) use($targetObject) { | |
// create getter method | |
$methodName = 'get' . strtoupper(substr($key, 0, 1)) . substr($key, 1); | |
// starts with 'is' & upper case after 'is' | |
if(substr($key, 0, 2) === 'is' && ctype_upper(substr($key, 2, 1))) { | |
$methodName = $key; | |
} | |
return $targetObject->$methodName()->getValue(); | |
}; | |
} | |
}// end API | |
function GET(Api $api) { | |
(new ApiUtil())->get($api); | |
} | |
function POST(Api $api) { | |
(new ApiUtil())->post($api); | |
} | |
class Request { | |
private $params; | |
public function __construct(array $params) { | |
$this->params = $params; | |
} | |
public function getParams(): array { | |
return $this->params; | |
} | |
public function option($key, $default) { | |
return $this->params[$key] ?? $default; | |
} | |
public function required($key) { | |
return $this->orThrow($key, new Exception('required ' . $key)); | |
} | |
public function orThrow(string $key, Exception $exception) { | |
if(isset($this->params[$key])) { | |
return $this->params[$key]; | |
} else { | |
throw $exception; | |
} | |
} | |
} | |
interface Api { | |
function invoke(ApiUtil $apiUtil, Request $request): array; | |
} |
Api#invoke()の戻り値がそのままjsonで返る。
例外が発生した場合は、上記の失敗例と同じフォーマットで返る。
個人的にはerrorとdataが排他の関係になるとイイと思う。
例外時の返却をカスタマイズしたい場合は、ApiUtilを継承してonExceptionをオーバライドすればok。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ミニマムなサンプル
required_onceは適当に追加してください。
動作結果
成功
URL: http://localhost:8080/sample.php?name=mike&age=20
jsonpの場合
URL: http://localhost:8080/sample.php?name=mike&age=20&callback=foo
失敗 (ageが足りない)
URL: http://localhost:8080/sample.php?name=mike