| Crates.io | jobsuche |
| lib.rs | jobsuche |
| version | 0.3.0 |
| created_at | 2025-10-21 05:45:25.318086+00 |
| updated_at | 2025-10-23 05:42:13.62952+00 |
| description | Rust interface for the Bundesagentur für Arbeit Jobsuche API |
| homepage | https://github.com/wunderfrucht/jobsuche |
| repository | https://github.com/wunderfrucht/jobsuche |
| max_upload_size | |
| id | 1893308 |
| size | 256,056 |
A Rust interface for the Bundesagentur für Arbeit Jobsuche API
Access Germany's largest job database programmatically. Search for jobs, get detailed information, and access employer data through a type-safe, ergonomic Rust API.
Add this to your Cargo.toml:
[dependencies]
jobsuche = "0.1"
# Optional: Enable async support
jobsuche = { version = "0.1", features = ["async"] }
use jobsuche::{Jobsuche, Credentials, SearchOptions, Arbeitszeit};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a client (uses the public API key by default)
let client = Jobsuche::new(
"https://rest.arbeitsagentur.de/jobboerse/jobsuche-service",
Credentials::default()
)?;
// Search for jobs
let results = client.search().list(SearchOptions::builder()
.was("Softwareentwickler") // What: job title
.wo("Berlin") // Where: location
.umkreis(50) // Radius: 50km
.arbeitszeit(vec![Arbeitszeit::Vollzeit]) // Full-time only
.veroeffentlichtseit(30) // Posted in last 30 days
.size(25) // 25 results per page
.build()
)?;
println!("Found {} jobs", results.stellenangebote.len());
// Get details for the first job
if let Some(job) = results.stellenangebote.first() {
println!("Job: {} at {}", job.beruf, job.arbeitgeber);
println!("Location: {}", job.arbeitsort.ort);
// Fetch full details
let details = client.job_details(&job.refnr)?;
println!("Description: {:?}", details.stellenbeschreibung);
}
Ok(())
}
use jobsuche::{SearchOptions, Arbeitszeit, Befristung, Angebotsart};
let options = SearchOptions::builder()
.was("Data Scientist")
.wo("München")
.umkreis(100) // 100km radius
.angebotsart(Angebotsart::Arbeit) // Regular employment
.befristung(vec![Befristung::Unbefristet]) // Permanent only
.arbeitszeit(vec![
Arbeitszeit::Vollzeit,
Arbeitszeit::Teilzeit,
])
.veroeffentlichtseit(14) // Last 2 weeks
.zeitarbeit(false) // Exclude temp agencies
.build();
let results = client.search().list(options)?;
// Manual pagination
for page in 1..=5 {
let results = client.search().list(SearchOptions::builder()
.was("Rust Developer")
.page(page)
.size(50)
.build()
)?;
for job in results.stellenangebote {
println!("{}: {}", job.refnr, job.beruf);
}
}
// Automatic pagination - get all results
let all_jobs = client.search().iter(SearchOptions::builder()
.was("DevOps Engineer")
.wo("Hamburg")
.veroeffentlichtseit(7) // Limit to last week to avoid too many results
.build()
)?;
println!("Found {} total jobs", all_jobs.len());
let job_listing = /* ... from search results ... */;
// Get comprehensive job information
let details = client.job_details(&job_listing.refnr)?;
println!("Title: {}", details.titel);
println!("Employer: {}", details.arbeitgeber);
println!("Locations: {:?}", details.arbeitsorte);
println!("Work time models: {:?}", details.arbeitszeitmodelle);
println!("Salary: {:?}", details.verguetung);
println!("Skills: {:?}", details.fertigkeiten);
use std::fs::File;
use std::io::Write;
let job = /* ... from search results ... */;
// Try to get employer logo (many employers don't have one)
if let Some(hash) = &job.kundennummer_hash {
match client.employer_logo(hash) {
Ok(logo_bytes) => {
let mut file = File::create("logo.png")?;
file.write_all(&logo_bytes)?;
println!("Logo saved!");
}
Err(_) => println!("No logo available"),
}
}
use jobsuche::Angebotsart;
Angebotsart::Arbeit // Regular employment
Angebotsart::Selbstaendigkeit // Self-employment
Angebotsart::Ausbildung // Apprenticeship/Dual study
Angebotsart::PraktikumTrainee // Internship/Trainee
use jobsuche::Befristung;
Befristung::Befristet // Fixed-term contract
Befristung::Unbefristet // Permanent contract
use jobsuche::Arbeitszeit;
Arbeitszeit::Vollzeit // Full-time
Arbeitszeit::Teilzeit // Part-time
Arbeitszeit::SchichtNachtarbeitWochenende // Shift/Night/Weekend
Arbeitszeit::HeimTelearbeit // Home office/Remote
Arbeitszeit::Minijob // Mini job
Based on GitHub issues:
404 Errors (Issue #61): Job details may return 404 even if the job appears in search results. Jobs expire quickly.
403 Errors (Issue #60): Sporadic rate limiting may occur. The client will return Error::Forbidden in these cases.
Employer Search (Issue #52): Case-sensitive and exact-match only:
"Deutsche Bahn AG""deutsche bahn" or "bahn"Employer Logos (Issue #62): Many employers don't have logos. Expect frequent 404s.
No Sorting (Issue #43): Results are always sorted oldest-to-newest. No way to change this.
RefNr Encoding: Reference numbers must be base64-encoded for the job details endpoint. This client handles this automatically.
This crate follows the architecture patterns from gouqi, featuring:
thiserrorContributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE for details