Design Specs: API
Contents
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 |