
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
A Node.js wrapper for the Trefle Plants API that provides easy access to comprehensive plant data including species information, taxonomy, distributions, and more.
This service follows the data-collection architecture pattern with organized data storage, rate limiting, comprehensive logging, and CLI orchestration - a Node.js port of the Python implementation.
# Install globally
npm install -g trefle-api
export TREFLE_API_TOKEN="your-token-here"
# Fetch plants
trefle --plants --pages 10
# Search for specific plants
trefle --search "rose" --search "oak"
import { TrefleAPI } from 'trefle-api';
const api = new TrefleAPI();
// Get edible plants
const plants = await api.getPlants({
filter: { edible: 'true' },
page: 1
});
// Search for a specific plant
const coconuts = await api.searchPlants('coconut');
// Get detailed information about a specific plant
const plant = await api.getPlant(123456);
The Trefle API provides access to a vast database of plants with over 1.3 million records. This Node.js service implements:
Core plant endpoints for searching and browsing plant data.
Endpoints:
getPlants() - List plants with filtering, sorting, and paginationgetPlant() - Get specific plant by ID or slugsearchPlants() - Search plants by query stringgetPlantsByZone() - List plants in a distribution zonegetPlantsByGenus() - List plants for a specific genusreportPlant() - Report an error for a plantParameters:
filter - Filter conditions (e.g., { edible: 'true', vegetable: 'true' })filter_not - Exclusion filters (e.g., { toxicity: 'high' })order - Sort order (e.g., { common_name: 'asc' })range - Range filters (e.g., { maximum_height: '10,100' })page - Page number for paginationHierarchical taxonomy data from kingdoms to genera.
Endpoints:
getKingdoms() / getKingdom() - Plant kingdomsgetSubkingdoms() / getSubkingdom() - SubkingdomsgetDivisions() / getDivision() - Divisions (phyla)getDivisionClasses() / getDivisionClass() - Division classesgetDivisionOrders() / getDivisionOrder() - Division ordersgetFamilies() / getFamily() - Plant familiesgetGenera() / getGenus() - Plant generaSpecies-specific endpoints with detailed information.
Endpoints:
getSpeciesList() - List species with filteringgetSpecies() - Get specific species by ID or slugsearchSpecies() - Search species by query stringreportSpecies() - Report an error for a speciesGeographic distribution zones (TDWG regions).
Endpoints:
getDistributions() - List all distribution zonesgetDistribution() - Get specific zone by ID or slugCommon Zone Codes:
usa - United Stateseur - Europeafr - Africaasi - Asiasam - South Americanam - North Americaaus - AustraliaCommunity-submitted corrections to plant data.
Endpoints:
getCorrections() - List all correctionsgetCorrection() - Get specific correction by IDgetCorrectionsForSpecies() - Get corrections for a speciesAdd your token to the .env file in the project root:
TREFLE_API_TOKEN=your_token_here
Important: Never commit your .env file or expose your token publicly.
# Install globally for CLI usage
npm install -g trefle-api
# Or install locally in your project
npm install trefle-api
# Clone the repository
git clone https://github.com/yourusername/trefle-api.git
cd trefle-api
# Install dependencies
npm install
Dependencies:
axios - HTTP client for API callscommander - CLI argument parsingdotenv - Environment variable managementwinston - Logging frameworkgetPlants(options)List plants with optional filtering, sorting, and pagination.
Parameters:
{
filter: Object, // Filter conditions (e.g., { edible: 'true', vegetable: 'true' })
filter_not: Object, // Exclusion filters (e.g., { toxicity: 'high' })
order: Object, // Sort order (e.g., { common_name: 'asc' })
range: Object, // Range filters (e.g., { maximum_height: '10,100' })
page: Number // Page number
}
Returns: Promise with 'data', 'links', and 'meta' keys
Example:
// Get edible vegetables, sorted alphabetically
const plants = await api.getPlants({
filter: { edible: 'true', vegetable: 'true' },
order: { common_name: 'asc' },
page: 1
});
// Get tall trees (10-100 meters height)
const trees = await api.getPlants({
filter: { ligneous_type: 'tree' },
range: { maximum_height: '1000,10000' }, // in cm
page: 1
});
Available Filters:
edible, vegetable, toxicity, edible_partflower_color, fruit_color, foliage_color, growth_habit, growth_rateaverage_height, maximum_height, spreadatmospheric_humidity, light, soil_humidity, ph_minimum, ph_maximumfamily_name, genus_name, common_name, scientific_namebloom_months, fruit_months, growth_months, durationgetPlant(plantId)Get specific plant by ID or slug.
Parameters:
plantId (Number|String): Plant ID or slugReturns: Promise - Complete plant object with main_species, genus, family, etc.
Example:
const plant = await api.getPlant(123456);
console.log(plant.data.common_name);
console.log(plant.data.scientific_name);
searchPlants(query, options)Search plants by query string. Searches across scientific name, common name, and synonyms.
Parameters:
query: String, // Required search query
options: {
page: Number,
filter: Object,
filter_not: Object,
order: Object,
range: Object
}
Returns: Promise - Search results with 'data', 'links', and 'meta' keys
Example:
// Simple search
const results = await api.searchPlants('coconut');
// Search with filters
const roses = await api.searchPlants('rose', {
filter: { edible: 'true' }
});
getPlantsByZone(zoneId, options)List plants in a specific distribution zone.
Parameters:
zoneId (String): TDWG zone code (e.g., 'usa', 'eur', 'afr')options (Object): Same as getPlants()Returns: Promise - Plants found in the specified zone
Example:
// Get plants native to USA
const usaPlants = await api.getPlantsByZone('usa', { page: 1 });
// Get edible plants in Europe
const eurEdibles = await api.getPlantsByZone('eur', {
filter: { edible: 'true' }
});
Common Zone Codes:
usa - United Stateseur - Europeafr - Africaasi - Asiasam - South Americanam - North Americaaus - AustraliagetPlantsByGenus(genusId, options)List plants for a specific genus.
Parameters:
genusId (Number): Genus IDoptions (Object): Same as getPlants()Returns: Promise - Plants in the specified genus
Example:
// Get all roses (Rosa genus)
const roses = await api.getPlantsByGenus(1234, { page: 1 });
reportPlant(plantId, notes)Report an error for a plant.
Parameters:
plantId (Number): Plant ID to report error fornotes (String): Description of the error or issueReturns: Promise - Correction object
Example:
const correction = await api.reportPlant(
123456,
"Common name is misspelled - should be 'Oak' not 'Oka'"
);
The following endpoints provide access to the plant taxonomy hierarchy.
getKingdoms(options) / getKingdom(id)List all kingdoms or get a specific kingdom.
// List all kingdoms
const kingdoms = await api.getKingdoms({ page: 1 });
// Get specific kingdom
const kingdom = await api.getKingdom('plantae');
getSubkingdoms(options) / getSubkingdom(id)List all subkingdoms or get a specific subkingdom.
const subkingdoms = await api.getSubkingdoms({ page: 1 });
const subkingdom = await api.getSubkingdom(123);
getDivisions(options) / getDivision(id)List all divisions or get a specific division.
const divisions = await api.getDivisions({ page: 1 });
const division = await api.getDivision('magnoliophyta');
getDivisionClasses(options) / getDivisionClass(id)List all division classes or get a specific division class.
const classes = await api.getDivisionClasses({ page: 1 });
const divClass = await api.getDivisionClass(123);
getDivisionOrders(options) / getDivisionOrder(id)List all division orders or get a specific division order.
const orders = await api.getDivisionOrders({ page: 1 });
const order = await api.getDivisionOrder('rosales');
getFamilies(options) / getFamily(id)List all families or get a specific family. Supports filtering and sorting.
// List families
const families = await api.getFamilies({
filter: { name: 'Rosa' },
page: 1
});
// Get specific family
const rosaceae = await api.getFamily('rosaceae');
getGenera(options) / getGenus(id)List all genera or get a specific genus. Supports filtering and sorting.
// List genera
const genera = await api.getGenera({ page: 1 });
// Get specific genus
const rosa = await api.getGenus('rosa');
getSpeciesList(options)List species with optional filtering, sorting, and pagination.
Parameters: Same as getPlants()
const species = await api.getSpeciesList({
filter: { edible: 'true' },
page: 1
});
getSpecies(speciesId)Get a specific species by ID or slug.
const species = await api.getSpecies(123456);
console.log(species.data.scientific_name);
searchSpecies(query, options)Search species by query string.
const results = await api.searchSpecies('oak', { page: 1 });
reportSpecies(speciesId, notes)Report an error for a species.
const correction = await api.reportSpecies(123456, 'Scientific name spelling error');
getDistributions(options)List all distribution zones with pagination.
const distributions = await api.getDistributions({ page: 1 });
getDistribution(distributionId)Get a specific distribution zone by ID or slug.
const zone = await api.getDistribution('usa');
console.log(zone.data.name);
getCorrections(options)List all corrections with pagination.
const corrections = await api.getCorrections({ page: 1 });
getCorrection(correctionId)Get a specific correction by ID.
const correction = await api.getCorrection(123);
getCorrectionsForSpecies(recordId)Get corrections for a specific species record.
const corrections = await api.getCorrectionsForSpecies(123456);
getAllPages(methodName, options)Helper method to fetch all pages of results automatically.
Parameters:
methodName: String, // Name of API method ('getPlants', 'searchPlants', etc.)
options: {
maxPages: Number, // Maximum pages to fetch (null for all)
...otherParams // Parameters to pass to the method
}
Returns: Promise - Combined data from all pages
Example:
// Get all edible plants (all pages)
const allEdibles = await api.getAllPages('getPlants', {
filter: { edible: 'true' }
});
// Get first 5 pages only
const limited = await api.getAllPages('getPlants', {
maxPages: 5,
filter: { vegetable: 'true' }
});
The CLI provides command-line access to fetch and save plant data.
# Global install
trefle [endpoint] [options]
# Local install (use npx)
npx trefle [endpoint] [options]
# From source (development)
npm run trefle -- [endpoint] [options]
# Show help
trefle --help
# Fetch everything
trefle --all
# Fetch reference data only
trefle --all-single
# Fetch plants with pagination
trefle --plants --pages 10
Note: Examples below use trefle command (global install). For local install, use npx trefle instead. For development from source, use npm run trefle -- [flags].
# Single search
trefle --search "maple"
# Multiple searches
trefle --search "oak" --search "pine" --search "rose"
# Start from specific page
trefle --plants --start-page 5 --pages 10
# Fetch with enrichment (full details + flattened structure)
trefle --plants --pages 5 --enrichment
# Output as compressed JSON
trefle --plants --pages 10 --format json.gz
# Dry run (preview without fetching)
trefle --all --dry-run
# Debug logging
trefle --plants --log-level DEBUG
Category Flags:
| Flag | Description |
|---|---|
--all | Fetch all data (reference + all plant pages) |
--all-single | Fetch all reference data (zones, genus list) |
--all-plants | Fetch all plant pages |
Plant Endpoint Flags:
| Flag | Description |
|---|---|
--plants | Fetch plants (use --pages to limit) |
--plants-combined | Shortcut for --plants --enrichment |
--search <queries...> | Search plants by query (can specify multiple) |
--plant-id <ids...> | Fetch specific plants by ID (can specify multiple) |
Taxonomy Endpoint Flags:
| Flag | Description |
|---|---|
--kingdoms | Fetch all kingdoms |
--kingdom <id> | Fetch specific kingdom by ID or slug |
--subkingdoms | Fetch all subkingdoms |
--subkingdom <id> | Fetch specific subkingdom by ID or slug |
--divisions | Fetch all divisions |
--division <id> | Fetch specific division by ID or slug |
--division-classes | Fetch all division classes |
--division-class <id> | Fetch specific division class by ID or slug |
--division-orders | Fetch all division orders |
--division-order <id> | Fetch specific division order by ID or slug |
--families | Fetch all families |
--family <id> | Fetch specific family by ID or slug |
--genera | Fetch all genera |
--genus <id> | Fetch specific genus by ID or slug |
Species Endpoint Flags:
| Flag | Description |
|---|---|
--species | Fetch species list |
--species-id <id> | Fetch specific species by ID or slug |
--search-species <queries...> | Search species by query (can specify multiple) |
Distribution & Correction Flags:
| Flag | Description |
|---|---|
--zones | Fetch all distribution zones |
--zone <id> | Fetch specific distribution zone by ID or slug |
--corrections | Fetch all corrections |
--correction <id> | Fetch specific correction by ID |
Pagination Options:
| Flag | Description |
|---|---|
--pages <N> | Number of pages to fetch |
--start-page <N> | Starting page number (default: 1) |
Other Options:
| Flag | Description |
|---|---|
--enrichment | Enrich data by fetching full details for each plant |
--format <format> | Output format: json (default), json.gz, csv |
--dry-run | Preview operations without fetching |
--log-level <level> | Set logging level (DEBUG, INFO, WARNING, ERROR) |
The CLI organizes fetched data into structured directories:
datasets/
└── trefle/
├── single/ # One-time reference data
│ ├── zones.json # Distribution zones
│ └── genus_list.json # Genus reference list
├── taxonomy/ # Taxonomy data
│ ├── kingdoms.json
│ ├── divisions.json
│ ├── families.json
│ └── genera.json
├── species/ # Species data
│ ├── species_list.json
│ └── search/
├── distributions/ # Distribution zone data
├── corrections/ # Correction data
├── plants_pages_1-10.json # Paginated plant lists (batched)
├── plants_pages_11-20.json # 10 pages per file (basic mode)
├── plants_pages_1-5_enriched.json # 5 pages per file (enriched mode)
├── plants_by_id/ # Individual plant details
│ ├── plant_123456.json
│ └── plant_789012.json
└── search/ # Search results
├── rose_results.json
├── oak_results.json
└── maple_results_enriched.json
The Trefle API has a rate limit of 120 requests per minute.
The CLI automatically implements rate limiting:
When using the API class directly, implement your own rate limiting:
import { pause, randomNumber } from './utils.js';
const api = new TrefleAPI();
for (let page = 1; page <= 100; page++) {
const plants = await api.getPlants({ page });
// Process plants...
// Rate limiting pause
await pause(randomNumber(2, 5));
}
import { TrefleAPI } from './api.js';
const api = new TrefleAPI();
// Get edible plants in USA
const usaEdibles = await api.getPlantsByZone('usa', {
filter: { edible: 'true' },
page: 1
});
for (const plant of usaEdibles.data) {
console.log(`${plant.common_name} - ${plant.scientific_name}`);
}
import { TrefleAPI } from './api.js';
import { writeToFile, pause, randomNumber } from './utils.js';
const api = new TrefleAPI();
const fruitTrees = await api.getAllPages('getPlants', {
filter: {
ligneous_type: 'tree',
fruit_conspicuous: 'true'
}
});
// Save to file
await writeToFile(fruitTrees, 'datasets/fruit_trees.json');
const api = new TrefleAPI();
// Search for roses that are fragrant and edible
const fragrantRoses = await api.searchPlants('rose', {
filter: {
edible: 'true',
flower_conspicuous: 'true'
}
});
console.log(`Found ${fragrantRoses.data.length} fragrant edible roses`);
const api = new TrefleAPI();
// Get all plant families
const families = await api.getFamilies({ page: 1 });
console.log(`Found ${families.meta.total} families`);
// Get details for a specific family
const rosaceae = await api.getFamily('rosaceae');
console.log(`Rosaceae has ${rosaceae.data.species_count} species`);
// Get all genera in the Rosa family
const genera = await api.getGenera({
filter: { family_id: rosaceae.data.id },
page: 1
});
# Fetch plants with full enrichment
trefle --plants --pages 10 --enrichment --format json.gz
# Search for medicinal herbs with enrichment
trefle \
--search "chamomile" \
--search "lavender" \
--search "mint" \
--enrichment
# Fetch taxonomy data
trefle --kingdoms --divisions --families
# Fetch zone data
trefle --zones
This Node.js implementation maintains feature parity with the Python version while adapting to JavaScript/Node.js idioms:
import/export vs import/from)getPlants) vs Python's snake_case (get_plants)fs/promises for async file operationszlib module for compression (vs Python's gzip)randomNumber() uses Math.random() vs Python's random.randint()pause() returns Promise with setTimeout vs time.sleep()All API methods return JSON responses in this format:
{
"data": [
{
"id": 123456,
"common_name": "Oak",
"scientific_name": "Quercus robur",
"genus": "Quercus",
"family": "Fagaceae",
...
}
],
"links": {
"self": "/api/v1/plants?page=1",
"first": "/api/v1/plants?page=1",
"next": "/api/v1/plants?page=2",
"prev": null,
"last": "/api/v1/plants?page=50"
},
"meta": {
"total": 500
}
}
The service includes comprehensive error handling:
try {
const plants = await api.getPlants({ page: 1 });
} catch (error) {
if (error.response) {
console.error(`HTTP Error: ${error.response.status}`);
} else {
console.error(`Error: ${error.message}`);
}
}
All errors are logged automatically with context information.
Error: TREFLE_API_TOKEN not found in environment variables
Solution: Add your token to the .env file:
TREFLE_API_TOKEN=your_actual_token_here
HTTP Error: 429 Too Many Requests
Solution: The API automatically rate limits, but if you see this:
HTTP Error: 401 Unauthorized
Solution:
Error: Cannot find module 'axios'
Solution: Install dependencies:
cd trefle-api
npm install
Note: These npm scripts are only available when working from the source repository.
npm run trefle # Run CLI
npm run trefle:help # Show help
npm run trefle:all # Fetch all data
npm run trefle:plants # Fetch first 10 pages of plants
npm run trefle:dry-run # Dry run preview
npm test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Generate coverage report
Pass additional flags with --:
npm run trefle -- --search "oak" --enrichment
Disclaimer: This project is an independent community wrapper and is not affiliated with trefle.io.
This package includes built-in rate limiting (2-5 second delays between requests), but users are ultimately responsible for how they use this tool. Please:
Abuse of this package (e.g., excessive requests, circumventing access controls) may result in your API token being revoked or your account being suspended. The maintainers of this package are not responsible for any consequences arising from misuse.
MIT
FAQs
Node.js client library and CLI for the Trefle Plants REST API
The npm package trefle-api receives a total of 2 weekly downloads. As such, trefle-api popularity was classified as not popular.
We found that trefle-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.