0

How do I implement REST service description in a Content-type agnostic way?

Background

I am developing a RESTful API for Web Application. Now this app is somewhat different than a standard run-of-mills solution. This app uses a SIP B2BUA (asterisk), PHP+Mysql on Apache & NodeJS.

It is a call center solution that uses asterisk to handle VoIP calls and a LAMP stack for the UI.

Architecture

REST demands that application be stateless. However, due to the very nature of SIP, it cannot be 100% stateless. Thus I am using NodeJS at certain places to keep the real-time communication going.

Now, there is a REST API to all of this. It is designed in a pretty simple way. You have resources like user, call, campaign etc. And a user can initiate HTTP Verbs on these resources.

The Questions

I have arranged the architecture following the MVC pattern. The most salient thing I have done is, enforce Docblocks in the Models. The following is an example of such a class:

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();

Of course, I have given an idea of the docblocks and not the complete docblocks here. Basically, they would have the necessary documentation. Now, all the classes in Model namespace that would extend this class would have to use docblocks thereby enforcing documentation.

Also, I have a Helper::convert() function that can convert any result between XML and JSON depending on the user's Accept Request in the HTTP Header.

So, I am all set with that.

What I am utterly confused with is: 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?

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

  2. 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.

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

How do I go about doing this following correct conventions? Also, some references to RFCs would be really appreciated.

  • How do I go about doing this following correct conventions? -- You can't. You're creating your own conventions, so by definition, they're not going to be "standard" or "best practice", but actually your "standard" and your "practice." There's nothing necessarily wrong with that, by the way. – Robert Harvey Oct 20 '15 at 6:33
  • Have you thought about encoding the "content type" in the URL, similar to this? Or is that still too non-agnostic for you ? – Robert Harvey Oct 20 '15 at 6:35
1

I'm not familiar with technologies like SIP and VOIP, but I think I can give answers to the four questions you have.

  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 a RESTful API, resources point to each other using links. I will focus on the case that your API returns XML or JSON (rather than HTML). These formats do not have a standard way of representing links, so you must pick a standard, or invent your own. Anyway, I think a link should not only specify a URI, but also the HTTP method to be used. If multiple HTTP methods can be used on the same URI, then there should a link for each of these HTTP methods. Example:

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

So this is how you can inform the client which methods are available.

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

Fine, but the RESTful APIs I have seen do not use OPTIONS. They use links as the only means to convey the allowed HTTP methods to their clients.

  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.

Yes, you can respond with an XML or a JSON message containing links as described above. Example:

{
    "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.

Yes, when the client follows one of the links, it gets a JSON representation of that resource, containing links specifying what can be done with that resource.

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

Yes, you can check that header and return a response in the appropriate format.

For more REST conventions proposed by myself, check out JAREST.

  • Thanks for this awesome response. This is exactly what I am in the process of deploying. Are there any good JSON standard schematics for returning links? OPTIONS is unfortunately not used that much. But, if someone were to follow the "true" REST, it ought to be available. I will check out your link now. – Christian M. Raymonds Nov 5 '15 at 5:04
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?

You don't.

REST works by having a pre-determined format for communication between client and server. For example HTML, or PNG, or MP4. The client understands HTML, the server understands HTML (well in some cases, in others the server is just a dumb document store)

The client tells the server what data formats it understands and the server responds with the format if it also can output this resource. The client shouldn't be learning about the data format used to represent the resources. It should instead navigate the data format to get to the resource it wants. It shouldn't understand the layout of the resources.

Take HTML for example. Firefox does not know the layout of resources on the New York Time site. It doesn't know what "Todays weather" means, nor does it know what "Headlines" mean.

Firefox does though know what HTML means. It then leaves the navigation of resources to the user.

Document your data format and then let the client (either via a human user or via an api crawler) discover the resources in your system.

And remember REST is a state machine. You find a resource, change the state of it, and push it back to the server to save. Don't tell the server to do something with a resource (other than GET,POST,PUT,DELETE etc), change the state of the resource on the client and push it back to the server to save.

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.

Again don't put this in code. Put this is a spec that the client then implements.

The whole point of REST is that the client and the server are not tied in this fashion. For example when a web browser pulls down an image in PNG format it doesn't also contain instructions on what a PNG image is. The assumption is that the browser already understands what a PNG image is otherwise it wouldn't have told the server to represent the resource in this image format.

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

Just check the Accept header on the request, if you support that format then response, if you don't return status code saying format not supported, or just return it in txt (most clients should at very least support text)

  • I think this answer doesn't quite fit to the problem described by the author of this question. You take a web browser as an example, which is a client that is capable of showing any web page, but the server has to supply both data and layout (css) and client-side logic (JavaScript). In this case however, I would create an API that would only provide the data and the client app would have the layout and user interaction logic. Note that the author of the question has indicated that the responses are in XML and JSON format, not HTML. – www.admiraalit.nl Nov 2 '15 at 20:02
  • That is essentially how a browser works. HTML does not explain to the browser how you parse and navigate a HTML document, the HTML standard does. What does this link mean. What happens when you click a link. When you say the client should have the interaction logic I agree, but that should be defined based on the standard of the content being exchanged between server and client (even if you define this standard yourself). XML and JSON are meta formats, not meaningful data formats for this, it would be like saying my web browser understands the "text" data format (when it in fact parse HTML) – Cormac Mulhall Nov 3 '15 at 12:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.