Ho avuto il badge Popular question
per questa domanda, quindi penso che sia giunto il momento di elaborare come ho fatto il mio soluton REST.
Ho guardato sia Laravel, Sympfony2 e Codeigniter per questo REST Api. Avevano tutti alcuni elementi che mi piacevano e altri non mi piacevano. La mia preoccupazione principale era come eseguire l'autenticazione perché avevo un algoritmo piuttosto complesso in cui i miei utenti possono accedere con access_token o access_tokens offerti da Google o Facebook. Mi permetto anche di essere in completo controllo della mia struttura e le strutture sopra menzionate avevano alcuni elementi che mi sembravano inutili e difficili da risolvere. Per questo motivo ho deciso di creare la mia soluzione REST. Non è così difficile come ci si potrebbe aspettare, e può essere fatto in diversi modi. Il modo in cui l'ho fatto richiede alcune conoscenze sulla programmazione OOP.
Okey, quindi iniziare una classe base chiamata REST. Questa classe si prende cura di tutte le cose che sono in comune per ogni chiamata. Come l'autenticazione, analizzando il percorso richiesto per un metodo, controllando access_token
ecc.
Una delle cose centrali in questa classe è il percorso richiesto e come questo viene tradotto in un metodo. L'ho fatto ispirandomi a Laravel. Ho un array con key
=>value
dove la chiave è l'url che deve corrispondere e il valore è il metodo effettivo da chiamare. Ho incluso anche il modo Lavavel analizza le variabili nell'URL in questo modo:
'/user/(:id)' => 'user_id',
Questo sarebbe adattarsi a qualsiasi/user/[numero]. Controlla anche che tipo di richiesta è, quindi se questo è un semplice metodo get proverebbe a chiamare get_user_id
. Qualsiasi cosa analizzata con (:id)
verrebbe utilizzata come argomento quando si chiama quel metodo (quindi in realtà sta chiamando get_user_id($id)
).
Dopo l'autenticazione viene valutata la chiamata al metodo effettivo. Non volevo tutti i metodi (come get_user_id
) nella classe REST stessa, quindi li ho rotti in diversi controller che estendono la classe REST. Questo viene fatto osservando l'url richiesto. Se è /user/(:id)
lo script controllerà se c'è un controller chiamato userController.php
. Se esiste, controlla se esiste il metodo che chiameremo. Se lo fa, controlla se il numero di argomenti corrisponde a quello che abbiamo. Se tutto è buono, eseguire il metodo, se non restituire un messaggio di errore. Struttura e messaggi di errore sono molto importanti quando si crea un'API come questa.
Nei diversi controller, chiamo il costruttore per la classe REST per ottenere l'autenticazione, l'analisi dell'URL, ecc. Risolto. La parte difficile qui è che non volevo fare:
$controller = new MyController();
$controller->printResponse();
Nella parte inferiore di ogni controller. Così ho creato un piccolo trucco e uno script chiamato run.php
che lo esegue dinamicamente per ogni classe di controller. Prima di includere lo run.php
, salvo il percorso del controller, eseguendo semplicemente $path = explode('/',__FILE__);
. Questo è usato nello script di esecuzione. La corsa-script simile a questa:
// 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();
ho trovato questo per essere una soluzione perfetta per come ho voluto costruire la mia API. Posso facilmente aggiungere nuovi metodi fornendoli nell'array che analizza gli url ai metodi, e posso aggiungere nuovi metodi nei controller ben divisi per la massima pulizia.
Alcune persone potrebbero pensare che questo è troppo lavoro, ma in realtà mi ci sono voluti solo poche ore per farlo funzionare. Chiamerei anche questo altamente dinamico in quanto posso solo aggiungere nuovi controller e il sistema li riconoscerà se sono url-pattern validi.
Alcuni consigli amichevoli.
Se si decide di andare con qualcosa che assomiglia a questa soluzione, questi possono essere alcuni buoni consigli. In ogni controller, fare qualcosa di simile:
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();
}
Avremo bisogno di memorizzare quale classe stiamo lavorando da. Questo sarebbe UserController
o qualcosa del genere.
Nella classe REST posso quindi utilizzare questa variabile per verificare se il metodo effettivo di chiamata in uso esiste in questo controller. L'ho fatto in questo modo:
// 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']);
Spero che possa farti andare tutti.
Codin Felice
Ecco un buon articolo: [REST API con Symfony2: The Right Way] (http://williamdurand.fr/2012/08/02/rest-apis-with-symfony2 -the-right-way /) – j0k
@ j0k: fantastico, guarderò. forse la soluzione potrebbe essere così facile. Grazie. – OptimusCrime
come va d'accordo? –