A comprehensive Node.js wrapper for the Vereinsflieger REST API with full TypeScript-style JSDoc documentation, modern ES6+ features, and complete CRUD operations.
Vereinsflieger is a popular system in Germany to help aviation clubs with their administration. The administration ranges from the legally required documentation duties, invoicing and accounting topics, managing flight training, to the annual statistics.
Although the system itself already maps all relevant topics in the web application, a reading and writing REST-based API is offered for many tables in the database. This API can be used to solve rare, individual needs.
Because there is a worldwide tendency to develop web applications based on Node.js, this wrapper API was created for Node.js. The code is made available here to the public.
✅ 48+ API Methods covering all major endpoints
✅ Complete JSDoc Documentation with IntelliSense support
✅ Input Validation for all critical parameters
✅ Modern Error Handling with descriptive error messages
✅ Native Fetch API (Node.js 18+, no external dependencies for HTTP)
✅ Environment Variables support via dotenv
✅ Zero Security Vulnerabilities
npm installCopy the template and add your credentials:
cp muster.env .envEdit .env file:
VEREINSFLIEGER_APPKEY=your_appkey_from_vereinsflieger
VEREINSFLIEGER_USERNAME=your.email@example.com
VEREINSFLIEGER_PASSWORD=your_passwordImportant: The .env file is already in .gitignore and will not be committed to git.
The API key (appkey) must be requested from Vereinsflieger support. Note the usage restrictions:
Der für die Anmeldung erforderliche appkey kann über den Support
angefragt werden. Die max. Anzahl an Requests (gemeint sind alle
Aufrufe) ist auf 1000 je Tag limitiert. Die kommerzielle Nutzung der
Schnittstelle ist grundsätzlich untersagt.
require('dotenv').config();
const { VereinsfliegerAPI } = require('./vereinsflieger_nodejs_api');
const vf = new VereinsfliegerAPI(process.env.VEREINSFLIEGER_APPKEY);
async function example() {
try {
// Sign in
await vf.signIn(process.env.VEREINSFLIEGER_USERNAME, process.env.VEREINSFLIEGER_PASSWORD);
// Get user info
const user = await vf.getUser();
console.log(`Logged in as: ${user.firstname} ${user.lastname}`);
// Get today's flights
const flights = await vf.getFlightListToday();
console.log('Today\'s flights:', flights);
// Sign out
await vf.signOut();
} catch (error) {
console.error('Error:', error.message);
}
}
example();signIn(username, password)- Sign in usersignOut()- Sign out current usergetUser()- Get current user infosetAccessToken()- Get access token (called automatically)
addFlight(callsign, options)- Add new flighteditFlight(flightId, options)- Edit existing flightdeleteFlight(flightId)- Delete flightgetFlight(flightId)- Get flight detailsgetFlightListToday()- Today's flightsgetFlightListDate(date)- Flights for specific dategetFlightListDaterange(from, to)- Flights in date rangegetLastFlightsPlane(callsign, count)- Last N flights of aircraftgetLastFlightsUser(count)- Last N flights of current usergetLastFlightsPilot(uid, count)- Last N flights of pilotgetLastModifiedFlights(days)- Recently modified flightsgetFlightStatistics(from, to)- Flight statistics
getAircraftList()- List all aircraftgetAircraft(callsign)- Get aircraft detailsgetMaintenanceData(callsign)- Get maintenance data
getPersonList()- List all users/membersgetUserDetails(uid)- Get detailed user info
addReservation(callsign, from, to, options)- Add reservationeditReservation(reservationId, options)- Edit reservationdeleteReservation(reservationId)- Delete reservationgetReservation(reservationId)- Get reservation detailsgetReservationList()- List active reservations
getCalendarPublic(hpaccessCode)- Get public calendar (no auth)getCalendarUser()- Get user's calendar
accountAddTransaction(date, value, tax, debit, credit, ...)- Add transactioneditAccountTransaction(transactionId, options)- Edit transactiondeleteAccountTransaction(transactionId)- Delete transactiongetAccountTransaction(transactionId)- Get transaction detailsgetAccountTransactionsToday()- Today's transactionsgetAccountListYear(year)- Transactions for yeargetAccountTransactionsDaterange(from, to)- Transactions in range
workhoursAdd(uid, date, text, hours, category, options)- Add work hourseditWorkhour(workhourId, options)- Edit work hoursdeleteWorkhour(workhourId)- Delete work hoursgetWorkhour(workhourId)- Get work hour detailsgetWorkhoursDaterange(from, to)- Work hours in rangegetWorkhoursCategories()- Get available categories
getArticles()- List all articlesaddSale(date, articleId, options)- Add sale transaction
require('dotenv').config();
const express = require('express');
const router = express.Router();
const { VereinsfliegerAPI } = require('../../vereinsflieger_api/vereinsflieger_nodejs_api');
const vf = new VereinsfliegerAPI(process.env.VEREINSFLIEGER_APPKEY);
async function vereinsfliegerLogin(req, res, next) {
try {
await vf.signIn(req.body.username, req.body.password);
return next();
} catch (error) {
return res.status(401).json({ error: error.message });
}
}
async function setUserdata(req, res, next) {
try {
req.session.userdata = await vf.getUser();
return next();
} catch (error) {
return res.status(500).json({ error: error.message });
}
}
function render(req, res) {
res.render('resulting_displayfile', {
title: 'Vereinsflieger-Benutzerdaten darstellen',
userdata: req.session.userdata
});
}
router.post('/login', vereinsfliegerLogin, setUserdata, render);
module.exports = router;Data returned from the API are often nested JavaScript objects. Here's how to convert them to arrays:
require('dotenv').config();
const express = require('express');
const { VereinsfliegerAPI } = require('../../vereinsflieger_api/vereinsflieger_nodejs_api');
const router = express.Router();
const vf = new VereinsfliegerAPI(process.env.VEREINSFLIEGER_APPKEY);
async function fillCashTransactions(req, res, next) {
try {
const transactions_json = await vf.getAccountListYear(new Date().getFullYear());
// Convert nested object to array
const transaction_array = Object.values(transactions_json);
// Filter transactions
const filteredTransactions = transaction_array.filter(el => el.creditaccount == 100000);
req.filteredTransactions = filteredTransactions;
return next();
} catch (error) {
return res.status(500).json({ error: error.message });
}
}
router.get('/transactions', fillCashTransactions, (req, res) => {
res.json(req.filteredTransactions);
});
module.exports = router;All methods throw descriptive errors that can be caught:
try {
await vf.addFlight('D-ECQH', {
pilotName: 'John Doe',
departureTime: '2024-01-01 10:00',
arrivalTime: '2024-01-01 12:00'
});
} catch (error) {
if (error.message.includes('Not signed in')) {
console.error('Please sign in first');
} else if (error.message.includes('Callsign is required')) {
console.error('Missing required parameter');
} else {
console.error('API Error:', error);
}
}All methods have complete JSDoc documentation. Your IDE will show:
- Parameter types and descriptions
- Return types
- Required vs optional parameters
- Error conditions
Simply start typing vf. and see all available methods with descriptions!
- Node.js 18+ (for native fetch API support)
- Valid Vereinsflieger API key
dotenv- Environment variable managementcrypto- MD5 hashing for passwords (built-in)- Native
fetchAPI (Node.js 18+)
You can use the code, but I do not guarantee the results and take no responsibility for the code. You have to get an individual App-Key from vereinsflieger.de. In this context you have to comply with the terms of use of vereinsflieger.de.
MIT License - See file header for details
Contributions are welcome! Please ensure:
- All new methods have JSDoc documentation
- Input validation for required parameters
- Proper error handling
- Test your changes
- ✅ Added 23 new API endpoints (48+ total methods)
- ✅ Complete JSDoc documentation
- ✅ Modern error handling with descriptive messages
- ✅ Input validation for all methods
- ✅ Migrated to native fetch API (no node-fetch dependency)
- ✅ Environment variable support with dotenv
- ✅ Fixed all security vulnerabilities
- ✅ Improved code quality and consistency
- Initial release with basic API coverage