Difference between revisions of "Design Specs: API"
(32 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
+ | = 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: | ||
+ | <pre> | ||
+ | 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; | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | New: | ||
+ | |||
+ | <pre> | ||
+ | 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; | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | |||
+ | |||
+ | |||
==API Specs== | ==API Specs== | ||
Line 17: | Line 150: | ||
This will stringify the name of the object and prevent it from being passed as an object. | 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 | ||
+ | |||
+ | <pre> 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; | ||
+ | } | ||
+ | </pre> | ||
+ | * package returned object into a hash containing name, id, and class information | ||
+ | |||
+ | <pre> | ||
+ | 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; | ||
+ | |||
+ | } | ||
+ | </pre> | ||
== Resources == | == Resources == | ||
Line 38: | Line 231: | ||
|- | |- | ||
! Issue | ! Issue | ||
+ | ! Notes | ||
! Pros | ! Pros | ||
! Cons | ! Cons | ||
Line 44: | Line 238: | ||
|- | |- | ||
| Let ACE objects through | | Let ACE objects through | ||
+ | | <br> | ||
| minimal API programming | | minimal API programming | ||
− | | breaking the | + | | 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 | ||
+ | | <br> | ||
+ | | <br> | ||
|- | |- | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | [[Category:Developer documentation]] |
Latest revision as of 14:59, 15 February 2011
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 |