Skip to content

Latest commit

History

215 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

BrAPI.js

BrAPI.js is a JavaScript client library for BrAPI. The call style of this library is inspired by D3.js. It can be used in either a browser or a Node.js application. It uses the Fetch API (or node-fetch in Node.js) for making AJAX calls. BrAPI.js is dependent on ES6 classes.

BrAPI.js supports BrAPI versions v1.0-v2.0. Currently, it expects a server to use a single version.

Contents

Installation

# Be sure your version of NPM supports 'prepare' scripts (>=npm@4.0.0)# Recommended:
npm install git+https://github.com/solgenomics/BrAPI-js
# Otherwise:
git clone https://github.com/solgenomics/BrAPI-js.git
cd BrAPI.js
npm install .

Include/Require

<!--Browser--><scriptsrc="build/BrAPI.js" charset="utf-8"></script>
// ES6 importimportBrAPIfrom'./build/BrAPI.js';
// Node.jsconstBrAPI=require('./BrAPI.js');

How it Works

BrAPI.js has been designed to allow for many simultaneous and interdependent calls to BrAPI to be performed asynchronously. In order to do this, data are managed by a class of objects called BrAPINodes. Nodes are organized into a DAG which represents dependancies. Each node represents a transformation on the data. Basic transformations include fork, join, map, reduce, and filter. BrAPI calls are special transformations. Each BrAPI call can be either a fork (calls returning array data) or a map (calls returning single objects). Data interacts through nodes via tasks. When a task completes, it triggers the creation of new task(s) in all child nodes. With the exception of reduce, the operations can be performed independently on each datum. This means one datum can be transformed across multiple nodes while another moves more slowly.

Usage Reference

Initialization and Configuration

#BrAPI(address, [version, auth_token, call_limit, credentials]) <>

Creates a root BrAPINode. This is the root of a BrAPI.js DAG dataflow. The address should be a string with the base URL of a BrAPI instance that is being queried, i.e. "https://www.yambase.org/brapi/v1". If an auth_token is provided, it will be added as a Bearer header when sending requests over HTTPS. Changing the version determines which deprecation/removal warnings are written the console, it does not restrict functionality. The call_limit parameter specifies how many simultaneous requests may be run by this node and its descendants against the specified server. The credentials parameter allows you to define how HTTP credentials (aka cookies) should be included in a request. See https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials for more information.

Examples:
varbrapi_root=BrAPI("https://www.yambase.org/brapi/v1")
varbrapi_root=BrAPI("https://www.yambase.org/brapi/v1","v1.2","myToken")
varbrapi_root=BrAPI("https://www.yambase.org/brapi/v1",null,//Don't specify version"myToken",18//Allow 18 simultaneous requests)

If you have multiple different versions of BrAPI for different calls on your server, you may have to create two separate BrAPI handlers. For example, if your search calls are v1.2 and everything else is v1.3, you would have to use one of the following options:

varbrapi_root1=BrAPI("https://www.myserver.org/brapi/v1","v1.2")// for your search callsvarbrapi_root2=BrAPI("https://www.myserver.org/brapi/v1","v1.3")// for your other calls.
varbrapi_root1=BrAPI("https://www.myserver.org/brapi/v1","v1.2")// for your search calls.germplasm_search(...).server("https://www.myserver.org/brapi/v1","v1.3")// switch for your other calls..germplasm_progeny(...).each(...);

#node.server(address, [version, auth_token, call_limit, credentials]) <>

Creates and returns a child BrAPINode which changes the BrAPI server instance queried by all descendants.

Examples:
BrAPI("https://www.yambase.org/brapi/v1")// Query accessions containing "MyAccession" from yambase.org.germplasm_search({germplasmName:"MyAccession"})// ** Switch to yamMarkerBase.net **.server("https://www.yamMarkerBase.net/brapi/v1")// Using results from the first query, search the second server// (one search for each result from the first).germplasm_search(function(germ){return{germplasmName:germ.germplasmName}});

#node.data(array) <>

Creates and returns a child BrAPINode which ignores any completed tasks from it's parent node and creates a new task in each child node for each datum in the array. This is the main way of adding input to the dataflow and is only available as a child of the root node, or on a server node that is the immediate child of a root node.

Examples:
BrAPI("https://www.yambase.org/brapi/v1")// Set ["344","567","223"] as data.data(["344","567","223"])// perform a germplasm call with each datum as germplasmDbId.germplasm(function(d){return{germplasmDbId:d};}).all(function(germplasm_objects){//prints a list of germplasm objectsconsole.log(germplasm_objects)});

BrAPI Call Nodes

#node.{{BrAPI_Method}}(params [, behavior]) <>

A {{BrAPI_Method}} is be one of the available BrAPI methods. These methods create and return a child BrAPINode which makes the relevant BrAPI calls. Calls are tracked as tasks and occur asynchronously. metadata.asynchStatus asynchronous BrAPI calls are also supported and a polling time of 15 seconds is used. Parameters (either URL parameters or body parameters) are specified for the call using the params argument. The params argument can either be an object, or a function. If it is a function, a separate BrAPI call will be made for each datum passed by the parent node. Otherwise, a single call (or series of calls for each page) will be made and the input data will be ignored. For each datum created, the full response from which it was extracted is available via datum.__response.

There are two special parameters specific to BrAPI.js. The first, pageRange (an array [first_page, last_page]), controls pagination and must be used in place of the usual BrAPI page parameter. pageRange defaults to [0,Infinity]. The second, HTTPMethod, allows one to override the default HTTP method (e.g. "POST","GET") for a BrAPI method.

For calls which return a response containing a data array, (i.e. node.germplasm_search(...) ), the behavior argument determines how that data is handled. The default behavior is "fork".

  • If behavior =="fork", each object in each page_response.results.data array will be treated as an individual datum.
  • If behavior =="map", the page_response.results.data array from each response will be concatenated into the initial response's data array and the resulting page_response.results object will be considered a single datum. For calls which do not return a data array, the response.results object is always treated as a single datum.

#node.poll(callback) <>

Wether a call is a BrAPI 'asynch' call will be determined automatically from the response. By default, polling occurs every 15 seconds. To vary the polling times, or check the status, one can use this method which is available only on brapi call nodes. The callback function receives the full json response as the only argument. If it returns a non-null value greater than zero, the next poll with occur after that many milliseconds. If multiple poll methods are chained, they will execute in order and the last non-null return value greater than zero will be used as the polling time.

//to poll the allelematrix_search call every 10 secondsBrAPI("https://www.yambase.org/brapi/v1").data(["1038","4542","45534"]).allelematrices_search(function(d){return{markerprofileDbId:d};}).poll(function(response){console.log(response.metadata);return10000;});

Non-BrAPI Nodes

#node.map(callback) <>

Creates and returns a child BrAPINode which transforms each datum in a manner similar to Array.prototype.map(). The callback function is called with two arguments (datum, key) for each datum, and may return any value which will be passed to child nodes as a single datum.

#node.fork(node [, node, ...]) <>

Creates and returns a child BrAPINode which transforms each datum in a manner similar to node.map(), however, the callback function should return an array. Each item of each returned array will be passed to child nodes as a datum.

#node.filter(callback) <>

Creates and returns a child BrAPINode which transforms each datum in a manner similar to Array.prototype.filter(). The callback function is called with two arguments (datum, key) for each datum, returning true will pass the datum to child nodes while returning false will remove it from the dataflow.

#node.reduce(callback [, initialValue]) <>

Creates and returns a child BrAPINode which transforms each datum in a manner similar to Array.prototype.reduce(). The callback function is called with two arguments (accumulator, datum) and should return the modified accumulator. The result from the reduction will be passed to child nodes as a single datum.

#node.join(node [, node, ...]) <>

Creates and returns a child BrAPINode which takes the output datum from multiple BrAPINodes and joins them into arrays on their keys which are then passed to child nodes. Datum are assigned keys in two different manners. First, when a key-modifying node (a fork node, a reduce node, or a BrAPI node with the behavior of "fork" or called with a single parameter object) transforms data, it will assign each datum a new key in order to maintain uniqueness. Second, keys can be manually assigned using node.keys(...) to create a keys node. node.join(...) will only join nodes which share their most recent key-modifying ancestor, or which have all had their keys manually assigned.

#node.keys(callback) <>

Creates and returns a child BrAPINode which transforms each datum in a manner similar to node.map(). However, instead of modifying the data, it will modify the key for each datum. The callback function is called with two arguments (datum, currentKey) and should return a new key to replace currentKey. Keys returned by the callback function may be any value. If the callback function returns any type other than a string, it will converted to a string before being used as a key. A single key string should not be assigned to two separate datum, doing so will result in errors later in the dataflow.

Accessing Data Output

#node.each(callback) <>

This method registers a callback function which is called each time the node completes the transformation of a datum. The callback function is called with the arguments (datum, key).

#node.all(callback) <>

This method registers a callback function which is called once a node has loaded all data. The callback function is called with a single argument data, which is an array of all data sorted by their keys lexicographically.

Available BrAPI Methods

BrAPI.js MethodBrAPI Call (<= v1.3)BrAPI Call (v2.0)Default HTTPMethod
node.allelematrices_search(params,...)/allelematrices-search(>=v1.2) or /allelematrix-search(<v1.2)POST
node.allelematrices(params,...)/allelematricesGET
node.attributes_categories(params,...)/attributes_categories/attributes/categoriesGET
node.attributes_detail(params,...)/attributes/{attributeDbId}GET
node.attributes_modify(params,...)/attributes/{attributeDbId}PUT
node.attributes_store(params,...)/attributesPOST
node.attributes(params,...)/attributes/attributesGET
node.attributevalues_detail(params,...)/attributevalues/{attributeValueDbId}GET
node.attributevalues_modify(params,...)/attributevalues/{attributeValueDbId}PUT
node.attributevalues_store(params,...)/attributevaluesPOST
node.attributevalues(params,...)/attributevaluesGET
node.breedingmethods_detail(params,...)/breedingmethods/{breedingMethodDbId}/breedingmethods/{breedingMethodDbId}GET
node.breedingmethods(params,...)/breedingmethods/breedingmethodsGET
node.calls(params,...)/calls (server info)GET
node.serverinfo(params,...)/serverinfoGET
node.calls(params,...)/calls (genotyping calls)GET
node.callsets_calls(params,...)/callsets/{callSetDbId}/callsGET
node.callsets_detail(params,...)/callsets/{callSetDbId}GET
node.callsets(params,...)/callsetsGET
node.commoncropnames(params,...)/commoncropnames(>=v1.2) or /crops(<v1.2)/commoncropnamesGET
node.crosses_modify(params,...)/crossesPUT
node.crosses_store(params,...)/crossesPOST
node.crosses(params,...)/crossesGET
node.crossingprojects_detail(params,...)/crossingprojects/{crossingProjectDbId}GET
node.crossingprojects_modify(params,...)/crossingprojects/{crossingProjectDbId}PUT
node.crossingprojects_store(params,...)/crossingprojectsPOST
node.crossingprojects(params,...)/crossingprojectsGET
node.events(params,...)/eventsGET
node.germplasm_attributes(params,...)/germplasm/{germplasmDbId}/attributesGET
node.germplasm_detail(params,...)/germplasm/{germplasmDbId}/germplasm/{germplasmDbId}GET
node.germplasm_markerprofiles(params,...)/germplasm/{germplasmDbId}/markerprofilesGET
node.germplasm_mcpd(params,...)/germplasm/{germplasmDbId}/mcpdGET
node.germplasm_modify(params,...)/germplasm/{germplasmDbId}PUT
node.germplasm_pedigree(params,...)/germplasm/{germplasmDbId}/pedigree/germplasm/{germplasmDbId}/pedigreeGET
node.germplasm_progeny(params,...)/germplasm/{germplasmDbId}/progeny/germplasm/{germplasmDbId}/progenyGET
node.germplasm_search(params,...)/germplasm-search/search/germplasmPOST-->GET
node.germplasm_store(params,...)/germplasmPOST
node.germplasm(params,...)/germplasm/germplasmGET
node.images_detail(params,...)/images/{imageDbId}/images/{imageDbId}GET
node.images_imagecontent(params,...)/images/{imageDbId}/imagecontentPUT
node.images_imagecontent_modify(params,...)/images/{imageDbId}/imagecontentPUT
node.images_modify(params,...)/images/{imageDbId}PUT
node.images_store(params,...)/imagesPOST
node.images(params,...)/images/imagesGET
node.lists_detail(params,...)/lists/{listDbId}/lists/{listDbId}GET
node.lists_modify(params,...)/lists/{listDbId}PUT
node.lists_items_store(params,...)/lists/{listDbId}/itemsPOST
node.lists_store(params,...)/listsPOST
node.lists(params,...)/lists/listsGET
node.locations_detail(params,...)/locations/{locationDbId}/locations/{locationDbId}GET
node.locations_modify(params,...)/locations/{locationDbId}PUT
node.locations_store(params,...)/locationsPOST
node.locations(params,...)/locations/locationsGET
node.maps_detail(params,...)/maps/{mapDbId}/maps/{mapDbId}GET
node.maps_linkagegroups_detail(params,...)/maps/{mapsDbId}/positions/{linkageGroupId}GET
node.maps_linkagegroups(params,...)/maps/{mapDbId}/linkagegroups GET
node.maps_positions(params,...)/maps/{mapsDbId}/positionsGET
node.maps(params,...)/maps/mapsGET
node.markerpositions(params,...)/markerpositionsGET
node.markerprofiles_detail(params,...)/markerprofiles/{markerprofileDbId}GET
node.markerprofiles_search(params,...)/markerprofiles-searchPOST
node.markerprofiles(params,...)/markerprofilesGET
node.markers_detail(params,...)/markers/{markerDbId}GET
node.markers_search(params,...)/markers-searchPOST
node.markers(params,...)/markersGET
node.methods_detail(params,...)/methods/{methodDbId}/methods/{methodDbId}GET
node.methods_modify(params,...)/methods/{methodDbId}PUT
node.methods_store(params,...)/methodsPOST
node.methods(params,...)/methods/methodsGET
node.observationlevels(params,...)/observationlevels(>=v1.2) or /observationLevels(<v1.2)/observationlevelsGET
node.observations_modify(params,...)/observations/{observationDbId}PUT
node.observations_detail(params,...)/observations/{observationDbId}GET
node.observations_modify_multiple(params,...)/observationsPUT
node.observations_store(params,...)/observationsPOST
node.observations_table(params,...)/observations/table GET
node.observations(params,...)/observationsGET
node.observationunits_modify(params,...)/observationunits/{observationUnitDbId}PUT
node.observationunits_detail(params,...)/observationunits/{observationUnitDbId}GET
node.observationunits_modify_multiple(params,...)/observationunitsPUT
node.observationunits_store(params,...)/observationunitsPOST
node.observationunits_table(params,...)/observationunits/table GET
node.observationunits(params,...)/observationunits/observationunitsGET
node.ontologies(params,...)/ontologies/ontologiesGET
node.people_detail(params,...)/people/{personDbId}/people/{personDbId}GET
node.people_modify(params,...)/people/{personDbId}PUT
node.people_store(params,...)/peoplePOST
node.people(params,...)/people/peopleGET
node.phenotypes_search_csv(params,...)/phenotypes-search/csvPOST
node.phenotypes_search_table(params,...)/phenotypes-search/tablePOST
node.phenotypes_search_tsv(params,...)/phenotypes-search/tsvPOST
node.phenotypes_search(params,...)/phenotypes-searchPOST
node.phenotypes(params,...)/phenotypesPOST
node.plannedcrosses_modify(params,...)/plannedcrossesPUT
node.plannedcrosses_store(params,...)/plannedcrossesPOST
node.plannedcrosses(params,...)/plannedcrossesGET
node.programs_detail(params,...)/programs/{programDbId}GET
node.programs_modify(params,...)/programs/{programDbId}PUT
node.programs_store(params,...)/programsPOST
node.programs(params,...)/programs/programsGET
node.references_bases(params,...)/references/{referenceDbId}/basesGET
node.references_detail(params,...)/references/{referenceDbId}GET
node.references(params,...)/referencesGET
node.referencesets_detail(params,...)/referencesets/{referenceSetDbId}GET
node.referencesets(params,...)/referencesetsGET
node.samples_detail(params,...)/samples/{sampleId}/samples/{sampleDbId}GET
node.samples_modify(params,...)/samples/{sampleDbId}PUT
node.samples_store(params,...)/samplesPOST
node.samples(params,...)/samples/samplesGET
node.scales_detail(params,...)/scales/{scaleDbId}/scales/{scaleDbId}GET
node.scales_modify(params,...)/scales/{scaleDbId}PUT
node.scales_store(params,...)/scalesPOST
node.scales(params,...)/scales/scalesGET
node.search_attributes(params,...)/search/attributesPOST-->GET
node.search_attributevalues(params,...)/search/attributevaluesPOST-->GET
node.search_calls(params,...)/search/callsPOST-->GET
node.search_callsets(params,...)/search/callsetsPOST-->GET
node.search_germplasm(params,...)/germplasm-search/search/germplasmPOST-->GET
node.search_GET(entity, params,...)/search/{entity}/{searchResultDbId}/search/{entity}/{searchResultsDbId}GET
node.search_images(params,...)/search/images/search/imagesPOST-->GET
node.search_lists(params,...)/search/listsPOST-->GET
node.search_locations(params,...)/search/locationsPOST-->GET
node.search_markerpositions(params,...)/search/markerpositionsPOST-->GET
node.search_markers(params,...)/markers-search/search/markersPOST-->GET
node.search_observations(params,...)/search/observationsPOST-->GET
node.search_observationtables(params,...)/search/observationtablesPOST-->GET
node.search_observationunits(params,...)/search/observationunits/search/observationunitsPOST-->GET
node.search_people(params,...)/search/peoplePOST-->GET
node.search_POST(entity, params,...)/search/{entity}POST
node.search_programs(params,...)/programs-search/search/programsPOST-->GET
node.search_references(params,...)/search/referencesPOST-->GET
node.search_referencesets(params,...)/search/referencesetsPOST-->GET
node.search_samples(params,...)/samples-search/search/samplesPOST-->GET
node.search_studies(params,...)/studies-search/search/studiesPOST-->GET
node.search_trials(params,...)/search/trialsPOST-->GET
node.search_variants(params,...)/search/variantsPOST-->GET
node.search_variantsets(params,...)/search/variantsetsPOST-->GET
node.search(entity, params,...)/search/{entity-->search/{entity}/{searchResultDbId}/search/{entity-->search/{entity}/{searchResultsDbId}POST-->GET
node.seasons_detail(params,...)/seasons/{seasonDbId}GET
node.seasons_modify(params,...)/seasons/{seasonDbId}PUT
node.seasons_store(params,...)/seasonsPOST
node.seasons(params,...)/seasons/seasonsGET
node.seedlots_detail_transactions(params,...)/seedlots/{seedLotDbId}/transactionsGET
node.seedlots_detail(params,...)/seedlots/{seedLotDbId}GET
node.seedlots_modify(params,...)/seedlots/{seedLotDbId}PUT
node.seedlots_store(params,...)/seedlotsPOST
node.seedlots_transactions_store(params,...)/seedlots/transactionsPOST
node.seedlots_transactions(params,...)/seedlots/transactionsGET
node.seedlots(params,...)/seedlotsGET
node.studies_detail(params,...)/studies/{studyDbId}/studies/{studyDbId}GET
node.studies_germplasm(params,...)/studies/{studyDbId}/germplasmGET
node.studies_layouts(params,...)/studies/{studyDbId}/layouts/studies/{studyDbId}/layoutGET
node.studies_modify(params,...)/studies/{studyDbId}PUT
node.studies_observations_modify(params,...)PUT /studies/{studyDbId}/observations(>=v1.1) or /studies/{studyDbId}/observations(<v1.1)POST
node.studies_observations_zip(params,...)/studies/{studyDbId}/observations/zipPOST
node.studies_observations(params,...)/studies/{studyDbId}/observationsGET
node.studies_observationvariables(params,...)/studies/{studyDbId}/observationvariablesGET
node.studies_store(params,...)/studiesPOST
node.studies_table_add(params,...)/studies/{studyDbId}/tablePOST
node.studies_table(params,...)/studies/{studyDbId}/tableGET
node.studies(params,...)/studies/studiesGET
node.studytypes(params,...)/studytypes(>=v1.1) or /studyTypes(<v1.1)/studytypesGET
node.traits_detail(params,...)/traits/{traitDbId}/traits/{traitDbId}GET
node.traits_modify(params,...)/traits/{traitDbId}PUT
node.traits_store(params,...)/traitsPOST
node.traits(params,...)/traits/traitsGET
node.trials_detail(params,...)/trials/{trialDbId}/trials/{trialDbId}GET
node.trials_modify(params,...)/trials/{trialDbId}PUT
node.trials_store(params,...)/trialsPOST
node.trials(params,...)/trials/trialsGET
node.variables_datatypes(params,...)/variables/datatypesGET
node.variables_detail(params,...)/variables/{observationVariableDbId}/variables/{observationVariableDbId}GET
node.variables_modify(params,...)/variables/{observationVariableDbId}PUT
node.variables_search(params,...)/variables-search/search/variablesPOST
node.variables_store(params,...)/variablesPOST
node.variables(params,...)/variables/variablesGET
node.variants_calls(params,...)/variantsets/{variantSetDbId}/callsGET
node.variants_detail(params,...)/variants/{variantDbId}GET
node.variants(params,...)/variantsGET
node.variantsets_calls(params,...)/variants/{variantDbId}/callsGET
node.variantsets_callsets(params,...)/variantsets/{variantSetDbId}/callsetsGET
node.variantsets_detail(params,...)/variantsets/{variantSetDbId}GET
node.variantsets_extract_store(params,...)/variantsets/extractPOST
node.variantsets_variants(params,...)/variantsets/{variantSetDbId}/variantsGET
node.variantsets(params,...)/variantsetsGET
node.vendor_orders_plates(params,...)/vendor/orders/{orderId}/plates/vendor/orders/{orderId}/platesGET
node.vendor_orders_results(params,...)/vendor/orders/{orderId}/results/vendor/orders/{orderId}/resultsGET
node.vendor_orders_status(params,...)/vendor/orders/{orderId}/status/vendor/orders/{orderId}/statusGET
node.vendor_orders_store(params,...)/vendor/ordersPOST
node.vendor_orders(params,...)/vendor/orders/vendor/ordersGET
node.vendor_plates_detail(params,...)/vendor/plates/{submissionId}/vendor/plates/{submissionId}GET
node.vendor_plates_search(params,...)/vendor/plates-search(>=v1.2) or /vendor/plate-search(<v1.2)POST
node.vendor_plates(params,...)/vendor/plates/vendor/platesPOST
node.vendor_specifications(params,...)/vendor/specifications/vendor/specificationsGET

About

JavaScript BrAPI Client with support for asynchronous interdependent calls.

Topics

Resources

Stars

8 stars

Watchers

30 watching

Forks

Releases

Packages

Used by

Contributors

Languages