Design Specs: API

From WormBaseWiki
Jump to navigationJump to search

Proposed Revisions, 2011.02.15

Here are proposed guidelines.

1. The data structure can be flexible and return a string for simple items, an array reference for simple lists, or a hash reference for more complex structures. return a string, an array reference or a hash reference.

2. Simple strings

$return = { description => 'prose description of the data',
                data           => 'this is a simple piece of data like a descriptor; we just return a string' };

If empty:

$return = { description => 'prose description of the data',
                data           => undef };

3. Simple lists

$return = { description => 'prose description of the data',
                data           => \@array };

If empty:

$return = { description => 'prose description of the data',
                data           => undef };

4. Hashrefs for complex data structures

$return = { description => 'prose description of the data',
                data           => { dog => 'fido',
                                        cat => 'fluffy',
                                        rat => 'remy',                                           
                                        pets => \@pets,
                                       }
               };

If empty, return undef for entries as above.

5. Adopting these standards could make template writing easier. We no longer need to do:

 [% IF fields.FIELDKEY.data.size > 0 %]

For strings and arrays, checking for undefined becomes:

    [% IF fields.FIELDKEY.data %]

A little more involved for more complicated data structures:

  [% IF fields.FIELDKEY.data.defined('KEY') %]

6. Documentation

I'd like to be able to generate the REST interface documentation automatically. we can do this easily with good POD.

At least to start:

=item also_refers_to()                                                                                                             
                                                                                                                                  
 Fetch other genes that the public name of the current gene might refer to.                                                        
                                                                                                                                  
 Returns: arrayref of other genes or undef.                                                                                        
                                                                                                                                  
=cut  

7. Formatting guidelines

Might I also suggest the following coding styles to help readability in models?

  • Hash keys unquoted unless necessary
$data{description} 
   not $data{'description'}
  • Line space when warranted. Don't got overboard. Some of us use netbooks and small devices.
  • Sensible indentation
  my $description =
       $object->Concise_description

|| eval {$object->Corresponding_CDS->Concise_description}

       || eval { $object->Gene_class->Description };

Not:

  my $description =
       $object->Concise_description

|| eval {$object->Corresponding_CDS->Concise_description}

   || eval { $object->Gene_class->Description };
  • Operator alignment on adjacent lines
  • Assign variables when necessary, otherwise not.
  • Comments when warranted
  • Example:

Old:

sub proteins {
                                       # no line space needed
        my $self = shift;       # align operators on adjacent lines
        my $object = $self->object;
        my %data;               # Unnecessary variable declaration
        my $desc = 'proteins related to gene';   # skip variable assignment unless necessary
                                                                 # White space not necessary
                                                                 # White space not necessary
        #### data pull and packaging               # Obvious comment is obvious 
                         
                my @cds    = $object->Corresponding_CDS;                          # weird indentation
                my @proteins  = map { $_->Corresponding_protein } @cds;     # weird indentation
        @proteins = map {$self->_pack_obj($_, $self->public_name($_, $_->class))} @proteins;

        ####          # Pointless comment
                         # Unnecessary whitespace
        $data{'data'} = \@proteins;    # Unnecessary hash key quote
        $data{'description'} = $desc; # Unnecessary hash key quote; variable assignment
        return \%data;
}

New:

sub proteins {
        my $self    = shift;
        my $object = $self->object;

        my @cds    = $object->Corresponding_CDS;
        my @proteins  = map { $_->Corresponding_protein } @cds;
        @proteins = map {$self->_pack_obj($_, $self->public_name($_, $_->class))} @proteins;

        my $data = { data              => \@proteins,
                                 description => 'proteins coded for by this gene', };
        return $data;
}



API Specs

  • Objects stop here -- what is passed to displays will be strings and numbers
  • Define data building blocks for common display formats -- lists, tables, build off these blocks
  • Provide consistent data access methods to above for display
  • Define common data packs? -- e.g. id and common names?
  • Analyze user reported data issues and build more robustness for common problems (e.g. object not found can't call method)

Notes 2010.02.04

  • The API need not be aware of presentation details. It doesn't need to know about tables, for example, although it should handle generic one and two dimensional arrays.
  • We may want to consider passing some objects through to templates. If we pass WormBase::API objects, templates can then do additional on-the-fly data extraction.
  • We probably DON'T want to pass Ace objects. This means that your data munging subroutines will need to do something like:
 $allele = $gene->Allele;
 $returned_data => { data => "$allele" };

This will stringify the name of the object and prevent it from being passed as an object.


Notes 2010.03.03

  • Maintain subsection level for return data structure -- most likely use hash for each anticipated data slot
  • Update elegansSubs subroutines to function in data pull mode here -- e.g. Object2URL will return a data structure containing data for generating URL
  • Another pack: Object2Human_readable_info, e.g. Common_name, GO_Term, etc.
  • For the template -- Update tableize, create form_URL, Objects for manipulating Ace data.

Notes 2010.03.08

  • more granular return data for API, data collation will be performed by controller
  • higher abstraction for Object::common_name to be used by all classes
  sub common_name {
   
    my $object = shift @_;
    my $class = shift @_;
    my $common_name;    
    
    if ($class =~ /gene/i) {
	$common_name = 
	$object->Public_name
	|| $object->CGC_name
	|| $object->Molecular_name
	|| eval { $object->Corresponding_CDS->Corresponding_protein }
	|| $object;
    }
    elsif ($class =~ /protein/i) {
    	$common_name = 
    	$object->Gene_name
    	|| eval { $object->Corresponding_CDS->Corresponding_protein }
    	||$object;
    }	
    else {
    	$common_name = $object;
    }

    my $data = $common_name;
    return $data;
 }
  • package returned object into a hash containing name, id, and class information
 sub compile_data_pack {

  my $object = shift @_;
  my $class = $object->class;
  my $common_name = common_name($object, $class);

  my %data_pack;

  $data_pack{'id'} = $object;
  $data_pack{'name'} = $common_name;
  $data_pack{'class'} = $class;
  return \%data_pack;	
 
}

Resources

You can find the API in the WormBase mercurial repository:

lib/WormBase/API


There are tests in t/

cd WormBase // the directory where you've checked out your code
prove -l t/API/Object/Gene.t

These are obviously dependent on being able to connect to the database...


Issues Table

Issue Notes Pros Cons
Let ACE objects through
minimal API programming breaking the MVC barriers
Allow API objects trough Need to create std. data passing structures; need to create methods which can use data structures maintain MVC barriers, flexibility for views; need programming from the view side more complex than letting ACE objects through
Create "query language" need to create std. data return structures; need standard syntax provides mechanisms to do complex queries involving data from related objects; with an accompanying data structure standard, easy access to returned data for view complexity, question of robustness
Code to deal with missing objects from tags Analyze user reported errors for priorities provide good measure of robustness added complexity to coding; use 80/20 rule
Learn the ropes of TT better provide more guidance re: above choices