Design Specs: Application Request Flow

From WormBaseWiki
Jump to navigationJump to search

Objectives

Background

Look at lib/WormBase/Web/Controller.pm.
http://bitbucket.org/tharris/wormbase/src/tip/lib/WormBase/Web/Controller.pm

This is the base class for Controllers.  Here I have dumb examples. All they do is return the available pages for the site, avaialble widgets for a page, and so on in plain text only.  Boring.  Next.

--
Now check out lib/WormBase/Web/Controller/Root.pm
http://bitbucket.org/tharris/wormbase/src/tip/lib/WormBase/Web/Controller/Root.pm

This is the Root controller, typically containing actions that would map to the document root (eg "/"), error pages (eg 404), or defaults for when there is no suitable action found in the Dispatch table.

This is (currently) quite complicated as it contains a fair amount of cruft, specifically relating to the dynamic creation of pages.  For example, look at sub page().  This action matches the URL reports/*/*.  It expects a class and a name of an object. From there, it fetches the object from the API, fills out each and every widget and field, and returns templates.

This needs to be reworked a bit.

--
Moving on, lets look at the REST interface.  I'd like to use the REST interface to build most of our pages, where the initial page is loaded as a standard GET, then each section loaded via Ajax asynchronously thruogh REST.

Look at lib/WormBase/Web/Controller/REST.pm
http://bitbucket.org/tharris/wormbase/src/tip/lib/WormBase/Web/Controller/REST.pm

Here again are methods for pages, widgets, and fields.

Look in particular at widget_compiled().  This is a single REST action that -- when provided with a class, object name, and symbolic name for a widget, will:
1. Get the object if it ain't been got
2. Fetch all the necessary fields that comprise that widget
3. Call that method on the API object.  Each field should correspond to a distinct method in the API (ie W::A::Object::Gene->description().
4. Place the return value in the stash with a key corresponding to the name of the field.
5. Set the appropriate template.  Currently this is dynamic. The configuration file can specify which fields require specific templates and which can use generic or common templates.
6. Pass it to the template for rendering.

Notes: 

* symbolic names for fields, specified in the configuration file correspond to both method names in the API and -- when required -- the names of templates. We could probably override the template name using configuration, but the field name/API name MUST MATCH!

* Templates are handed a perl data structure. We may want to consider an alternative approach where we push off rendering to the client.  See below.

Putting it all together
----------------------------
Consider a simple page with sections or tabs.  This page is available at "/reports/[CLASS]/[OBJECT]"

* Controller::Root::reports() handles the request.
* It looks up the template (from the web app configuration file)
* It hands to the template the symbolic name of all sections that the page should contain
* The template is rendered and returned to the client. It contains.
** A tabbed interface set up by javascript, one per each section
** Each tab, except for the default tab, is a link to the REST API (/rest/[CLASS]/[OBJECT]/[SECTION]).  When clicked, this request is sent to the server where it is populated.
** In return, the client receives html which it simply inserts into the document OR JSON, which it parses and inserts