Descrizione del servizio REST in modo agnostico Hypermedia?

0

Come faccio a implementare la descrizione del servizio REST in modo tipo di contenuto agnostico ?

Sfondo

Sto sviluppando un'API RESTful per l'applicazione Web. Ora questa app è in qualche modo diversa da una soluzione standard di run-of-mills. Questa app utilizza un SIP B2BUA (asterisco), PHP + Mysql su Apache & NodeJS.

È una soluzione per call center che utilizza l'asterisco per gestire le chiamate VoIP e uno stack LAMP per l'interfaccia utente.

Architettura

REST richiede che l'applicazione sia senza stato. Tuttavia, a causa della natura stessa di SIP, non può essere al 100% senza stato. In questo modo sto utilizzando NodeJS in determinati punti per mantenere attiva la comunicazione in tempo reale.

Ora, c'è una API REST per tutto questo. È progettato in un modo abbastanza semplice. Hai risorse come utente , chiamata , campagna ecc. E un utente può avviare Verbi HTTP su queste risorse.

Le domande

Ho organizzato l'architettura seguendo il modello MVC. La cosa più importante che ho fatto è applicare Docblocks nel Modello . Quello che segue è un esempio di una classe del genere:

abstract class BaseUserInterface implements Interfaces\UserInterface {
protected $usrType = null;


/**
 * This is the constructor
 */  
public function __construct(Interfaces\User $usrObj){
    $this->usrType = ($usrObj instanceof \Model\Agent) ? 'agent':$this->usrType;
    $this->usrType = ($usrObj instanceof \Model\Admin) ? 'admin':$this->usrType;
    if($this->usrType === null){
        throw new \Framework\APIException(__CLASS__." : Insane Type of User Passed while initiating Interface", 500);
    }

    //Force docblocks
    $methodList = $this->listMethods();
    foreach($methodList as $method){
        $docblock = $this->describe($method);
        if(!$docblock){
            throw new \Framework\APIException(__CLASS__." : Contract Violated - Method $method Lacks Documentation", 500);
        }
    }
} //End __construct


/**
 * This is the typeOfInterface
 */ 
public function typeOfInterface(){ //return whether this is admin or agent interface
    return $this->usrType;
} //End typeOfInterface


/**
 * This is the listMethods
 */ 
public function listMethods(){ //Allowed Methods
    return get_class_methods($this);
} //End listMethods


/**
 * This is the describe
 */ 
public function describe($methodName){
    $methodList = $this->listMethods();
    if(!in_array($methodName, $methodList)){
        throw new \Framework\APIException(__CLASS__." : Asked To Describe Insane Method - ".$methodName, 400);
    }
    $class = get_class($this);
    $reflector = new \ReflectionClass($class);
    $phpdoc = $reflector->getMethod($methodName)->getDocComment();
    if($phpdoc){
        return $this->docParse($phpdoc);
    }
    else {
        return false;
    }
} //End describe

/**
 * This is the DocParser
 */ 
protected function docParse($phpdoc){ 
    $phpdoc = new \phpDocumentor\Reflection\DocBlock($phpdoc);
            return $phpdoc->getShortDescription()."<br />";
} //End docParse

abstract public function logout();

Naturalmente, ho dato un'idea dei docblock e non dei docblock completi qui. Fondamentalmente, avrebbero la documentazione necessaria. Ora, tutte le classi nello spazio dei nomi Modello che estenderebbero questa classe dovrebbero utilizzare docblocks che rafforzano la documentazione.

Inoltre, ho una funzione Helper :: convert () che può convertire qualsiasi risultato tra XML e JSON a seconda della richiesta di accettazione dell'utente nell'intestazione HTTP .

Quindi, sono tutto pronto con quello.

Ciò di cui sono completamente confuso è: 1. Voglio che l'utente sia in grado di chiedere Describe() su available methods a un dato resource . Come posso implementarlo tramite le intestazioni HTTP?

  1. OPTIONS in HTTP mi dice di rispondere con allowed VERBS on ***this*** resource .

  2. Voglio avere un gateway comune per l'app. L'utente chiede /index.php. Rispondo con user, call, campaign e un breve messaggio che dice loro che possono usare GET su questi resources per saperne di più. Quindi su quelle risorse, voglio visualizzare available methods seguito da description of the selected method e così via e così via.

  3. Soprattutto, voglio rispondere nell'intestazione accettata dall'utente se supportata da me.

Come faccio a fare questo seguendo le convenzioni corrette? Inoltre, alcuni riferimenti alle RFC sarebbero molto apprezzati.

    
posta Christian M. Raymonds 20.10.2015 - 04:28
fonte

2 risposte

1

Non ho familiarità con tecnologie come SIP e VOIP, ma penso di poter dare risposte alle quattro domande che hai.

  1. I want the user to be able to ask for Describe() on available methods at a given resource. How do I implement that via HTTP headers?

In un'API RESTful, le risorse puntano l'una sull'altra usando i collegamenti. Mi concentrerò sul caso in cui la tua API restituisce XML o JSON (anziché HTML). Questi formati non hanno un modo standard per rappresentare i collegamenti, quindi devi scegliere uno standard o inventare il tuo. Ad ogni modo, penso che un link non dovrebbe solo specificare un URI, ma anche il metodo HTTP da utilizzare. Se è possibile utilizzare più metodi HTTP sullo stesso URI, è necessario un collegamento per ciascuno di questi metodi HTTP. Esempio:

{
    "id": "12345",
    "name": "John Brown",
    "update" : { "href" : "/persons/12345", "method" : "PATCH" },
    "delete" : { "href" : "/persons/12345", "method" : "DELETE" }
}

Ecco come puoi informare il cliente sui metodi disponibili.

  1. OPTIONS in HTTP tells me to respond with allowed VERBS on this resource.

Bene, ma le API RESTful che ho visto non usano OPTIONS. Utilizzano i collegamenti come unico mezzo per trasmettere i metodi HTTP consentiti ai loro clienti.

  1. I want to have a common gateway to the app. User asks for /index.php. I respond with user, call, campaign and a brief message telling them that they can use GET on these resources to know more.

Sì, puoi rispondere con un messaggio XML o JSON contenente collegamenti come descritto sopra. Esempio:

{
    "user" : { "href" : "/users/{userID}", "method" : "GET" },
    "call" : { "href" : "/calls/{callID}", "method" : "GET" },
    "campaign" : { "href" : "/campaign", "method" : "GET" }
}

Then upon those resources, I want to display available methods followed by description of the selected method and so on and so forth.

Sì, quando il client segue uno dei collegamenti, ottiene una rappresentazione JSON di quella risorsa, contenente collegamenti che specificano cosa può essere fatto con quella risorsa.

  1. Most importantly, I want to respond in the user's chosen accept-header if supported by me.

Sì, puoi controllare quell'intestazione e restituire una risposta nel formato appropriato.

Per ulteriori convenzioni REST proposte da me stesso, consulta JAREST .

    
risposta data 02.11.2015 - 20:53
fonte
1

I want the user to be able to ask for Describe() on available methods at a given resource. How do I implement that via HTTP headers?

Non lo fai.

REST funziona con un formato predeterminato per la comunicazione tra client e server. Ad esempio HTML, o PNG o MP4. Il client capisce l'HTML, il server capisce l'HTML (beh in alcuni casi, in altri il server è solo un negozio di documenti stupido)

Il client dice al server quali formati di dati comprende e il server risponde con il formato se può anche emettere questa risorsa. Il cliente non dovrebbe conoscere il formato dei dati utilizzato per rappresentare le risorse. Dovrebbe invece navigare nel formato dei dati per raggiungere la risorsa che desidera. Non dovrebbe capire il layout delle risorse.

Prendi HTML per esempio. Firefox non conosce il layout delle risorse sul sito di New York Time. Non sa cosa significa "Meteo di oggi", né sa cosa significhi "Titoli".

Firefox sa però cosa significa HTML. Quindi lascia la navigazione delle risorse all'utente.

Documenta il tuo formato di dati e poi lascia che il client (tramite un utente umano o tramite un crawler API) scopra le risorse nel tuo sistema.

E ricorda che REST è una macchina a stati. Puoi trovare una risorsa, cambiarne lo stato e reinserirla sul server per salvarla. Non dire al server di fare qualcosa con una risorsa (diversa da GET, POST, PUT, DELETE ecc.), Cambiare lo stato della risorsa sul client e spingerlo di nuovo al server per salvare.

I want to have a common gateway to the app. User asks for /index.php. I respond with user, call, campaign and a brief message telling them that they can use GET on these resources to know more. Then upon those resources, I want to display available methods followed by description of the selected method and so on and so forth.

Ancora non inserire questo codice. Metti questa è una specifica che il cliente implementa.

L'intero punto di REST è che il client e il server non sono legati in questo modo. Ad esempio, quando un browser Web abbassa un'immagine in formato PNG, non contiene istruzioni su cosa sia un'immagine PNG. Il presupposto è che il browser già capisca cosa sia un'immagine PNG altrimenti non avrebbe detto al server di rappresentare la risorsa in questo formato di immagine.

Most importantly, I want to respond in the user's chosen accept-header if supported by me.

Basta controllare l'intestazione Accept sulla richiesta, se si supporta quel formato quindi la risposta, se non si restituisce il codice di stato che dice che il formato non è supportato, o semplicemente si restituisce in txt (la maggior parte dei client dovrebbe almeno supportare il testo)

    
risposta data 20.10.2015 - 13:55
fonte

Leggi altre domande sui tag