0

I'm not sure how to ask this. I know this is simplistic, but I understand (I think):

  • REST is an architecture, not required, simply a way to build
  • REST is a style and a community standard for transfer of data
  • REST uses verbs and nouns, mostly the latter, GET, POST, PUT, DELETE...

As I read I only see the architecture from the consumers point of view and the creator of the API for the consumer.

What I cannot find is how to do this for just my application. What if I'm not sharing anything with anyone at the moment. I want to build my application to follow this architecture for the future.

What do I do now? If I want to use this type of construct:

Examples:

  • PUT http://www.example.com/customers/12345
  • PUT http://www.example.com/customers/12345/orders/98765
  • PUT http://www.example.com/buckets/secret_stuff

I my application, when I create a new person, I use an HTML <form action="something.php" method=POST> Now how do I do this with PUT? Where does this go?

If I use http://www.example.com/customers/12345 how do I know within my application that I want to PUT or GET or whatever?

I'm using MVC, where's my action? I realize the consumer might use my architecture/service with nouns, but this is for only me. How do I know what to do, if I can't use PUT in a form tag?

Right now I use my PHP page to grab the query string based upon a RewriteRule:

require_once("database\\adapters\\PDO\\Database.bootstrap.php");
class App {
    protected $_controller = 'Welcome';
    protected $_method = 'index';
    protected $_params = [];
    protected $_model = 'Welcome';

    public function __construct(){
    $url = $this->parseURL();
    //This works because I put the rewrite rules in IIS; 
    //Our RewriteRule in IIS (or Apache) is ^(.+)$  This is any character saved to a variable.
    //The new location is index.php?url=$1 [QSA, L].  This will look a little different after you import it into IIS.

    if (file_exists('app\\controllers\\' . $url[0] . '.controller.php')){
        $this->_controller = $url[0];
        $this->_model = $url[0];
        unset($url[0]);  //Unset removes that element from the array; 
        //var_dump($url);
    }

    //Get the controller and model.  All done by convention over configuration;
    require_once 'app\\controllers\\' . $this->_controller . '.controller.php';
    require_once 'app\\models\\Parent.model.php';

    //get a new Database object from the bootstrap;
    $_DB = new DatabaseBootstrap();

    $this->_controller = $this->_controller . "Controller"; 

    $this->_model = new ParentModel($_DB->getAdapter());
    $this->_controller = new $this->_controller($this->_model);

    //This checks to see if our method from the url exists;
    //Your querystring will look like this - http://server/virtualdirectory/controller/action/variables1/variable2.....

    if(isset($url[1])){
        if(method_exists($this->_controller,$url[1])){
            $this->_method = $url[1];
            unset($url[1]);
        }
    }

    $this->_params = $url ? array_values($url) : [];

    //This calls your controller and your method and sends over your array of parameters
    call_user_func_array([$this->_controller, $this->_method],$this->_params)
}

public function parseURL(){
    if(isset($_GET['url'])){
        return $url = explode('/',filter_var(rtrim($_GET['url'],'/'),FILTER_SANITIZE_URL));
        }
    }

EDIT: Based upon my reading of the answers, it appears I cannot use REST natively as in using HTTP verbs. I either have to use the name of the types in AJAX or I have to have a hidden field that contains my REST method like so (example from cakePHP):

<form id="RecipeEditForm" method="post" action="/recipes/edit/5">
<input type="hidden" name="_method" value="PUT" />

And it seems this is done for the "greater good." That is, so that others can consume my API services using libraries such as curl or using AJAX where one can create any request method they wish (?). Since we are using a REST architecture, the consumer using the API would simply put PUT, DELETE, etc. Some future architecture might not use those verbs, so we make up new keywords. It's just that PUT, etc. are in the w3 specs for HTTP, which are not very well supported.?

1

One popular php framework allows faking PUT/DELETE requests by adding a _method=PUT argument to your form action:

<form method="POST" action="/customers/12345?_method=PUT">

Internally, the framework converts the POST request to a PUT request.

http://symfony.com/doc/current/cookbook/routing/method_parameters.html#faking-the-method-with-method

Easy enough to implement. But I would follow @vrostu's advice and look into a javascript REST framework instead of trying to use forms.

  • Why would it do this? Is this solely so it can be RESTful, having that architecture, even though you cannot really use those verbs? – johnny Oct 2 '14 at 17:52
  • Yep. Your server side code can be written to properly support PUT/DELETE. When you do move to a proper client side REST application your server will be ready. – Cerad Oct 2 '14 at 18:09
  • In your Symfony example, do you think that is proper? Is that what you mean? – johnny Oct 2 '14 at 18:20
  • Yep. I use it for a few apps though most of the time I just go with AngularJS on the client. The fact that CakePHP appears to do pretty much the same implies that it is a workable approach. It's a little bit funky since POST is defined a bit differently than PUT/DELETE especially with respect to caching. But it would be rare to run into those issues for most apps. You should of course think carefully about what you are trying to achieve. By not using ajax you are really limiting yourself. But if you have to stick with html only on the client side then have at it. – Cerad Oct 2 '14 at 18:26
  • I would avoid such hacks if you possibly can (and seriously question why you can't if you feel you can't). They break the defined meaning of HTTP verbs and couple server implementation to a very specific client implementation. Both these things defeat the purpose of REST in the first place, so raises question why bother with REST at all if your design simply negates its usefulness – Cormac Mulhall Oct 3 '14 at 8:55
2

HTML forms can only be submitted by GET and POST. Many applications that use REST services don't rely on HTML forms because of these limitations, and instead submit data by AJAX where you are not limited to just two verbs. There are endless existing libraries for doing this in Javascript (jQuery, Angular $http, etc). Additionally you are not limited to form-encoded data over AJAX - for example you can send JSON or XML from your page if that's more convenient.

  • I know our craft is complex by nature for the most part, and I can build it, but that seems to be really complicated for what I'm asking to do. Can it not be done without AJAX? If I do use AJAX with my "Type:" qualifier, such as in jQuery, aren't I just making up a type there? I mean can't I put any kind of type there? It's just that I happen to be adhering to the REST architecture that in reality isn't supported in HTTP? – johnny Oct 2 '14 at 17:57
1

How do I know what to do, if I can't use PUT in a form tag?

There seems to be some confusion between your application (the server) and one possible client of your application (the web browser talking to the server). You most certainly can use PUT on the server.

As vrostu says web browsers use HTML and HTML has not kept up well with HTTP. HTTP has had these verbs since the late 1990s but HTML has not been updated to allow easy construction of web site forms that use these verbs. I think HTML 5 is changing this, slowly.

When designing your server it is best to ignore what client will be using to communicate and just design it correctly the way you want to design it, using all the HTTP verbs. You can use other tools to communicate with it rather than HTML web forms.

When you are happy the server is working well then look to using a javascript library to hack the web page to send the correct HTTP request.

  • But how can I do that if the form tag does not allow PUT/DELETE requests to be sent? Say I want to use no javascript AJAX as you said. How do I use the HTTP verbs for an all internal application (no client), just my server. I also think my notions of client and server are messed up. In my app, aren't I the client and the server? The front end and back end? I do not have other consumers other than myself. – johnny Oct 2 '14 at 17:51
  • The Web browsers is a client. And unfortunately they aren't great. You can use something like curl on the command line to test your servers api. – Cormac Mulhall Oct 2 '14 at 17:53
  • I do appreciate everyone's answer. I really do, but this doesn't really answer my question. Where do I put the HTTP verbs? Do I put it in a URL in my form's action? Do I put it in a hidden input somewhere? Do I do it all in AJAX and put the Type: I want? Where does this information go in my client that I'm saving my data to? If I use curl, that isn't helping me with my client's design. It only tells me my API is working for someone else that consumes it via CURL or some other library. I'm doing everything from an HTML page client.In other words, I cannot use all the HTTP verbs in HTML. – johnny Oct 2 '14 at 17:59
  • Seems that all tutorials go for the consumer of services, but they never talk about your own app consuming your own services. I guess I was the only one asking. – johnny Oct 2 '14 at 18:34
  • 1
    If you are doing everything from a HTML page client running in a web browser then unless you use Javascript you cannot use PUT or DELETE because HTML forms do not support HTTP verbs other than GET and POST. Answer is don't use pure HTML running in a web browser, they are not designed to be clients for rich RESTful APIs. – Cormac Mulhall Oct 3 '14 at 8:46
1

I my application, when I create a new person, I use an HTML Now how do I do this with PUT? Where does this go?

You don't. If you are using html as your representation of application state, then the links you provide in your hypertext use GET or POST. Yes, you can try to fake PUT/DELETE via post, but the client isn't going to recognize those actions as idempotent, nor will the various caches, reverse proxies, etc between your server and the application. Don't fight the tides; you'll get far fewer surprises down the road.

If you take HTML out of the picture, the story changes. For instance, if you are going to use JSON as the representation of state, your resources can support the PUT and DELETE methods directly.

There's no reason that your server can't do both. Provide html representations of the application state with GET/POST links, and provide json representations with application state that includes PUT/DELETE links as well. The basic plot is that when a client arrives at your service, you give them the representation that matches the content-type the client supports, and from that point, the client simply follows the links that your server provides.

The resources are not necessarily 1-1. For instance, if you want an idempotent "create", using a PUT is perfect... but not in HTML, where put isn't supported. You'll probably end up doing a POST, and to a different resource. So at the representation level, you've got more work to do than just transforming the json to html.

If I use http://www.example.com/customers/12345 how do I know within my application that I want to PUT or GET or whatever?

Link relations and media types. That is, the link in your application state includes meta data that describes the kind of link it is, and the documentation of your api tells the application programmer what meanings are associated with that link.

For example, review the Paged Feeds specification. The application state provides the url and the link relation. Your api specification explains the semantics of the relation.

<link 
    rel="http://www.example.com/docs/links/relations/create"
    href="http://www.example.com/customers/12345"
    ...
/>

Using the identifier of the documentation as the spelling of the link relation makes it really easy for developers to find the docs, but it's not required to do that; you'll have noticed that the Paged Feeds specification uses spellings "next", "previous", and so on.

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.