Ответ 1
Я получил значок Popular question
для этого вопроса, поэтому я чувствую это вовремя, когда я подробно расскажу, как я сделал свой REST-soluton.
Я посмотрел как на Laravel, Sympfony2, так и на Codeigniter для этого REST Api. У всех у них были некоторые элементы, которые мне нравились, а некоторые мне не нравились. Моя основная проблема заключалась в том, как сделать аутентификацию, потому что у меня был довольно сложный алгоритм, когда мои пользователи могут входить в систему с помощью access_token или access_tokens приложений, которые обслуживаются Google или Facebook. Я также уверен, что полностью контролирую свои рамки, и упомянутые выше структуры имеют некоторые элементы, которые я чувствовал ненужным и трудным для работы. Из-за этого я решил создать собственное REST-решение. Это не так сложно, как можно было бы ожидать, и это можно сделать несколькими способами. То, как я это делал, требует некоторых знаний о программировании ООП.
Okey, поэтому, начиная с создания базового класса, называемого REST. Этот класс заботится обо всем, что является общим для каждого звонка. Подобно аутентификации, разбор запрошенного пути к методу, проверка access_token
и т.д.
Одной из центральных вещей в этом классе является запрошенный путь и способ его перевода в метод. Я сделал это, вдохновленный Ларавелем. У меня есть массив с key
= > value
, где ключ - это URL-адрес, который должен соответствовать, и значение является фактическим методом вызова. Я также включил способ, которым Lavavel анализирует переменные в URL-адресе следующим образом:
'/user/(:id)' => 'user_id',
Это будет соответствовать любому /user/ [number]. Он также проверяет, какой тип запроса это, поэтому, если это простой метод get, он попытается вызвать get_user_id
. Все, что анализировалось с помощью (:id)
, было бы использовано в качестве аргумента при вызове этого метода (поэтому он фактически вызывает get_user_id($id)
).
После проверки подлинности вычисляется фактический вызов метода. Мне не нужны все методы (например, get_user_id
) в самом REST-классе, поэтому я разбил их на разных контроллерах, которые расширяют класс REST. Это делается путем просмотра запрашиваемого URL-адреса. Если это /user/(:id)
, script будет проверять, есть ли контроллер с именем userController.php
. Если он существует, проверьте, существует ли метод, который мы собираемся вызывать. Если это так, проверьте, соответствует ли количество аргументов тому, что у нас есть. Если все хорошо, выполните метод, если не вернете сообщение об ошибке. Структура и сообщения об ошибках очень важны при создании API.
В разных контроллерах я вызываю конструктор для REST-класса, чтобы получить аутентификацию, разбор URL-адреса и т.д. Трудная часть здесь заключается в том, что я не хотел этого делать:
$controller = new MyController();
$controller->printResponse();
В нижней части каждого контроллера. Поэтому я сделал небольшой взлом и script под названием run.php
, который делает это динамически для каждого класса контроллера. Прежде чем включить run.php
, я сохраню путь для контроллера, просто сделав $path = explode('/',__FILE__);
. Это используется в run-script. Run-script выглядит следующим образом:
// Splitting the file-name, removing the extension
$name = explode('.',$path[count($path)-1]);
// Uppercasing the first letter to be nice and OOP-ish
$classToCall = ucfirst($name[0]);
// Creating a new instance
$controller = new $classToCall();
// Logging
$controller->doLog();
// Printing the final response
$controller->printResponse();
Я нашел, что это идеальное решение для того, как я хотел создать свой API. Я могу легко добавить новые методы, предоставив его в массиве, который анализирует URL-адреса методам, и я могу добавить новые методы в прекрасно разбитые контроллеры для максимальной чистоты.
Некоторые люди могут подумать, что это слишком много работы, но на самом деле мне потребовалось всего несколько часов, чтобы запустить его и запустить. Я бы назвал это очень динамичным, так как я могу просто добавить новые контроллеры, и система распознает их, если они являются действительными url-образцами.
Несколько дружеских советов.
Если вы решите пойти с чем-то похожим на это решение, это могут быть некоторые полезные советы. В каждом контроллере сделайте что-то вроде этого:
public function __construct() {
// Loading the class-name, setting it in the REST-class, so we can check if it holds the method being called
$this->className = get_class($this);
// Calling RESTs constructor
parent::__construct();
}
Нам нужно будет сохранить класс, в котором мы сейчас работаем. Это будет UserController
или что-то в этом роде.
В REST-классе я могу использовать эту переменную, чтобы проверить, существует ли в этом контроллере фактический метод вызова. Я сделал это следующим образом:
// Checking if the method exists
if (method_exists($this->className,$method_name)) {
// Check to see if we have the required number of arguments represented
$ReflectionClass = new ReflectionClass($this->className);
if ($ReflectionClass->getMethod($method_name)->getNumberOfParameters() == count($this->methodUrl['args'])) {
$this->response['response'] = call_user_func_array(array($this, $method_name), $this->methodUrl['args']);
Надеюсь, это может заставить вас всех пойти.
Счастливый codin '