Lights, Camera, Action

Welcome to the POST office

Okay, we've explored the power of serverside scripts. And we know how to configure URLs, whether by Content Management or ElementAjax, but so far, we've only explored how the server responds to the HTTP GET verb, and that's a lot of fun, but you're probably going to want a little bit more. So let's look at how to make a form.  Let's make a form to let frontend users create Expression Articles.

Remember those XprPostHandler adapters we said we'd get back to? Let's look at an example:

{  
    "type"          : "XprPostHandler",
    "contextName"   : "CreateArticleForm",
    "configuration" : {
        "postHandler" : "ArticleCreatorBundle/CreateArticleHandler"
    }
}  

What's that in the postHandler variable? We've seen this before. It's a bundlePath. This is a reference to a bundleable object we haven't touched on yet, called a PostHandler. We'll get to the View Template in a a second, but first let's take a peek at a Post Handler:

{
    "fields" : [
        {
               "name"       : "Title",
               "required"   : false,
               "type"       : "text"
        },
        {
                "name"      : "Body",
                "required"  : false,
                "type"      : "text"
        }
    ],
    "script" : [ "ArticleCreatorBundle/CreateArticleScript" ]
}

So this little bit of glue - your Datasource and Posthandler definition - work in tandem to provide replacement variables for your View Template:  

{{#with CreateArticleForm}}
    <form method="POST">
        {{#each fields}}
        <input type="{{type}}" name="{{name}}"/>
        {{/each}}
        {{{postbackInput}}}
    </form>
    {{#if result}}
        Last POST result:
        <pre>
        {{{XprJson result.createdArticle}}}
        </pre>  
    {{/if}}
{{/with}}

Hang on, what's with those triple curly braces? In handlebars templating, {{{ }}} allows you to emit HTML that is not escaped. We're using it for two purposes here:

  1. postBackinput
  2. XprJson

What the heck is a postbackInput? It's simply a generated <input> tag which contains a value that signs this particular instance of the form on the page so it knows how to route the response to the POST request. It's just provided as a convenience, you can supply the same value generated as a form post variable yourself if you're not interacting with your element via an HTML form.   

If a page is rendered and it contains a PostHandler datasource, it'll respond to POSTs, simply by virtue of it being included on the page.

And as for XprJson? It's an example of a Template Helper. Expression ships with a rich library of helpers, covered in the rest of the reference material. In this particular case, we're just using it to print the JSON returned from the script we bound in the postHandler object.   

Speaking of, we should take a look at that:  

/**
    ArticleCreatorBundle/CreateArticleScript
**/

var api = new XprApi();  

function process(formData) {
    try {
        var createdArticle = api.call({
            method: "POST",
            uri: "/articles/",
            data: {
                "Title" : formData.title,
                "Html"  : formData.body
            },
        });
        return {
            "createdArticle" : createdArticle 
        };
    } catch (error) {
        return {
            "message" : "There was an error creating the article"
            };
    }
} 

What's going on here?

First, we're creating an instance of XprApi - the Serverside Scripting land interface to the Expression REST API. This is the interface by which you can interact programmatically with all of Expression's core objects. We're simply proxying the the data entered by the user on the form into an API call. The return value from process will be stuffed into the XprPostHandler datasource's {{response}} variable. Neat, hey? 

To put that in perspective, our entire backend management platform, you know, that thing with the Bundle editor and Content Management modules in it? It was built with the same API. This isn't just an afterthought, this is the same engine we used to build the application. We're a bit meta like that.  

Second, we're returning the newly created article. In the ViewTemplate, this will become the variable CreateArticleForm.result.createdArticle

It's worth observing that we're wrapping the whole shebang in a try...catch. Most Expression APIs return specially formatted, javascript compatible exceptions. We'd like to live in a world where technology never fails, but sometimes it does. So be safe, and handle those error states!  

You might be wondering how we know what fields to marshall our data into. Data objects, (articles, users, people, etc.) are all documented at {www.mydomain.com}/api/docs/.